From f0ae26f98e957e2efe450e6853a4874a4140cca0 Mon Sep 17 00:00:00 2001 From: Adrian Hesketh Date: Fri, 3 May 2024 09:48:36 +0100 Subject: [PATCH] feat: add Nix flake --- deepface/detectors/OpenCv.py | 3 + flake.lock | 27 +++++ flake.nix | 197 ++++++++++++++++++++++++++++++++++ mtcnn-0001-merge-pr-129.patch | 22 ++++ 4 files changed, 249 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 mtcnn-0001-merge-pr-129.patch diff --git a/deepface/detectors/OpenCv.py b/deepface/detectors/OpenCv.py index 9b59d7d..c00722d 100644 --- a/deepface/detectors/OpenCv.py +++ b/deepface/detectors/OpenCv.py @@ -168,6 +168,9 @@ class OpenCvClient(Detector): Returns: installation_path (str) """ + if os.getenv("OPENCV_PATH", "") != "": + return os.getenv("OPENCV_PATH") + opencv_home = cv2.__file__ folders = opencv_home.split(os.path.sep)[0:-1] diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..908e186 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1714253743, + "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..24b3a08 --- /dev/null +++ b/flake.nix @@ -0,0 +1,197 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + }; + + outputs = { self, nixpkgs }: + let + allSystems = [ + "x86_64-linux" # 64-bit Intel/AMD Linux + "aarch64-linux" # 64-bit ARM Linux + "x86_64-darwin" # 64-bit Intel macOS + "aarch64-darwin" # 64-bit ARM macOS + ]; + + forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f { + pkgs = import nixpkgs { + inherit system; + }; + }); + + # Deepface requires mtcnn, which requires keras 2.14.0, but nixpkgs has 3.x releases in it. + # So, manually package the required version. + python-keras = pkgs: pkgs.python311Packages.buildPythonPackage rec { + pname = "keras"; + version = "2.14.0"; + format = "wheel"; + + src = pkgs.fetchPypi { + inherit format pname version; + hash = "sha256-10KdHSExzH6x8uouwzAifH2dONqz398ueN7+5OzEP80="; + python = "py3"; + dist = "py3"; + }; + + nativeCheckInputs = [ + pkgs.pytest + pkgs.pytest-cov + pkgs.pytest-xdist + ]; + + propagatedBuildInputs = [ + pkgs.python311Packages.six + pkgs.python311Packages.pyyaml + pkgs.python311Packages.numpy + pkgs.python311Packages.scipy + pkgs.python311Packages.h5py + pkgs.python311Packages.keras-applications + pkgs.python311Packages.keras-preprocessing + ]; + + # Skip tests. + doCheck = false; + }; + # Deepface requires mtcnn. + # https://github.com/ipazc/mtcnn + mtcnn-src = pkgs: pkgs.fetchFromGitHub { + owner = "ipazc"; + repo = "mtcnn"; + rev = "master"; + sha256 = "sha256-GXUrLJ5XD6V2hT/gjyYSuh/CMMw2xIXKBsYFvQmbLYs="; + }; + mtcnn = pkgs: pkgs.python311Packages.buildPythonPackage { + pname = "mtcnn"; + version = "main"; + + src = "${(mtcnn-src pkgs)}"; + + # Do not run tests. + doCheck = false; + + # Add dependencies. + propagatedBuildInputs = [ + pkgs.python311Packages.tensorflow + (python-keras pkgs) + pkgs.python311Packages.opencv4 + ]; + + # Patch https://github.com/ipazc/mtcnn/pull/129 which fixes a bug due to a breaking + # change in setuptools. + patches = [ ./mtcnn-0001-merge-pr-129.patch ]; + + build-system = [ + pkgs.python311Packages.setuptools + pkgs.python311Packages.wheel + ]; + }; + # Deepface requires https://github.com/heewinkim/retinaface + retinaface = pkgs: pkgs.python311Packages.buildPythonPackage { + pname = "retinaface"; + version = "0.0.1"; + + src = pkgs.fetchFromGitHub { + owner = "heewinkim"; + repo = "retinaface"; + rev = "master"; + sha256 = "sha256-ELnTLgWiz8/b55JIPNZ0xkpCIyLyADomT07lp9LhAYU="; + }; + + # Do not run tests. + doCheck = false; + + build-system = [ + pkgs.python311Packages.setuptools + pkgs.python311Packages.wheel + ]; + }; + deepface-deps = pkgs: [ + pkgs.python311Packages.tensorflow + pkgs.python311Packages.pandas + pkgs.python311Packages.gdown + (mtcnn pkgs) + (retinaface pkgs) + pkgs.python311Packages.opencv4 + pkgs.python311Packages.gunicorn # Required to run app. + pkgs.python311Packages.flask # Required to run app. + pkgs.python311Packages.pytest # Required to run app. + ]; + python-with-deepface-deps = pkgs: pkgs.python311.withPackages (python-pkgs: + (deepface-deps pkgs) + ); + deepface = pkgs: pkgs.python311Packages.buildPythonPackage { + pname = "deepface"; + version = "v0.0.90"; + + src = ./.; + + # Do not run tests. + doCheck = false; + + # Add dependencies. + propagatedBuildInputs = deepface-deps pkgs; + + build-system = [ + pkgs.python311Packages.setuptools + pkgs.python311Packages.wheel + ]; + }; + python-with-deepface = pkgs: pkgs.python311.withPackages (python-pkgs: [ + (deepface pkgs) + ]); + deepface-weights = pkgs: pkgs.fetchurl { + url = "https://github.com/serengil/deepface_models/releases/download/v1.0/vgg_face_weights.h5"; + hash = "sha256-dZJmuWFND9XWW5e/cWgYt0bMd6tZRMe//JN8a6lFXYw="; + }; + deepface-home = pkgs: pkgs.stdenv.mkDerivation { + name = "deepface-home"; + + dontUnpack = true; + + src = ./.; + + installPhase = '' + mkdir -p $out/opt/deepface/home/.deepface/weights + cp ${deepface-weights pkgs} $out/opt/deepface/home/.deepface/weights/vgg_face_weights.h5 + ''; + }; + deepface-api = pkgs: pkgs.stdenv.mkDerivation { + name = "deepface-api"; + + # Runtime dependencies. + propagatedBuildInputs = [ + (python-with-deepface pkgs) + ]; + + # Unpacking runs the tests, which modify data on disk, so skip that, + # because Nix requires read only inputs. + dontUnpack = true; + + src = ./.; + + installPhase = '' + mkdir -p $out/opt/deepface-api + cp -r $src/deepface/api/src/* $out/opt/deepface-api + ''; + }; + in + { + packages = forAllSystems ({ pkgs }: { + default = pkgs.writeShellScriptBin "deepface-api" '' + # Set the path for the opencv data files. + # Data files are found at, for example, /nix/store/c1h6iyvpi2j7a9bypjnvz9zlw4lq1psk-opencv-4.9.0/share/opencv4/haarcascades/haarcascade_eye.xml + export OPENCV_PATH="${(pkgs.python311Packages.opencv4)}/share/opencv4/haarcascades/" + # Set the home directory where the weights are stored. + export DEEPFACE_HOME="${(deepface-home pkgs)}/opt/deepface/home" + ${(python-with-deepface pkgs)}/bin/python ${deepface-api pkgs}/opt/deepface-api/api.py + ''; + python311Packages.deepface = (deepface pkgs); + }); + devShells = forAllSystems ({ pkgs }: { + default = pkgs.mkShell { + packages = [ + (python-with-deepface-deps pkgs) + ]; + }; + }); + }; +} diff --git a/mtcnn-0001-merge-pr-129.patch b/mtcnn-0001-merge-pr-129.patch new file mode 100644 index 0000000..f11226d --- /dev/null +++ b/mtcnn-0001-merge-pr-129.patch @@ -0,0 +1,22 @@ +diff --git a/setup.py b/setup.py +index fd019b4..389a258 100644 +--- a/setup.py ++++ b/setup.py +@@ -24,7 +24,7 @@ + # SOFTWARE. + + import sys +-from setuptools import setup, setuptools ++from setuptools import setup, find_packages + + + __author__ = "Iván de Paz Centeno" +@@ -48,7 +48,7 @@ setup(name='mtcnn', + author='Iván de Paz Centeno', + author_email='ipazc@unileon.es', + license='MIT', +- packages=setuptools.find_packages(exclude=["tests.*", "tests"]), ++ packages=find_packages(exclude=["tests.*", "tests"]), + install_requires=[ + "keras>=2.0.0", + "opencv-python>=4.1.0"