diff --git a/.install/windows/install.nsi b/.install/windows/install.nsi index a41d4946ce..528d21689a 100644 --- a/.install/windows/install.nsi +++ b/.install/windows/install.nsi @@ -27,15 +27,6 @@ InstallDir $PROFILE\faceswap !define flagsRepo "--depth 1 --no-single-branch ${wwwRepo}" !define flagsEnv "-y python=3.6" -# Dlib Wheel prefix -!define prefixDlib "dlib-19.16.99-cp36-cp36m-win_amd64" -!define dlibFinalName "dlib-19.16.99-cp36-cp36m-win_amd64.whl" # Dlib Wheel MUST have this name before installing -!define cudaDlib "_cuda90" -!define avxDlib "_avx" -!define sseDlib "_sse4" -!define noneDlib "_none" - - # Folders Var ProgramData Var dirTemp @@ -48,7 +39,6 @@ Var dirConda # Items to Install Var InstallGit Var InstallConda -Var dlibWhl # Misc Var gitInf @@ -78,6 +68,7 @@ Var envName Page custom pgPrereqCreate pgPrereqLeave # Install Faceswap Page +!define MUI_PAGE_CUSTOMFUNCTION_SHOW InstFilesShow !define MUI_PAGE_HEADER_SUBTEXT "Installing Faceswap..." !insertmacro MUI_PAGE_INSTFILES @@ -99,11 +90,16 @@ Function .onInit StrCpy $gitInf "$dirTemp\git_install.inf" StrCpy $envName "faceswap" SetOutPath "$dirTemp" - File *.whl File git_install.inf Call CheckPrerequisites FunctionEnd +# Enable the cancel button during installation +Function InstFilesShow + GetDlgItem $0 $HWNDPARENT 2 + EnableWindow $0 1 +FunctionEnd + Function VerifyInstallDir # Check install folder does not already exist IfFileExists $INSTDIR 0 +3 @@ -278,7 +274,6 @@ Section Install Call InstallPrerequisites Call CloneRepo Call SetEnvironment - Call InstallDlib Call SetupFaceSwap Call DesktopShortcut SectionEnd @@ -292,7 +287,10 @@ Function InstallPrerequisites ${If} $0 == "OK" DetailPrint "Installing Git..." SetDetailsPrint listonly - ExecWait "$\"$dirTemp\git_installer.exe$\" ${flagsGit} /LOADINF=$\"$gitInf$\"" $0 + ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$\"$dirTemp\git_installer.exe$\" ${flagsGit} /LOADINF=$\"$gitInf$\"" + pop $0 + ExecDos::wait $0 + pop $0 SetDetailsPrint both ${If} $0 != 0 DetailPrint "Error Installing Git" @@ -312,7 +310,10 @@ Function InstallPrerequisites ${If} $0 == "OK" DetailPrint "Installing Miniconda3. This will take a few minutes..." SetDetailsPrint listonly - ExecWait "$\"$dirTemp\Miniconda3.exe$\" ${flagsConda}" $0 + ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$\"$dirTemp\Miniconda3.exe$\" ${flagsConda}" + pop $0 + ExecDos::wait $0 + pop $0 StrCpy $dirConda "$dirMiniconda" SetDetailsPrint both ${If} $0 != 0 @@ -340,7 +341,10 @@ Function CloneRepo ${Else} StrCpy $9 "git" ${EndIf} - ExecWait "$9 clone ${flagsRepo} $\"$INSTDIR$\"" $0 + ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$9 clone ${flagsRepo} $\"$INSTDIR$\"" + pop $0 + ExecDos::wait $0 + pop $0 SetDetailsPrint both ${If} $0 != 0 DetailPrint "Error Downloading Faceswap" @@ -352,14 +356,20 @@ Function SetEnvironment # Updating Conda breaks setup.py. Commented out in case this issue gets resolved in future # DetailPrint "Initializing Conda..." # SetDetailsPrint listonly -# ExecWait "$dirConda\scripts\activate.bat && conda update -y -n base -c defaults conda && conda deactivate" $0 +# ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$dirConda\scripts\activate.bat && conda update -y -n base -c defaults conda && conda deactivate" +# pop $0 +# ExecDos::wait $0 +# pop $0 # SetDetailsPrint both DetailPrint "Creating Conda Virtual Environment..." IfFileExists "$dirConda\envs\$envName" DeleteEnv CreateEnv DeleteEnv: SetDetailsPrint listonly - ExecWait "$\"$dirConda\scripts\activate.bat$\" && conda env remove -y -n $\"$envName$\" && conda deactivate" $0 + ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$\"$dirConda\scripts\activate.bat$\" && conda env remove -y -n $\"$envName$\" && conda deactivate" + pop $0 + ExecDos::wait $0 + pop $0 SetDetailsPrint both ${If} $0 != 0 DetailPrint "Error deleting Conda Virtual Environment" @@ -368,7 +378,10 @@ Function SetEnvironment CreateEnv: SetDetailsPrint listonly - ExecWait "$\"$dirConda\scripts\activate.bat$\" && conda create ${flagsEnv} -n $\"$envName$\" && conda deactivate" $0 + ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$\"$dirConda\scripts\activate.bat$\" && conda create ${flagsEnv} -n $\"$envName$\" && conda deactivate" + pop $0 + ExecDos::wait $0 + pop $0 SetDetailsPrint both ${If} $0 != 0 DetailPrint "Error Creating Conda Virtual Environment" @@ -376,46 +389,18 @@ Function SetEnvironment ${EndIf} FunctionEnd -Function InstallDlib - DetailPrint "Installing Dlib..." - SetDetailsPrint listonly - - StrCpy $dlibWhl ${prefixDlib} - - ${If} $noNvidia != 1 - StrCpy $dlibWhl "$dlibWhl${cudaDlib}" - ${EndIf} - - ${If} $hasAVX == 1 - StrCpy $dlibWhl "$dlibWhl${avxDlib}" - ${ElseIf} $hasSSE4 == 1 - StrCpy $dlibWhl "$dlibWhl${sseDlib}" - ${Else} - StrCpy $dlibWhl "$dlibWhl${noneDlib}" - ${EndIf} - - StrCpy $dlibWhl "$dlibWhl.whl" - DetailPrint "Renaming $dlibWhl to ${dlibFinalName}" - Rename "$dirTemp\$dlibWhl" "$dirTemp\${dlibFinalName}" - - ExecWait "$\"$dirConda\scripts\activate.bat$\" && conda activate $\"$envName$\" && pip install $\"$dirTemp\${dlibFinalName}$\" && conda deactivate" $0 - SetDetailsPrint both - ${If} $0 != 0 - DetailPrint "Error Installing Dlib" - Call Abort - ${EndIf} - -FunctionEnd - Function SetupFaceSwap - DetailPrint "Setting up FaceSwap Environment" + DetailPrint "Setting up FaceSwap Environment... This may take a while" StrCpy $0 "${flagsSetup}" ${If} $noNvidia != 1 StrCpy $0 "$0 --gpu" ${EndIf} SetDetailsPrint listonly - ExecWait "$\"$dirConda\scripts\activate.bat$\" && conda activate $\"$envName$\" && python $\"$INSTDIR\setup.py$\" $0 && conda deactivate" $0 + ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$\"$dirConda\scripts\activate.bat$\" && conda activate $\"$envName$\" && python $\"$INSTDIR\setup.py$\" $0 && conda deactivate" + pop $0 + ExecDos::wait $0 + pop $0 SetDetailsPrint both ${If} $0 != 0 DetailPrint "Error Setting up Faceswap" diff --git a/Dockerfile.cpu b/Dockerfile.cpu index 10364453aa..2bc5fc4168 100755 --- a/Dockerfile.cpu +++ b/Dockerfile.cpu @@ -7,8 +7,6 @@ RUN apt-get update -qq -y \ COPY requirements.txt /opt/ RUN pip3 install --upgrade pip -RUN pip3 install cmake -RUN pip3 install dlib RUN pip3 --no-cache-dir install -r /opt/requirements.txt && rm /opt/requirements.txt WORKDIR "/srv" diff --git a/Dockerfile.gpu b/Dockerfile.gpu index 48f24c67a0..4a7f94a222 100755 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -7,8 +7,6 @@ RUN apt-get update -qq -y \ COPY requirements.txt /opt/ RUN pip3 install --upgrade pip -RUN pip3 install cmake -RUN pip3 install dlib RUN pip3 --no-cache-dir install -r /opt/requirements.txt && rm /opt/requirements.txt RUN pip3 install jupyter matplotlib RUN pip3 install jupyter_http_over_ws diff --git a/INSTALL.md b/INSTALL.md index 20adae27ba..7b9500628f 100755 --- a/INSTALL.md +++ b/INSTALL.md @@ -4,24 +4,13 @@ - [Hardware Requirements](#hardware-requirements) - [Supported operating systems](#supported-operating-systems) - [Important before you proceed](#important-before-you-proceed) -- [General Install Guide](#general-install-guide) - - [Installing dependencies](#installing-dependencies) - - [Getting the faceswap code](#getting-the-faceswap-code) - - [Setup](#setup) - - [About some of the options](#about-some-of-the-options) - - [Run the project](#run-the-project) - - [Notes](#notes) - [Windows Install Guide](#windows-install-guide) - [Installer](#installer) - - [Manual Install](#Manual-install) + - [Manual Install](#manual-install) - [Prerequisites](#prerequisites-1) - - [Microsoft Visual Studio 2015](#microsoft-visual-studio-2015) - - [Cuda](#cuda) - - [cuDNN](#cudnn) - - [CMake](#cmake) - [Anaconda](#anaconda) - [Git](#git) - - [Setup](#setup-1) + - [Setup](#setup) - [Anaconda](#anaconda-1) - [Set up a virtual environment](#set-up-a-virtual-environment) - [Entering your virtual environment](#entering-your-virtual-environment) @@ -31,9 +20,13 @@ - [Running Faceswap](#running-faceswap) - [Create a desktop shortcut](#create-a-desktop-shortcut) - [Updating faceswap](#updating-faceswap) - - [Dlib](#dlib) - - [Build Latest Dlib with GPU Support](#build-latest-dlib-with-gpu-support) - - [Easy install of Dlib without GPU Support](#easy-install-of-dlib-without-gpu-support) +- [General Install Guide](#general-install-guide) + - [Installing dependencies](#installing-dependencies) + - [Getting the faceswap code](#getting-the-faceswap-code) + - [Setup](#setup-1) + - [About some of the options](#about-some-of-the-options) + - [Run the project](#run-the-project) + - [Notes](#notes) # Prerequisites Machine learning essentially involves a ton of trial and error. You're letting a program try millions of different settings to land on an algorithm that sort of does what you want it to do. This process is really really slow unless you have the hardware required to speed this up. @@ -69,6 +62,84 @@ Alternatively, there is a docker image that is based on Debian. The developers are also not responsible for any damage you might cause to your own computer. +# Windows Install Guide + +## Installer +Windows now has an installer which installs everything for you and creates a desktop shortcut to launch straight into the GUI. You can download the installer from https://github.com/deepfakes/faceswap/releases. + +If you have issues with the installer then read on for the more manual way to install Faceswap on Windows. + +## Manual Install + +Setting up Faceswap can seem a little intimidating to new users, but it isn't that complicated, although a little time consuming. It is recommended to use Linux where possible as Windows will hog about 20% of your GPU Memory, making Faceswap run a little slower, however using Windows is perfectly fine and 100% supported. + +## Prerequisites + +### Anaconda +Download and install the latest Python 3 Anaconda from: https://www.anaconda.com/download/. Unless you know what you are doing, you can leave all the options at default. + +### Git +Download and install Git for Windows: https://git-scm.com/download/win. Unless you know what you are doing, you can leave all the options at default. + +## Setup +Reboot your PC, so that everything you have just installed gets registered. + +### Anaconda +#### Set up a virtual environment +- Open up Anaconda Navigator +- Select "Environments" on the left hand side +- Select "Create" at the bottom +- In the pop up: + - Give it the name: faceswap + - **IMPORTANT**: Select python version 3.6 + - Hit "Create" (NB: This may take a while as it will need to download Python 3.6) +![Anaconda virtual env setup](https://i.imgur.com/Tl5tyVq.png) + +#### Entering your virtual environment +To enter the virtual environment: +- Open up Anaconda Navigator +- Select "Environments" on the left hand side +- Hit the ">" arrow next to your faceswap environment and select "Open Terminal" +![Anaconda enter virtual env](https://i.imgur.com/rKSq2Pd.png) + +### Faceswap +- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) +- Get the Faceswap repo by typing: `git clone --depth 1 https://github.com/deepfakes/faceswap.git` +- Enter the faceswap folder: `cd faceswap` + +#### Easy install +- Enter the command `python setup.py` and follow the prompts: +- If you have issues/errors follow the Manual install steps below. + +#### Manual install +- Install tkinter (required for the GUI) by typing: `conda install tk` +- Install requirements: `pip install -r requirements.txt` +- Install Tensorflow (either GPU or CPU version depending on your setup): + - GPU Version: `pip install tensorflow-gpu` + - Non GPU Version: `pip install tensorflow` + +## Running Faceswap +- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) +- Enter the faceswap folder: `cd faceswap` +- Enter the following to see the list of commands: `python faceswap.py -h` or enter `python faceswap.py gui` to launch the GUI + +## Create a desktop shortcut +A desktop shortcut can be added to easily launch straight into the faceswap GUI: + +- Open Notepad +- Paste the following: +``` +%USERPROFILE%\Anaconda3\envs\faceswap\python.exe %USERPROFILE%/faceswap/faceswap.py gui +``` +- Save the file to your desktop as "faceswap.bat" + +## Updating faceswap +It's good to keep faceswap up to date as new features are added and bugs are fixed. To do so: +- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) +- Enter the faceswap folder: `cd faceswap` +- Enter the following `git pull --all` +- Once the latest version has downloaded, make sure your requirements are up to date: `pip install --upgrade -r requirements.txt` + # General Install Guide ## Installing dependencies - Python >= 3.2-3.6 64-bit (cannot be 3.7.x as Tensorflow has not been updated to provide support) @@ -78,10 +149,6 @@ The developers are also not responsible for any damage you might cause to your o - [virtualenv](https://github.com/pypa/virtualenv) and [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io) may help when you are not using docker. - If you are using an Nvidia graphics card You should install CUDA (https://developer.nvidia.com/cuda-zone) and CUDNN (https://developer.nvidia.com/cudnn). If you do not plan to build Tensorflow yourself, make sure you install no higher than version 10.0 of CUDA and 7.4.x of CUDNN -- dlib is required for face recognition and is compiled as part of the setup process. You will need the following applications for your os to successfully install dlib (nb: list may be incomplete. Please raise an issue if another prerequisite is required for your OS): - - Windows: Visual Studio 2015, CMake v3.8.2 - - Linux: build-essential, cmake - - macOS: xquartz ## Getting the faceswap code Simply download the code from http://github.com/deepfakes/faceswap - For development, it is recommended to use git instead of downloading the code and extracting it. @@ -193,157 +260,4 @@ Proceed to [../blob/master/USAGE.md](USAGE.md) ## Notes This guide is far from complete. Functionality may change over time, and new dependencies are added and removed as time goes on. -If you are experiencing issues, please raise them in the [faceswap-playground](https://github.com/deepfakes/faceswap-playground) repository instead of the main repo. - -# Windows Install Guide - -## Installer -Windows now has an installer which installs everything for you and creates a desktop shortcut to launch straight into the GUI. You can download the installer from https://github.com/deepfakes/faceswap/releases. - -If you have issues with the installer then read on for the more manual way to install Faceswap on Windows. - -## Manual Install - -Setting up Faceswap can seem a little intimidating to new users, but it isn't that complicated, although a little time consuming. It is recommended to use Linux where possible as Windows will hog about 20% of your GPU Memory, making Faceswap run a little slower, however using Windows is perfectly fine and 100% supported. - -## Prerequisites -### Microsoft Visual Studio 2015 -**Important** Make sure to download the 2015 version of Microsoft Visual Studio - -Download and install Microsoft Visual Studio 2015 from: https://go.microsoft.com/fwlink/?LinkId=532606&clcid=0x409 - -On the install screen: -- Select "Custom" then click "Next"\ -![MSVS Custom](https://i.imgur.com/Bx8fjzT.png) -- Uncheck all previously checked options -- Expand "Programming Languages" and select "Visual C++"\ -![MSVS C++](https://i.imgur.com/c8k1IYD.png) -- Select "Next" and "Install" - - -### Cuda -**GPU Only** If you do not have an Nvidia GPU you can skip this step. - -At the time of writing Tensorflow (version 1.13.1) only supports Cuda up to version 10.0, but check https://www.tensorflow.org/install/gpu for the latest supported version. It is crucial that you download the correct version of Cuda. - -Download and install the correct version of the Cuda Toolkit from: https://developer.nvidia.com/cuda-toolkit-archive - -NB: Make a note of the install folder as you'll need to access it in the next step. - -### cuDNN -**GPU Only** If you do not have an Nvidia GPU you can skip this step. - -As with Cuda you will need to install the correct version of cuDNN that the latest Tensorflow supports. At the time of writing this is Tensorflow v1.13.1 which supports cuDNN version 7.4, but check https://www.tensorflow.org/install/gpu for the latest supported version. - -Download cuDNN from https://developer.nvidia.com/cudnn. You will need to create an account with Nvidia. - -At the bottom of the list of latest cuDNN release will be a link to "Archived cuDNN Releases": -![cuDNN Archive](https://i.imgur.com/dHiAsxg.png) - -Select this and choose the latest version of cuDNN that supports the version of Cuda you installed and has a minor version greater than or equal to the latest version that Tensorflow supports. (Eg Tensorflow 1.12 supports Cuda 9.0 and cuDNN 7.2. There is not an archived version of cuDNN 7.2 for Cuda 9.0, so select cuDNN version 7.3) -- Open the zip file -- Extract all of the files and folders into your Cuda folder (It is likely to be located in `C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA`):\ -![cuDNN to Cuda](https://i.imgur.com/X098w0N.png) - -### CMake -Install the latest stable release of CMake from https://cmake.org/download/. (Scroll down the page for Latest Releases and select the relevant Binary distribution installer for your OS). - -When installing CMake make sure to enable the option to CMake to the system path: -![cmake path](https://i.imgur.com/XTtacdY.png) - - -### Anaconda -Download and install the latest Python 3 Anaconda from: https://www.anaconda.com/download/. Unless you know what you are doing, you can leave all the options at default. - -### Git -Download and install Git for Windows: https://git-scm.com/download/win. Unless you know what you are doing, you can leave all the options at default. - -## Setup -Reboot your PC, so that everything you have just installed gets registered. - -### Anaconda -#### Set up a virtual environment -- Open up Anaconda Navigator -- Select "Environments" on the left hand side -- Select "Create" at the bottom -- In the pop up: - - Give it the name: faceswap - - **IMPORTANT**: Select python version 3.6 - - Hit "Create" (NB: This may take a while as it will need to download Python 3.6) -![Anaconda virtual env setup](https://i.imgur.com/Tl5tyVq.png) - -#### Entering your virtual environment -To enter the virtual environment: -- Open up Anaconda Navigator -- Select "Environments" on the left hand side -- Hit the ">" arrow next to your faceswap environment and select "Open Terminal" -![Anaconda enter virtual env](https://i.imgur.com/rKSq2Pd.png) - -### Faceswap -- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) -- Get the Faceswap repo by typing: `git clone https://github.com/deepfakes/faceswap.git` -- Enter the faceswap folder: `cd faceswap` - -#### Easy install -- Enter `python setup.py` and follow the prompts. - -If you have issues/errors follow the Manual install steps below. - -#### Manual install -If dlib failed to install you can follow the steps to [manually install dlib](#dlib).\ -Once dlib is installed follow these steps: - -- Install tkinter (required for the GUI) by typing: `conda install tk` -- Install requirements: `pip install -r requirements.txt` -- Install Tensorflow (either GPU or CPU version depending on your setup): - - GPU Version: `pip install tensorflow-gpu` - - Non GPU Version: `pip install tensorflow` - -## Running Faceswap -- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) -- Enter the faceswap folder: `cd faceswap` -- Enter the following to see the list of commands: `python faceswap.py -h` or enter `python faceswap.py gui` to launch the GUI - -## Create a desktop shortcut -A desktop shortcut can be added to easily launch straight into the faceswap GUI: - -- Open Notepad -- Paste the following: -``` -%USERPROFILE%\Anaconda3\envs\faceswap\python.exe %USERPROFILE%/faceswap/faceswap.py gui -``` -- Save the file to your desktop as "faceswap.bat" - -## Updating faceswap -It's good to keep faceswap up to date as new features are added and bugs are fixed. To do so: -- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) -- Enter the faceswap folder: `cd faceswap` -- Enter the following `git pull --all` -- Once the latest version has downloaded, make sure your requirements are up to date: `pip install --upgrade -r requirements.txt` - -## Dlib -You should only need to follow these steps if you want the latest Dlib code or the process was unable to install Dlib for you. - -For reasons outside of our control, this is the trickiest part of the process, and most of the prerequisites you installed are to support just Dlib. It is recommended to build Dlib from source for 3 main reasons: -1) To get the latest version -2) Enable GPU Support in Dlib -3) To prevent yourself from running into a whole host of issues later in the process. - -If you are not bothered about having GPU support or the latest version, scroll to the end of this section for a simple one-liner to install the CPU version of Dlib. -### Build Latest Dlib with GPU Support -- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) -- In the terminal type: `git clone https://github.com/davisking/dlib.git` -- Enter the dlib folder: `cd dlib` -- Add Visual Studio to your path by typing: `SET PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin` -- Enter: `python setup.py -G "Visual Studio 14 2015" install --yes USE_AVX_INSTRUCTIONS --yes DLIB_USE_CUDA --clean` - -This will build and install dlib for you. It is worth backing up the generated .egg file somewhere so that you can re-install it if you ever need to rather than having to re-compile: -- From within the dlib folder copy the file named `dlib-xx.yy.zz-py3.5-win-amd64.egg` to somewhere safe -- If you ever need to install it again, then from within your virtual environment enter: `python -m easy_install ` - -Once Dlib is built, you can remove Visual Studio and CMake from your PC. - -### Easy install of Dlib without GPU Support -NB: Don't do this if you have already compiled Dlib with GPU support. -- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment) -- In the terminal type: `conda install -c conda-forge dlib` +If you are experiencing issues, please raise them in the [faceswap-playground](https://github.com/deepfakes/faceswap-playground) repository instead of the main repo. \ No newline at end of file diff --git a/plugins/extract/detect/mtcnn.py b/plugins/extract/detect/mtcnn.py index 19e63791d9..f2cbf711d9 100755 --- a/plugins/extract/detect/mtcnn.py +++ b/plugins/extract/detect/mtcnn.py @@ -170,8 +170,6 @@ def process_output(self, faces, points, rotation_matrix, scale): def recalculate_bounding_box(faces, landmarks): """ Recalculate the bounding box for Face Alignment. - Face Alignment was built to expect a DLIB bounding - box and calculates center and scale based on that. Resize the bounding box around features to present a better box to Face Alignment. Helps its chances on edge cases and helps remove 'jitter' """ diff --git a/requirements.txt b/requirements.txt index eff489a886..909b72e50e 100755 --- a/requirements.txt +++ b/requirements.txt @@ -14,9 +14,6 @@ ffmpy==0.2.2 nvidia-ml-py3 h5py==2.9.0 Keras==2.2.4 -cmake -dlib -face-recognition # tensorflow is included within the docker image. # If you are looking for dependencies for a manual install, diff --git a/scripts/fsmedia.py b/scripts/fsmedia.py index 6c420882f5..013b141f0c 100644 --- a/scripts/fsmedia.py +++ b/scripts/fsmedia.py @@ -236,8 +236,9 @@ def set_actions(self): args = args if isinstance(args, tuple) else tuple() kwargs = kwargs if isinstance(kwargs, dict) else dict() task = globals()[action](*args, **kwargs) - logger.debug("Adding Postprocess action: '%s'", task) - actions.append(task) + if task.valid: + logger.debug("Adding Postprocess action: '%s'", task) + actions.append(task) for action in actions: action_name = camel_case_split(action.__class__.__name__) @@ -293,6 +294,7 @@ class PostProcessAction(): # pylint: disable=too-few-public-methods def __init__(self, *args, **kwargs): logger.debug("Initializing %s: (args: %s, kwargs: %s)", self.__class__.__name__, args, kwargs) + self.valid = True # Set to False if invalid params passed in to disable logger.debug("Initialized base class %s", self.__class__.__name__) def process(self, output_item): @@ -391,6 +393,7 @@ def load_face_filter(self, filter_lists, ref_threshold, aligner, detector, logle if not any(val for val in filter_lists.values()): return None + facefilter = None filter_files = [self.set_face_filter(f_type, filter_lists[f_type]) for f_type in ("filter", "nfilter")] @@ -403,6 +406,8 @@ def load_face_filter(self, filter_lists, ref_threshold, aligner, detector, logle multiprocess, ref_threshold) logger.debug("Face filter: %s", facefilter) + else: + self.valid = False return facefilter @staticmethod @@ -414,6 +419,9 @@ def set_face_filter(f_type, f_args): logger.info("%s: %s", f_type.title(), f_args) filter_files = f_args if isinstance(f_args, list) else [f_args] filter_files = list(filter(lambda fpath: Path(fpath).exists(), filter_files)) + if not filter_files: + logger.warning("Face %s files were requested, but no files could be found. This " + "filter will not be applied.", f_type) logger.debug("Face Filter files: %s", filter_files) return filter_files diff --git a/setup.py b/setup.py index 592f56c228..dc33da2056 100755 --- a/setup.py +++ b/setup.py @@ -155,7 +155,7 @@ def output_runtime_info(self): def check_pip(self): """ Check installed pip version """ try: - import pip + import pip # noqa pylint:disable=unused-import except ImportError: self.output.error("Import pip failed. Please Install python3-pip and try again") exit(1) @@ -295,7 +295,7 @@ def warning(self, text): def error(self, text): """ Format ERROR Text """ - global INSTALL_FAILED + global INSTALL_FAILED # pylint:disable=global-statement trm = "ERROR " if self.term_support_color: trm = "{}ERROR {} ".format(self.red, self.default_color) @@ -336,7 +336,6 @@ def __init__(self, environment): self.env.cuda_version = input("Manually specify CUDA version: ") self.env.update_tf_dep() - self.check_system_dependencies() if self.env.os_version[0] == "Windows": self.tips.pip() @@ -489,117 +488,6 @@ def cudnn_checkfiles_windows(self): cudnn_checkfile = os.path.join(self.env.cuda_path, "include", "cudnn.h") return [cudnn_checkfile] - def check_system_dependencies(self): - """ Check that system applications are installed """ - self.output.info("Checking System Dependencies...") - self.cmake_check() - if self.env.os_version[0] == "Windows": - self.visual_studio_check() - self.check_cplus_plus() - if self.env.os_version[0] == "Linux": - self.gcc_check() - self.gpp_check() - - def gcc_check(self): - """ Check installed gcc version for linux """ - chk = Popen("gcc --version", shell=True, stdout=PIPE, stderr=PIPE) - stdout, stderr = chk.communicate() - if stderr: - self.output.error("gcc not installed. Please install gcc for your distribution") - return - gcc = [re.sub(" +", " ", line.strip()) - for line in stdout.decode(self.env.encoding).splitlines() - if line.lower().strip().startswith("gcc")][0] - version = gcc[gcc.rfind(" ") + 1:] - self.output.info("gcc version: {}".format(version)) - - def gpp_check(self): - """ Check installed g++ version for linux """ - chk = Popen("g++ --version", shell=True, stdout=PIPE, stderr=PIPE) - stdout, stderr = chk.communicate() - if stderr: - self.output.error("g++ not installed. Please install g++ for your distribution") - return - gpp = [re.sub(" +", " ", line.strip()) - for line in stdout.decode(self.env.encoding).splitlines() - if line.lower().strip().startswith("g++")][0] - version = gpp[gpp.rfind(" ") + 1:] - self.output.info("g++ version: {}".format(version)) - - def cmake_check(self): - """ Check CMake is installed """ - chk = Popen("cmake --version", shell=True, stdout=PIPE, stderr=PIPE) - stdout, stderr = chk.communicate() - stdout = stdout.decode(self.env.encoding) - if stderr and self.env.os_version[0] == "Windows": - stdout, stderr = self.cmake_check_windows() - if stderr: - self.output.error("CMake could not be found. See " - "https://github.com/deepfakes/faceswap/blob/master/INSTALL.md#cmake " - "for instructions") - return - cmake = [re.sub(" +", " ", line.strip()) - for line in stdout.splitlines() - if line.lower().strip().startswith("cmake")][0] - version = cmake[cmake.rfind(" ") + 1:] - self.output.info("CMake version: {}".format(version)) - - def cmake_check_windows(self): - """ Additional checks for cmake on Windows """ - chk = Popen("wmic product where \"name = 'cmake'\" get installlocation,version", - shell=True, stdout=PIPE, stderr=PIPE) - stdout, stderr = chk.communicate() - if stderr: - return False, stderr - lines = [re.sub(" +", " ", line.strip()) - for line in stdout.decode(self.env.encoding).splitlines() - if line.strip()] - stdout = lines[1] - location = stdout[:stdout.rfind(" ")] + "bin" - self.output.info("CMake not found in %PATH%. Temporarily adding: \"{}\"".format(location)) - os.environ["PATH"] += ";{}".format(location) - stdout = "cmake {}".format(stdout) - return stdout, False - - def visual_studio_check(self): - """ Check Visual Studio 2015 is installed for Windows - - Somewhat hacky solution which checks for the existence - of the VS2015 Performance Report - """ - chk = Popen("reg query HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VSPerf", - shell=True, stdout=PIPE, stderr=PIPE) - _, stderr = chk.communicate() - if stderr: - self.output.error("Visual Studio 2015 could not be found. See " - "https://github.com/deepfakes/faceswap/blob/master/" - "INSTALL.md#microsoft-visual-studio-2015 for instructions") - return - self.output.info("Visual Studio 2015 version: 14.0") - - def check_cplus_plus(self): - """ Check Visual C++ Redistributable 2015 is instlled for Windows """ - keys = ( - "HKLM\\SOFTWARE\\Classes\\Installer\\Dependencies\\" - "{d992c12e-cab2-426f-bde3-fb8c53950b0d}", - "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64") - for key in keys: - chk = Popen("reg query {}".format(key), shell=True, stdout=PIPE, stderr=PIPE) - stdout, stderr = chk.communicate() - if stdout: - break - if stderr: - self.output.error("Visual C++ 2015 could not be found. Make sure you have selected " - "'Visual C++' in Visual Studio 2015 Configuration or download the " - "Visual C++ 2015 Redistributable from: " - "https://www.microsoft.com/en-us/download/details.aspx?id=48145") - return - vscpp = [re.sub(" +", " ", line.strip()) - for line in stdout.decode(self.env.encoding).splitlines() - if line.lower().strip().startswith(("displayname", "version"))][0] - version = vscpp[vscpp.find("REG_SZ") + 7:] - self.output.info("Visual Studio C++ version: {}".format(version)) - class Install(): """ Install the requirements """ @@ -655,7 +543,7 @@ def check_conda_missing_dep(self): def install_missing_dep(self): """ Install missing dependencies """ - # Install conda packages first as dlib will need Cuda + # Install conda packages first if self.env.conda_missing_packages: self.install_conda_packages() if self.env.missing_packages: @@ -711,16 +599,7 @@ def pip_installer(self, package): # install as user to solve perm restriction if not self.env.is_admin and not self.env.is_virtualenv: pipexe.append("--user") - if package.startswith("dlib"): - if not self.env.enable_cuda: - pipexe.extend(["--install-option=--no", "--install-option=DLIB_USE_CUDA"]) - if self.env.os_version[0] == "Windows": - pipexe.extend(["--global-option=-G", "--global-option=Visual Studio 14 2015"]) - msg = ("Compiling {}. This will take a while...\n" - "Please ignore the following UserWarning: " - "'Disabling all use of wheels...'".format(package)) - else: - msg = "Installing {}".format(package) + msg = "Installing {}".format(package) self.output.info(msg) pipexe.append(package) try: @@ -816,8 +695,8 @@ def macos(self): "will handle the installation of CUDA and cuDNN for you:\n" "https://www.anaconda.com/distribution/\n\n" - "2b. If you do not want to use Anaconda, or if you wish to compile DLIB with GPU\n" - "support you will need to manually install CUDA and cuDNN:\n" + "2b. If you do not want to use Anaconda you will need to manually install CUDA and " + "cuDNN:\n" "CUDA: https://developer.nvidia.com/cuda-downloads" "cuDNN: https://developer.nvidia.com/rdp/cudnn-download\n\n") diff --git a/tools/sort.py b/tools/sort.py index 310a45e0b0..0b133b3a8c 100644 --- a/tools/sort.py +++ b/tools/sort.py @@ -13,13 +13,12 @@ from tqdm import tqdm # faceswap imports -import face_recognition - from lib.cli import FullHelpArgumentParser from lib import Serializer from lib.faces_detect import DetectedFace from lib.multithreading import SpawnProcess from lib.queue_manager import queue_manager, QueueEmpty +from lib.utils import GetModel from plugins.plugin_loader import PluginLoader from . import cli @@ -34,6 +33,7 @@ def __init__(self, arguments): self.args = arguments self.changes = None self.serializer = None + self.vgg_face = VGGFace() def process(self): """ Main processing function of the sort tool """ @@ -181,7 +181,7 @@ def sort_face(self): logger.info("Sorting by face similarity...") - img_list = [[img, face_recognition.face_encodings(cv2.imread(img))] + img_list = [[img, self.vgg_face.predict(cv2.imread(img))] for img in tqdm(self.find_images(input_dir), desc="Loading", @@ -196,12 +196,7 @@ def sort_face(self): for j in range(i + 1, len(img_list)): f1encs = img_list[i][1] f2encs = img_list[j][1] - if f1encs and f2encs: - score = face_recognition.face_distance(f1encs[0], - f2encs)[0] - else: - score = float("inf") - + score = self.vgg_face.find_cosine_similiarity(f1encs, f2encs) if score < min_score: min_score = score j_min_score = j @@ -216,7 +211,7 @@ def sort_face_dissim(self): logger.info("Sorting by face dissimilarity...") - img_list = [[img, face_recognition.face_encodings(cv2.imread(img)), 0] + img_list = [[img, self.vgg_face.predict(cv2.imread(img)), 0] for img in tqdm(self.find_images(input_dir), desc="Loading", @@ -228,13 +223,9 @@ def sort_face_dissim(self): for j in range(0, img_list_len): if i == j: continue - try: - score_total += face_recognition.face_distance( - [img_list[i][1]], - [img_list[j][1]]) - except: - logger.info("except") - pass + score_total += self.vgg_face.find_cosine_similiarity( + img_list[i][1], + img_list[j][1]) img_list[i][2] = score_total @@ -429,7 +420,6 @@ def group_face(self, img_list): # Comparison threshold used to decide how similar # faces have to be to be grouped together. min_threshold = self.args.min_threshold - img_list_len = len(img_list) for i in tqdm(range(1, img_list_len), @@ -452,18 +442,16 @@ def group_face(self, img_list): # processed, as the first value is None. try: score = self.get_avg_score_faces(f1encs, references) - except TypeError: - score = float("inf") - except ZeroDivisionError: + except (TypeError, ValueError, ZeroDivisionError): score = float("inf") if score < current_best[1]: current_best[0], current_best[1] = key, score if current_best[1] < min_threshold: - reference_groups[current_best[0]].append(f1encs[0]) + reference_groups[current_best[0]].append(f1encs) bins[current_best[0]].append(img_list[i][0]) else: - reference_groups[len(reference_groups)] = img_list[i][1] + reference_groups[len(reference_groups)] = [img_list[i][1]] bins.append([img_list[i][0]]) return bins @@ -681,7 +669,7 @@ def reload_images(self, group_method, img_list): file=sys.stdout)] elif group_method == 'group_face': temp_list = [ - [img, face_recognition.face_encodings(cv2.imread(img))] + [img, self.vgg_face.predict(cv2.imread(img))] for img in tqdm(self.find_images(input_dir), desc="Reloading", file=sys.stdout)] @@ -867,13 +855,12 @@ def get_avg_score_hist(img1, references): scores.append(score) return sum(scores) / len(scores) - @staticmethod - def get_avg_score_faces(f1encs, references): + def get_avg_score_faces(self, f1encs, references): """ Return the average similarity score between a face and reference image """ scores = [] for f2encs in references: - score = face_recognition.face_distance(f1encs, f2encs)[0] + score = self.vgg_face.find_cosine_similiarity(f1encs, f2encs) scores.append(score) return sum(scores) / len(scores) @@ -908,3 +895,63 @@ def bad_args(args): # pylint: disable=unused-argument PARSER.set_defaults(func=bad_args) ARGUMENTS = PARSER.parse_args() ARGUMENTS.func(ARGUMENTS) + + +class VGGFace(): + """ Temporary drop-in replacement for face_recognition.face_encodings """ + # TODO: Replace with GPU bound keras-vgg-face + def __init__(self): + git_model_id = 7 + model_filename = ["vgg_face_v1.caffemodel", "vgg_face_v1.prototxt"] + self.input_size = 224 + self.model = self.get_model(git_model_id, model_filename) + + @staticmethod + def get_model(git_model_id, model_filename): + """ Check if model is available, if not, download and unzip it """ + root_path = os.path.abspath(os.path.dirname(sys.argv[0])) + cache_path = os.path.join(root_path, "plugins", "extract", ".cache") + model = GetModel(model_filename, cache_path, git_model_id).model_path + vgg_face = cv2.dnn.readNetFromCaffe(model[1], model[0]) # pylint: disable=no-member + vgg_face.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU) # pylint: disable=no-member + return vgg_face + + def predict(self, face): + """ Return face encodings from vgg_face """ + if face.shape[0] != self.input_size: + face = self.resize_face(face) + blob = cv2.dnn.blobFromImage(face, # pylint: disable=no-member + 1.0, + (self.input_size, self.input_size), + [104, 117, 123], + False, + False) + logger.trace("vgg_face input shape: %s", blob.shape) + self.model.setInput(blob) + preds = self.model.forward()[0, :] + logger.trace("vgg_face encoding shape: %s", preds.shape) + return preds + + def resize_face(self, face): + """ Resize incoming face to model_input_size """ + if face.shape[0] < self.input_size: + interpolation = cv2.INTER_CUBIC # pylint:disable=no-member + else: + interpolation = cv2.INTER_AREA # pylint:disable=no-member + + face = cv2.resize(face, # pylint:disable=no-member + dsize=(self.input_size, self.input_size), + interpolation=interpolation) + return face + + @staticmethod + def find_cosine_similiarity(source_face, test_face): + """ Find the cosine similarity between a source face and a test face """ + logger.trace("source_face shape: %s, test_face shape: %s", + source_face.shape, test_face.shape) + var_a = np.matmul(np.transpose(source_face), test_face) + var_b = np.sum(np.multiply(source_face, source_face)) + var_c = np.sum(np.multiply(test_face, test_face)) + retval = 1 - (var_a / (np.sqrt(var_b) * np.sqrt(var_c))) + logger.debug("Similarity: %s", retval) + return retval