Merge pull request #268619 from tweag/lib-descriptions
[NixPkgs.git] / pkgs / development / libraries / opencv / 4.x.nix
blob06360449c1ba96a1ef8f67456129a96f0d569c2b
1 { lib
2 , stdenv
3 , fetchurl
4 , fetchFromGitHub
5 , fetchpatch
6 , cmake
7 , pkg-config
8 , unzip
9 , zlib
10 , pcre
11 , hdf5
12 , boost
13 , gflags
14 , protobuf_21
15 , config
16 , ocl-icd
17 , buildPackages
18 , qimgv
19 , opencv4
21 , enableJPEG ? true
22 , libjpeg
23 , enablePNG ? true
24 , libpng
25 , enableTIFF ? true
26 , libtiff
27 , enableWebP ? true
28 , libwebp
29 , enableEXR ? !stdenv.isDarwin
30 , openexr
31 , ilmbase
32 , enableJPEG2000 ? true
33 , openjpeg
34 , enableEigen ? true
35 , eigen
36 , enableBlas ? true
37 , blas
38 , enableContrib ? true
40 , enableCuda ? config.cudaSupport
41 , enableCublas ? enableCuda
42 , enableCudnn ? false # NOTE: CUDNN has a large impact on closure size so we disable it by default
43 , enableCufft ? enableCuda
44 , cudaPackages ? {}
45 , nvidia-optical-flow-sdk
47 , enableLto ? true
48 , enableUnfree ? false
49 , enableIpp ? false
50 , enablePython ? false
51 , pythonPackages
52 , enableGtk2 ? false
53 , gtk2
54 , enableGtk3 ? false
55 , gtk3
56 , enableVtk ? false
57 , vtk
58 , enableFfmpeg ? true
59 , ffmpeg
60 , enableGStreamer ? true
61 , gst_all_1
62 , enableTesseract ? false
63 , tesseract
64 , leptonica
65 , enableTbb ? false
66 , tbb
67 , enableOvis ? false
68 , ogre
69 , enableGPhoto2 ? false
70 , libgphoto2
71 , enableDC1394 ? false
72 , libdc1394
73 , enableDocs ? false
74 , doxygen
75 , graphviz-nox
77 , AVFoundation
78 , Cocoa
79 , VideoDecodeAcceleration
80 , CoreMedia
81 , MediaToolbox
82 , Accelerate
83 , bzip2
84 , callPackage
85 }@inputs:
87 let
88   version = "4.7.0";
90   # It's necessary to consistently use backendStdenv when building with CUDA
91   # support, otherwise we get libstdc++ errors downstream
92   stdenv = throw "Use effectiveStdenv instead";
93   effectiveStdenv = if enableCuda then cudaPackages.backendStdenv else inputs.stdenv;
95   src = fetchFromGitHub {
96     owner = "opencv";
97     repo = "opencv";
98     rev = version;
99     sha256 = "sha256-jUeGsu8+jzzCnIFbVMCW8DcUeGv/t1yCY/WXyW+uGDI=";
100   };
102   contribSrc = fetchFromGitHub {
103     owner = "opencv";
104     repo = "opencv_contrib";
105     rev = version;
106     sha256 = "sha256-meya0J3RdOIeMM46e/6IOVwrKn3t/c0rhwP2WQaybkE=";
107   };
109   testDataSrc = fetchFromGitHub {
110     owner = "opencv";
111     repo = "opencv_extra";
112     rev = version;
113     sha256 = "sha256-6hAdJdaUgtRGQanQKuY/q6fcXWXFZ3K/oLbGxvksry0=";
114   };
116   # Contrib must be built in order to enable Tesseract support:
117   buildContrib = enableContrib || enableTesseract || enableOvis;
119   # See opencv/3rdparty/ippicv/ippicv.cmake
120   ippicv = {
121     src = fetchFromGitHub {
122       owner = "opencv";
123       repo = "opencv_3rdparty";
124       rev = "a56b6ac6f030c312b2dce17430eef13aed9af274";
125       sha256 = "1msbkc3zixx61rcg6a04i1bcfhw1phgsrh93glq1n80hgsk3nbjq";
126     } + "/ippicv";
127     files = let name = platform: "ippicv_2019_${platform}_general_20180723.tgz"; in
128       if effectiveStdenv.hostPlatform.system == "x86_64-linux" then
129         { ${name "lnx_intel64"} = "c0bd78adb4156bbf552c1dfe90599607"; }
130       else if effectiveStdenv.hostPlatform.system == "i686-linux" then
131         { ${name "lnx_ia32"} = "4f38432c30bfd6423164b7a24bbc98a0"; }
132       else if effectiveStdenv.hostPlatform.system == "x86_64-darwin" then
133         { ${name "mac_intel64"} = "fe6b2bb75ae0e3f19ad3ae1a31dfa4a2"; }
134       else
135         throw "ICV is not available for this platform (or not yet supported by this package)";
136     dst = ".cache/ippicv";
137   };
139   # See opencv_contrib/modules/xfeatures2d/cmake/download_vgg.cmake
140   vgg = {
141     src = fetchFromGitHub {
142       owner = "opencv";
143       repo = "opencv_3rdparty";
144       rev = "fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d";
145       sha256 = "0r9fam8dplyqqsd3qgpnnfgf9l7lj44di19rxwbm8mxiw0rlcdvy";
146     };
147     files = {
148       "vgg_generated_48.i" = "e8d0dcd54d1bcfdc29203d011a797179";
149       "vgg_generated_64.i" = "7126a5d9a8884ebca5aea5d63d677225";
150       "vgg_generated_80.i" = "7cd47228edec52b6d82f46511af325c5";
151       "vgg_generated_120.i" = "151805e03568c9f490a5e3a872777b75";
152     };
153     dst = ".cache/xfeatures2d/vgg";
154   };
156   # See opencv_contrib/modules/xfeatures2d/cmake/download_boostdesc.cmake
157   boostdesc = {
158     src = fetchFromGitHub {
159       owner = "opencv";
160       repo = "opencv_3rdparty";
161       rev = "34e4206aef44d50e6bbcd0ab06354b52e7466d26";
162       sha256 = "13yig1xhvgghvxspxmdidss5lqiikpjr0ddm83jsi0k85j92sn62";
163     };
164     files = {
165       "boostdesc_bgm.i" = "0ea90e7a8f3f7876d450e4149c97c74f";
166       "boostdesc_bgm_bi.i" = "232c966b13651bd0e46a1497b0852191";
167       "boostdesc_bgm_hd.i" = "324426a24fa56ad9c5b8e3e0b3e5303e";
168       "boostdesc_binboost_064.i" = "202e1b3e9fec871b04da31f7f016679f";
169       "boostdesc_binboost_128.i" = "98ea99d399965c03d555cef3ea502a0b";
170       "boostdesc_binboost_256.i" = "e6dcfa9f647779eb1ce446a8d759b6ea";
171       "boostdesc_lbgm.i" = "0ae0675534aa318d9668f2a179c2a052";
172     };
173     dst = ".cache/xfeatures2d/boostdesc";
174   };
176   # See opencv_contrib/modules/face/CMakeLists.txt
177   face = {
178     src = fetchFromGitHub {
179       owner = "opencv";
180       repo = "opencv_3rdparty";
181       rev = "8afa57abc8229d611c4937165d20e2a2d9fc5a12";
182       sha256 = "061lsvqdidq9xa2hwrcvwi9ixflr2c2lfpc8drr159g68zi8bp4v";
183     };
184     files = {
185       "face_landmark_model.dat" = "7505c44ca4eb54b4ab1e4777cb96ac05";
186     };
187     dst = ".cache/data";
188   };
190   # See opencv/modules/gapi/cmake/DownloadADE.cmake
191   ade = rec {
192     src = fetchurl {
193       url = "https://github.com/opencv/ade/archive/${name}";
194       sha256 = "sha256-TjLRbFbC7MDY9PxIy560ryviBI58cbQwqgc7A7uOHkg=";
195     };
196     name = "v0.1.2a.zip";
197     md5 = "fa4b3e25167319cb0fa9432ef8281945";
198     dst = ".cache/ade";
199   };
201   # See opencv_contrib/modules/wechat_qrcode/CMakeLists.txt
202   wechat_qrcode = {
203     src = fetchFromGitHub {
204       owner = "opencv";
205       repo = "opencv_3rdparty";
206       rev = "a8b69ccc738421293254aec5ddb38bd523503252";
207       sha256 = "sha256-/n6zHwf0Rdc4v9o4rmETzow/HTv+81DnHP+nL56XiTY=";
208     };
209     files = {
210       "detect.caffemodel" = "238e2b2d6f3c18d6c3a30de0c31e23cf";
211       "detect.prototxt" = "6fb4976b32695f9f5c6305c19f12537d";
212       "sr.caffemodel" = "cbfcd60361a73beb8c583eea7e8e6664";
213       "sr.prototxt" = "69db99927a70df953b471daaba03fbef";
214     };
215     dst = ".cache/wechat_qrcode";
216   };
218   # See opencv/cmake/OpenCVDownload.cmake
219   installExtraFiles = extra: with lib; ''
220     mkdir -p "${extra.dst}"
221   '' + concatStrings (flip mapAttrsToList extra.files (name: md5: ''
222     ln -s "${extra.src}/${name}" "${extra.dst}/${md5}-${name}"
223   ''));
224   installExtraFile = extra: ''
225     mkdir -p "${extra.dst}"
226     ln -s "${extra.src}" "${extra.dst}/${extra.md5}-${extra.name}"
227   '';
229   opencvFlag = name: enabled: "-DWITH_${name}=${printEnabled enabled}";
231   runAccuracyTests = true;
232   runPerformanceTests = false;
233   printEnabled = enabled: if enabled then "ON" else "OFF";
234   withOpenblas = (enableBlas && blas.provider.pname == "openblas");
235   #multithreaded openblas conflicts with opencv multithreading, which manifest itself in hung tests
236   #https://github.com/xianyi/OpenBLAS/wiki/Faq/4bded95e8dc8aadc70ce65267d1093ca7bdefc4c#multi-threaded
237   openblas_ = blas.provider.override { singleThreaded = true; };
239   inherit (cudaPackages) cudaFlags cudaVersion;
240   inherit (cudaFlags) cudaCapabilities;
244 effectiveStdenv.mkDerivation {
245   pname = "opencv";
246   inherit version src;
248   outputs = [
249     "out"
250     "package_tests"
251   ];
253   postUnpack = lib.optionalString buildContrib ''
254     cp --no-preserve=mode -r "${contribSrc}/modules" "$NIX_BUILD_TOP/source/opencv_contrib"
255   '';
257   # Ensures that we use the system OpenEXR rather than the vendored copy of the source included with OpenCV.
258   patches = [
259     ./cmake-don-t-use-OpenCVFindOpenEXR.patch
260   ] ++ lib.optionals enableContrib [
261     (fetchpatch {
262       name = "CVE-2023-2617.patch";
263       url = "https://github.com/opencv/opencv_contrib/commit/ccc277247ac1a7aef0a90353edcdec35fbc5903c.patch";
264       stripLen = 2;
265       extraPrefix = [ "opencv_contrib/" ];
266       sha256 = "sha256-drZ+DVn+Pk4zAZJ+LgX5u3Tz7MU0AEI/73EVvxDP3AU=";
267     })
268     (fetchpatch {
269       name = "CVE-2023-2618.patch";
270       url = "https://github.com/opencv/opencv_contrib/commit/ec406fa4748fb4b0630c1b986469e7918d5e8953.patch";
271       stripLen = 2;
272       extraPrefix = [ "opencv_contrib/" ];
273       sha256 = "sha256-cB5Tsh2fDOsc0BNtSzd6U/QoCjkd9yMW1QutUU69JJ0=";
274     })
275   ] ++ lib.optional enableCuda ./cuda_opt_flow.patch;
277   # This prevents cmake from using libraries in impure paths (which
278   # causes build failure on non NixOS)
279   postPatch = ''
280     sed -i '/Add these standard paths to the search paths for FIND_LIBRARY/,/^\s*$/{d}' CMakeLists.txt
281   '';
283   preConfigure =
284     installExtraFile ade +
285     lib.optionalString enableIpp (installExtraFiles ippicv) + (
286       lib.optionalString buildContrib ''
287         cmakeFlagsArray+=("-DOPENCV_EXTRA_MODULES_PATH=$NIX_BUILD_TOP/source/opencv_contrib")
289         ${installExtraFiles vgg}
290         ${installExtraFiles boostdesc}
291         ${installExtraFiles face}
292         ${installExtraFiles wechat_qrcode}
293       ''
294     );
296   postConfigure = ''
297     [ -e modules/core/version_string.inc ]
298     echo '"(build info elided)"' > modules/core/version_string.inc
299   '';
301   buildInputs = [ zlib pcre boost gflags protobuf_21 ]
302     ++ lib.optional enablePython pythonPackages.python
303     ++ lib.optional (effectiveStdenv.buildPlatform == effectiveStdenv.hostPlatform) hdf5
304     ++ lib.optional enableGtk2 gtk2
305     ++ lib.optional enableGtk3 gtk3
306     ++ lib.optional enableVtk vtk
307     ++ lib.optional enableJPEG libjpeg
308     ++ lib.optional enablePNG libpng
309     ++ lib.optional enableTIFF libtiff
310     ++ lib.optional enableWebP libwebp
311     ++ lib.optionals enableEXR [ openexr ilmbase ]
312     ++ lib.optional enableJPEG2000 openjpeg
313     ++ lib.optional enableFfmpeg ffmpeg
314     ++ lib.optionals (enableFfmpeg && effectiveStdenv.isDarwin)
315       [ VideoDecodeAcceleration bzip2 ]
316     ++ lib.optionals enableGStreamer (with gst_all_1; [ gstreamer gst-plugins-base gst-plugins-good ])
317     ++ lib.optional enableOvis ogre
318     ++ lib.optional enableGPhoto2 libgphoto2
319     ++ lib.optional enableDC1394 libdc1394
320     ++ lib.optional enableEigen eigen
321     ++ lib.optional enableBlas blas.provider
322     # There is seemingly no compile-time flag for Tesseract.  It's
323     # simply enabled automatically if contrib is built, and it detects
324     # tesseract & leptonica.
325     ++ lib.optionals enableTesseract [ tesseract leptonica ]
326     ++ lib.optional enableTbb tbb
327     ++ lib.optionals effectiveStdenv.isDarwin [
328       bzip2 AVFoundation Cocoa VideoDecodeAcceleration CoreMedia MediaToolbox Accelerate
329     ]
330     ++ lib.optionals enableDocs [ doxygen graphviz-nox ]
331     ++ lib.optionals enableCuda  (with cudaPackages; [
332       cuda_cudart
333       cuda_cccl # <thrust/*>
334       libnpp # npp.h
335     ] ++ lib.optionals enableCublas [
336       libcublas # cublas_v2.h
337     ] ++ lib.optionals enableCudnn [
338       cudnn # cudnn.h
339     ] ++ lib.optionals enableCufft [
340       libcufft # cufft.h
341   ]);
343   propagatedBuildInputs = lib.optional enablePython pythonPackages.numpy
344     ++ lib.optionals enableCuda [ nvidia-optical-flow-sdk ];
346   nativeBuildInputs = [ cmake pkg-config unzip ]
347   ++ lib.optionals enablePython [
348     pythonPackages.pip
349     pythonPackages.wheel
350     pythonPackages.setuptools
351   ] ++ lib.optionals enableCuda [
352     cudaPackages.cuda_nvcc
353   ];
355   env.NIX_CFLAGS_COMPILE = lib.optionalString enableEXR "-I${ilmbase.dev}/include/OpenEXR";
357   # Configure can't find the library without this.
358   OpenBLAS_HOME = lib.optionalString withOpenblas openblas_.dev;
359   OpenBLAS = lib.optionalString withOpenblas openblas_;
361   cmakeFlags = [
362     "-DOPENCV_GENERATE_PKGCONFIG=ON"
363     "-DWITH_OPENMP=ON"
364     "-DBUILD_PROTOBUF=OFF"
365     "-DProtobuf_PROTOC_EXECUTABLE=${lib.getExe buildPackages.protobuf_21}"
366     "-DPROTOBUF_UPDATE_FILES=ON"
367     "-DOPENCV_ENABLE_NONFREE=${printEnabled enableUnfree}"
368     "-DBUILD_TESTS=${printEnabled runAccuracyTests}"
369     "-DBUILD_PERF_TESTS=${printEnabled runPerformanceTests}"
370     "-DCMAKE_SKIP_BUILD_RPATH=ON"
371     "-DBUILD_DOCS=${printEnabled enableDocs}"
372     # "OpenCV disables pkg-config to avoid using of host libraries. Consider using PKG_CONFIG_LIBDIR to specify target SYSROOT"
373     # but we have proper separation of build and host libs :), fixes cross
374     "-DOPENCV_ENABLE_PKG_CONFIG=ON"
375     (opencvFlag "IPP" enableIpp)
376     (opencvFlag "TIFF" enableTIFF)
377     (opencvFlag "WEBP" enableWebP)
378     (opencvFlag "JPEG" enableJPEG)
379     (opencvFlag "PNG" enablePNG)
380     (opencvFlag "OPENEXR" enableEXR)
381     (opencvFlag "OPENJPEG" enableJPEG2000)
382     "-DWITH_JASPER=OFF" # OpenCV falls back to a vendored copy of Jasper when OpenJPEG is disabled
383     (opencvFlag "TBB" enableTbb)
385     # CUDA options
386     (opencvFlag "CUDA" enableCuda)
387     (opencvFlag "CUDA_FAST_MATH" enableCuda)
388     (opencvFlag "CUBLAS" enableCublas)
389     (opencvFlag "CUDNN" enableCudnn)
390     (opencvFlag "CUFFT" enableCufft)
392     # LTO options
393     (opencvFlag "ENABLE_LTO" enableLto)
394     (opencvFlag "ENABLE_THIN_LTO" (
395       enableLto && (
396         # Only clang supports thin LTO, so we must either be using clang through the effectiveStdenv,
397         effectiveStdenv.cc.isClang ||
398           # or through the backend effectiveStdenv.
399           (enableCuda && effectiveStdenv.cc.isClang)
400       )
401     ))
402   ] ++ lib.optionals enableCuda [
403     "-DCUDA_FAST_MATH=ON"
404     "-DCUDA_NVCC_FLAGS=--expt-relaxed-constexpr"
406     # OpenCV respects at least three variables:
407     # -DCUDA_GENERATION takes a single arch name, e.g. Volta
408     # -DCUDA_ARCH_BIN takes a semi-colon separated list of real arches, e.g. "8.0;8.6"
409     # -DCUDA_ARCH_PTX takes the virtual arch, e.g. "8.6"
410     "-DCUDA_ARCH_BIN=${lib.concatStringsSep ";" cudaCapabilities}"
411     "-DCUDA_ARCH_PTX=${lib.last cudaCapabilities}"
413     "-DNVIDIA_OPTICAL_FLOW_2_0_HEADERS_PATH=${nvidia-optical-flow-sdk}"
414   ] ++ lib.optionals effectiveStdenv.isDarwin [
415     "-DWITH_OPENCL=OFF"
416     "-DWITH_LAPACK=OFF"
418     # Disable unnecessary vendoring that's enabled by default only for Darwin.
419     # Note that the opencvFlag feature flags listed above still take
420     # precedence, so we can safely list everything here.
421     "-DBUILD_ZLIB=OFF"
422     "-DBUILD_TIFF=OFF"
423     "-DBUILD_OPENJPEG=OFF"
424     "-DBUILD_JASPER=OFF"
425     "-DBUILD_JPEG=OFF"
426     "-DBUILD_PNG=OFF"
427     "-DBUILD_WEBP=OFF"
428   ] ++ lib.optionals (!effectiveStdenv.isDarwin) [
429     "-DOPENCL_LIBRARY=${ocl-icd}/lib/libOpenCL.so"
430   ] ++ lib.optionals enablePython [
431     "-DOPENCV_SKIP_PYTHON_LOADER=ON"
432   ];
434   postBuild = lib.optionalString enableDocs ''
435     make doxygen
436   '';
438   preInstall =
439     lib.optionalString (runAccuracyTests || runPerformanceTests) ''
440     mkdir $package_tests
441     cp -R $src/samples $package_tests/
442     ''
443     + lib.optionalString runAccuracyTests "mv ./bin/*test* $package_tests/ \n"
444     + lib.optionalString runPerformanceTests "mv ./bin/*perf* $package_tests/";
446   # By default $out/lib/pkgconfig/opencv4.pc looks something like this:
447   #
448   #   prefix=/nix/store/g0wnfyjjh4rikkvp22cpkh41naa43i4i-opencv-4.0.0
449   #   exec_prefix=${prefix}
450   #   libdir=${exec_prefix}//nix/store/g0wnfyjjh4rikkvp22cpkh41naa43i4i-opencv-4.0.0/lib
451   #   includedir_old=${prefix}//nix/store/g0wnfyjjh4rikkvp22cpkh41naa43i4i-opencv-4.0.0/include/opencv4/opencv
452   #   includedir_new=${prefix}//nix/store/g0wnfyjjh4rikkvp22cpkh41naa43i4i-opencv-4.0.0/include/opencv4
453   #   ...
454   #   Libs: -L${exec_prefix}//nix/store/g0wnfyjjh4rikkvp22cpkh41naa43i4i-opencv-4.0.0/lib ...
455   # Note that ${exec_prefix} is set to $out but that $out is also appended to
456   # ${exec_prefix}. This causes linker errors in downstream packages so we strip
457   # of $out after the ${exec_prefix} and ${prefix} prefixes:
458   postInstall = ''
459     sed -i "s|{exec_prefix}/$out|{exec_prefix}|;s|{prefix}/$out|{prefix}|" \
460       "$out/lib/pkgconfig/opencv4.pc"
461   ''
462   # install python distribution information, so other packages can `import opencv`
463   + lib.optionalString enablePython ''
464     pushd $NIX_BUILD_TOP/$sourceRoot/modules/python/package
465     python -m pip wheel --verbose --no-index --no-deps --no-clean --no-build-isolation --wheel-dir dist .
467     pushd dist
468     python -m pip install ./*.whl --no-index --no-warn-script-location --prefix="$out" --no-cache
470     # the cv2/__init__.py just tries to check provide "nice user feedback" if the installation is bad
471     # however, this also causes infinite recursion when used by other packages
472     rm -r $out/${pythonPackages.python.sitePackages}/cv2
474     popd
475     popd
476   '';
478   passthru = {
479     tests = {
480       inherit (gst_all_1) gst-plugins-bad;
481     }
482     // lib.optionalAttrs (!effectiveStdenv.isDarwin) { inherit qimgv; }
483     // lib.optionalAttrs (!enablePython) { pythonEnabled = pythonPackages.opencv4; }
484     // lib.optionalAttrs (effectiveStdenv.buildPlatform != "x86_64-darwin") {
485       opencv4-tests = callPackage ./tests.nix {
486         inherit enableGStreamer enableGtk2 enableGtk3 runAccuracyTests runPerformanceTests testDataSrc;
487         inherit opencv4;
488       };
489     }
490     // lib.optionalAttrs (enableCuda) {
491       no-libstdcxx-errors = callPackage ./libstdcxx-test.nix { attrName = "opencv4"; };
492     };
493   } // lib.optionalAttrs enablePython { pythonPath = [ ]; };
495   meta = with lib; {
496     description = "Open Computer Vision Library with more than 500 algorithms";
497     homepage = "https://opencv.org/";
498     license = with licenses; if enableUnfree then unfree else bsd3;
499     maintainers = with maintainers; [ basvandijk ];
500     platforms = with platforms; linux ++ darwin;
501   };