PKG Add opencv-python, ffmpeg and libwebp (#2305)

* Add opencv-python

* Update comment

* Add JPEG, PNG, WEBP, ZLIB support

* Add tests for image processing

* Add more core modules

* Disable opencl

* Replace lena with baboon and add more tests

* Add file system support

* Add ffmpeg

* Add more tests

* Disable pthread in ffmpeg

* Disable canonical input processing mode in node test

* Update changelog

* Remove import test

* Allow more time in the first test

* Split out libwebp

* Fix node test

* Use a seperate CI job for opencv-python

* Fix generator

* Update changelog

* Remove protobuf package

* Try to fix CI workspace conflict

* Fix CI

* Use another CI job for generating unified packages.json

* Try to fix CI

* Fix CI again

* Disable verbose build

* Prevent from building opencv-python twice

* Persist only build artifacts

* Sepearate Cmake args into a script

* Try to reuse build packages job

* Fix CI

* Fix typo

* Fix merge conflict

* Use large resource class for package build

* Do not upload unwanted artifacts

* Do not upload unwanted artifacts
This commit is contained in:
Gyeongjae Choi 2022-04-19 09:24:47 +09:00 committed by GitHub
parent 5f52842a57
commit 6900afdc5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1205 additions and 90 deletions

View File

@ -111,78 +111,13 @@ jobs:
- store_artifacts:
path: /root/repo/packages/build-logs
build-packages-no-numpy-dependents:
<<: *defaults
resource_class: large
steps:
- checkout
- attach_workspace:
at: .
- restore_cache:
keys:
- -pkg1-v20220303-{{ checksum "Makefile.envs" }}
- -pkg1-v20220303
- run:
name: build packages
no_output_timeout: 30m
command: |
source pyodide_env.sh
# Set mtime for EM_CONFIG to avoid ccache cache misses
touch -m -d '1 Jan 2021 12:00' emsdk/emsdk/.emscripten
ccache -z
PYODIDE_PACKAGES='*, no-numpy-dependents' make -C packages
ccache -s
environment:
PYODIDE_JOBS: 5
- run:
name: check-size
command: ls -lh dist/
- save_cache:
paths:
- /root/.ccache
key: -pkg1-v20220303-{{ checksum "Makefile.envs" }}
- persist_to_workspace:
root: .
paths:
- ./packages
- ./dist
- run:
name: Zip build directory
command: |
tar cjf pyodide-build.tar.gz dist
tar cjf build-logs.tar.gz packages/build-logs
- persist_to_workspace:
root: .
paths:
- .
- store_artifacts:
path: /root/repo/dist/
- store_artifacts:
path: /root/repo/pyodide-build.tar.gz
- store_artifacts:
path: /root/repo/packages/build-logs
- store_artifacts:
path: /root/repo/build-logs.tar.gz
build-packages:
parameters:
packages:
description: The packages to be built.
type: string
<<: *defaults
resource_class: large
steps:
- checkout
@ -196,7 +131,7 @@ jobs:
- run:
name: build packages
no_output_timeout: 30m
no_output_timeout: 60m
command: |
source pyodide_env.sh
@ -204,7 +139,7 @@ jobs:
touch -m -d '1 Jan 2021 12:00' emsdk/emsdk/.emscripten
ccache -z
PYODIDE_PACKAGES='*' make -C packages
PYODIDE_PACKAGES='<< parameters.packages >>' make -C packages
ccache -s
environment:
PYODIDE_JOBS: 5
@ -221,24 +156,12 @@ jobs:
- run:
name: Zip build directory
command: |
tar cjf pyodide-build.tar.gz dist
tar --exclude="node_modules" -cjf pyodide-build.tar.gz dist
tar cjf build-logs.tar.gz packages/build-logs
- persist_to_workspace:
root: .
paths:
- ./packages/.artifacts
- ./dist
- store_artifacts:
path: /root/repo/dist/
- store_artifacts:
path: /root/repo/pyodide-build.tar.gz
- store_artifacts:
path: /root/repo/packages/build-logs
- store_artifacts:
path: /root/repo/build-logs.tar.gz
@ -421,19 +344,68 @@ workflows:
tags:
only: /.*/
- build-packages-no-numpy-dependents:
- build-packages:
name: build-packages-no-numpy-dependents
packages: "*,no-numpy-dependents"
requires:
- build-core
filters:
tags:
only: /.*/
post-steps:
- persist_to_workspace:
root: .
paths:
- ./packages
- ./dist
- build-packages:
name: build-packages-opencv-python
packages: opencv-python
requires:
- build-packages-no-numpy-dependents
filters:
tags:
only: /.*/
post-steps:
- persist_to_workspace:
root: .
paths:
- ./packages/opencv-python/build
- ./packages/opencv-python/dist
- ./packages/build-logs/opencv*
- ./dist/opencv*
- build-packages:
name: build-packages-numpy-dependents
packages: "*,!opencv-python"
requires:
- build-packages-no-numpy-dependents
filters:
tags:
only: /.*/
post-steps:
- persist_to_workspace:
root: .
paths:
- ./packages
- ./dist
- build-packages:
name: build-packages
packages: "*"
requires:
- build-packages-numpy-dependents
- build-packages-opencv-python
filters:
tags:
only: /.*/
post-steps:
- persist_to_workspace:
root: .
paths:
- ./packages/.artifacts
- ./dist
- test-main:
name: test-core-chrome

View File

@ -385,12 +385,16 @@ class NodeWrapper(SeleniumWrapper):
browser = "node"
def init_node(self):
self.p = pexpect.spawn(
f"node --expose-gc --experimental-wasm-bigint ./src/test-js/node_test_driver.js {self.base_url}",
timeout=60,
)
self.p = pexpect.spawn("/bin/bash", timeout=60)
self.p.setecho(False)
self.p.delaybeforesend = None
# disable canonical input processing mode to allow sending longer lines
# See: https://pexpect.readthedocs.io/en/stable/api/pexpect.html#pexpect.spawn.send
self.p.sendline("stty -icanon")
self.p.sendline(
f"node --expose-gc --experimental-wasm-bigint ./src/test-js/node_test_driver.js {self.base_url}",
)
try:
self.p.expect_exact("READY!!")
except pexpect.exceptions.EOF:

View File

@ -26,6 +26,8 @@ substitutions:
`pyodide.runPython(code, { globals : some_dict})`;
{pr}`2391`
- New packages: opencv-python v4.5.5.64 {pr}`2305`, ffmpeg {pr}`2305`, libwebp {pr}`2305`
## Version 0.20.0
[See the release notes for a summary.](https://blog.pyodide.org/posts/0.20-release/)

25
packages/ffmpeg/meta.yaml Normal file
View File

@ -0,0 +1,25 @@
package:
name: ffmpeg
version: "4.4.1"
source:
url: https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n4.4.1.tar.gz
sha256: 82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666
extract_dir: FFmpeg-n4.4.1
build:
library: true
script: |
emconfigure ./configure \
--extra-cflags="-fPIC" \
--disable-x86asm \
--disable-inline-asm \
--disable-doc \
--disable-stripping \
--disable-programs \
--disable-pthreads \
--nm="$PYODIDE_ROOT/emsdk/emsdk/upstream/bin/llvm-nm -g" \
--ar=emar --cc=emcc --cxx=em++ --objcc=emcc --dep-cc=emcc --ranlib=emranlib \
--prefix=./lib
emmake make -j${PYODIDE_JOBS:-3}
emmake make install

View File

@ -0,0 +1,14 @@
package:
name: libwebp
version: 1.2.2
source:
url: https://github.com/webmproject/libwebp/archive/refs/tags/v1.2.2.tar.gz
sha256: 51e9297aadb7d9eb99129fe0050f53a11fcce38a0848fb2b0389e385ad93695e
build:
library: true
script: |
mkdir build && cd build && emcmake cmake -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_INSTALL_PREFIX=./lib ../
emmake make -j ${PYODIDE_JOBS:-3}
emmake make install

View File

@ -0,0 +1,31 @@
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
set(OPENCV_PYTHON_SKIP_LINKER_EXCLUDE_LIBS TRUE)
set(CMAKE_SKIP_COMPATIBILITY_TESTS 1)
set(CMAKE_SIZEOF_CHAR 1)
set(CMAKE_SIZEOF_UNSIGNED_SHORT 2)
set(CMAKE_SIZEOF_SHORT 2)
set(CMAKE_SIZEOF_INT 4)
set(CMAKE_SIZEOF_UNSIGNED_LONG 4)
set(CMAKE_SIZEOF_UNSIGNED_INT 4)
set(CMAKE_SIZEOF_LONG 4)
set(CMAKE_SIZEOF_VOID_P 4)
set(CMAKE_SIZEOF_FLOAT 4)
set(CMAKE_SIZEOF_DOUBLE 8)
set(CMAKE_C_SIZEOF_DATA_PTR 4)
set(CMAKE_CXX_SIZEOF_DATA_PTR 4)
set(CMAKE_HAVE_LIMITS_H 1)
set(CMAKE_HAVE_UNISTD_H 1)
set(CMAKE_HAVE_PTHREAD_H 1)
set(CMAKE_HAVE_SYS_PRCTL_H 1)
set(CMAKE_WORDS_BIGENDIAN 0)
set(CMAKE_DL_LIBS)
set(CMAKE_RANLIB echo)
# Force filesystem support, it is disabled in Emscripten platform (needs fix)
# https://github.com/opencv/opencv/blob/17234f82d025e3bbfbf611089637e5aa2038e7b8/modules/core/include/opencv2/core/utils/filesystem.private.hpp#L10
add_definitions(-DOPENCV_HAVE_FILESYSTEM_SUPPORT=1)
if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "")
set(EMSCRIPTEN_ROOT_PATH "$ENV{EMSCRIPTEN}")
endif()
list(APPEND CMAKE_MODULE_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake/Modules")

View File

@ -0,0 +1,218 @@
# ----------------------------------------------------------------------------
# Detect 3rd-party image IO libraries
# ----------------------------------------------------------------------------
# We want to use emscripten-ported version of ZLIB, LIBJPEG, LIBPNG.
# However, OpenCV tries to find them in system paths.
# Let's deceive OpenCV and pretend we have them.
set(HAVE_JPEG YES)
set(HAVE_PNG YES)
set(ZLIB_FOUND YES)
# --- libtiff (optional, should be searched after zlib and libjpeg) ---
if(WITH_TIFF)
if(BUILD_TIFF)
ocv_clear_vars(TIFF_FOUND)
else()
ocv_clear_internal_cache_vars(TIFF_LIBRARY TIFF_INCLUDE_DIR)
include(FindTIFF)
if(TIFF_FOUND)
ocv_parse_header("${TIFF_INCLUDE_DIR}/tiff.h" TIFF_VERSION_LINES TIFF_VERSION_CLASSIC TIFF_VERSION_BIG TIFF_VERSION TIFF_BIGTIFF_VERSION)
endif()
endif()
if(NOT TIFF_FOUND)
ocv_clear_vars(TIFF_LIBRARY TIFF_LIBRARIES TIFF_INCLUDE_DIR)
set(TIFF_LIBRARY libtiff CACHE INTERNAL "")
set(TIFF_LIBRARIES ${TIFF_LIBRARY})
add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/libtiff")
set(TIFF_INCLUDE_DIR "${${TIFF_LIBRARY}_SOURCE_DIR}" "${${TIFF_LIBRARY}_BINARY_DIR}" CACHE INTERNAL "")
ocv_parse_header("${${TIFF_LIBRARY}_SOURCE_DIR}/tiff.h" TIFF_VERSION_LINES TIFF_VERSION_CLASSIC TIFF_VERSION_BIG TIFF_VERSION TIFF_BIGTIFF_VERSION)
endif()
if(TIFF_VERSION_CLASSIC AND NOT TIFF_VERSION)
set(TIFF_VERSION ${TIFF_VERSION_CLASSIC})
endif()
if(TIFF_BIGTIFF_VERSION AND NOT TIFF_VERSION_BIG)
set(TIFF_VERSION_BIG ${TIFF_BIGTIFF_VERSION})
endif()
if(NOT TIFF_VERSION_STRING AND TIFF_INCLUDE_DIR)
list(GET TIFF_INCLUDE_DIR 0 _TIFF_INCLUDE_DIR)
if(EXISTS "${_TIFF_INCLUDE_DIR}/tiffvers.h")
file(STRINGS "${_TIFF_INCLUDE_DIR}/tiffvers.h" tiff_version_str REGEX "^#define[\t ]+TIFFLIB_VERSION_STR[\t ]+\"LIBTIFF, Version .*")
string(REGEX REPLACE "^#define[\t ]+TIFFLIB_VERSION_STR[\t ]+\"LIBTIFF, Version +([^ \\n]*).*" "\\1" TIFF_VERSION_STRING "${tiff_version_str}")
unset(tiff_version_str)
endif()
unset(_TIFF_INCLUDE_DIR)
endif()
set(HAVE_TIFF YES)
endif()
# --- libwebp (optional) ---
if(WITH_WEBP)
if(BUILD_WEBP)
ocv_clear_vars(WEBP_FOUND WEBP_LIBRARY WEBP_LIBRARIES WEBP_INCLUDE_DIR)
else()
ocv_clear_internal_cache_vars(WEBP_LIBRARY WEBP_INCLUDE_DIR)
include(cmake/OpenCVFindWebP.cmake)
if(WEBP_FOUND)
set(HAVE_WEBP 1)
endif()
endif()
endif()
# --- Add libwebp to 3rdparty/libwebp and compile it if not available ---
if(WITH_WEBP AND NOT WEBP_FOUND
AND (NOT ANDROID OR HAVE_CPUFEATURES)
)
ocv_clear_vars(WEBP_LIBRARY WEBP_INCLUDE_DIR)
set(WEBP_LIBRARY libwebp CACHE INTERNAL "")
set(WEBP_LIBRARIES ${WEBP_LIBRARY})
add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/libwebp")
set(WEBP_INCLUDE_DIR "${${WEBP_LIBRARY}_SOURCE_DIR}/src" CACHE INTERNAL "")
set(HAVE_WEBP 1)
endif()
if(NOT WEBP_VERSION AND WEBP_INCLUDE_DIR)
ocv_clear_vars(ENC_MAJ_VERSION ENC_MIN_VERSION ENC_REV_VERSION)
if(EXISTS "${WEBP_INCLUDE_DIR}/enc/vp8enci.h")
ocv_parse_header("${WEBP_INCLUDE_DIR}/enc/vp8enci.h" WEBP_VERSION_LINES ENC_MAJ_VERSION ENC_MIN_VERSION ENC_REV_VERSION)
set(WEBP_VERSION "${ENC_MAJ_VERSION}.${ENC_MIN_VERSION}.${ENC_REV_VERSION}")
elseif(EXISTS "${WEBP_INCLUDE_DIR}/webp/encode.h")
file(STRINGS "${WEBP_INCLUDE_DIR}/webp/encode.h" WEBP_ENCODER_ABI_VERSION REGEX "#define[ \t]+WEBP_ENCODER_ABI_VERSION[ \t]+([x0-9a-f]+)" )
if(WEBP_ENCODER_ABI_VERSION MATCHES "#define[ \t]+WEBP_ENCODER_ABI_VERSION[ \t]+([x0-9a-f]+)")
set(WEBP_ENCODER_ABI_VERSION "${CMAKE_MATCH_1}")
set(WEBP_VERSION "encoder: ${WEBP_ENCODER_ABI_VERSION}")
else()
unset(WEBP_ENCODER_ABI_VERSION)
endif()
endif()
endif()
# --- libopenjp2 (optional, check before libjasper) ---
if(WITH_OPENJPEG)
if(BUILD_OPENJPEG)
ocv_clear_vars(OpenJPEG_FOUND)
else()
find_package(OpenJPEG QUIET)
endif()
if(NOT OpenJPEG_FOUND OR OPENJPEG_MAJOR_VERSION LESS 2)
ocv_clear_vars(OPENJPEG_MAJOR_VERSION OPENJPEG_MINOR_VERSION OPENJPEG_BUILD_VERSION OPENJPEG_LIBRARIES OPENJPEG_INCLUDE_DIRS)
message(STATUS "Could NOT find OpenJPEG (minimal suitable version: 2.0, "
"recommended version >= 2.3.1). OpenJPEG will be built from sources")
add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/openjpeg")
if(OCV_CAN_BUILD_OPENJPEG)
set(HAVE_OPENJPEG YES)
message(STATUS "OpenJPEG libraries will be built from sources: ${OPENJPEG_LIBRARIES} "
"(version \"${OPENJPEG_VERSION}\")")
else()
set(HAVE_OPENJPEG NO)
message(STATUS "OpenJPEG libraries can't be built from sources. System requirements are not fulfilled.")
endif()
else()
set(HAVE_OPENJPEG YES)
message(STATUS "Found system OpenJPEG: ${OPENJPEG_LIBRARIES} "
"(found version \"${OPENJPEG_VERSION}\")")
endif()
endif()
# --- libjasper (optional, should be searched after libjpeg) ---
if(WITH_JASPER AND NOT HAVE_OPENJPEG)
if(BUILD_JASPER)
ocv_clear_vars(JASPER_FOUND)
else()
include(FindJasper)
endif()
if(NOT JASPER_FOUND)
ocv_clear_vars(JASPER_LIBRARY JASPER_LIBRARIES JASPER_INCLUDE_DIR)
set(JASPER_LIBRARY libjasper CACHE INTERNAL "")
set(JASPER_LIBRARIES ${JASPER_LIBRARY})
add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/libjasper")
set(JASPER_INCLUDE_DIR "${${JASPER_LIBRARY}_SOURCE_DIR}" CACHE INTERNAL "")
endif()
set(HAVE_JASPER YES)
if(NOT JASPER_VERSION_STRING)
ocv_parse_header2(JASPER "${JASPER_INCLUDE_DIR}/jasper/jas_config.h" JAS_VERSION "")
endif()
endif()
# --- OpenEXR (optional) ---
if(WITH_OPENEXR)
ocv_clear_vars(HAVE_OPENEXR)
if(NOT BUILD_OPENEXR)
ocv_clear_internal_cache_vars(OPENEXR_INCLUDE_PATHS OPENEXR_LIBRARIES OPENEXR_ILMIMF_LIBRARY OPENEXR_VERSION)
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindOpenEXR.cmake")
endif()
if(OPENEXR_FOUND)
set(HAVE_OPENEXR YES)
else()
ocv_clear_vars(OPENEXR_INCLUDE_PATHS OPENEXR_LIBRARIES OPENEXR_ILMIMF_LIBRARY OPENEXR_VERSION)
set(OPENEXR_LIBRARIES IlmImf)
add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/openexr")
if(OPENEXR_VERSION) # check via TARGET doesn't work
set(BUILD_OPENEXR ON)
set(HAVE_OPENEXR YES)
set(BUILD_OPENEXR ON)
endif()
endif()
endif()
# --- GDAL (optional) ---
if(WITH_GDAL)
find_package(GDAL QUIET)
if(NOT GDAL_FOUND)
set(HAVE_GDAL NO)
ocv_clear_vars(GDAL_VERSION GDAL_LIBRARIES)
else()
set(HAVE_GDAL YES)
ocv_include_directories(${GDAL_INCLUDE_DIR})
endif()
endif()
if(WITH_GDCM)
find_package(GDCM QUIET)
if(NOT GDCM_FOUND)
set(HAVE_GDCM NO)
ocv_clear_vars(GDCM_VERSION GDCM_LIBRARIES)
else()
set(HAVE_GDCM YES)
# include(${GDCM_USE_FILE})
set(GDCM_LIBRARIES gdcmMSFF) # GDCM does not set this variable for some reason
endif()
endif()
if(WITH_IMGCODEC_HDR)
set(HAVE_IMGCODEC_HDR ON)
elseif(DEFINED WITH_IMGCODEC_HDR)
set(HAVE_IMGCODEC_HDR OFF)
endif()
if(WITH_IMGCODEC_SUNRASTER)
set(HAVE_IMGCODEC_SUNRASTER ON)
elseif(DEFINED WITH_IMGCODEC_SUNRASTER)
set(HAVE_IMGCODEC_SUNRASTER OFF)
endif()
if(WITH_IMGCODEC_PXM)
set(HAVE_IMGCODEC_PXM ON)
elseif(DEFINED WITH_IMGCODEC_PXM)
set(HAVE_IMGCODEC_PXM OFF)
endif()
if(WITH_IMGCODEC_PFM)
set(HAVE_IMGCODEC_PFM ON)
elseif(DEFINED WITH_IMGCODEC_PFM)
set(HAVE_IMGCODEC_PFM OFF)
endif()

View File

@ -0,0 +1,90 @@
#!/bin/bash
export CMAKE_ARGS=" \
-DCMAKE_TOOLCHAIN_FILE=$PYODIDE_ROOT/packages/opencv-python/cmake/Config.cmake \
-DPYTHON3_INCLUDE_PATH=$PYTHONINCLUDE \
-DPYTHON3_LIBRARY=$PYTHONINCLUDE/../libpython$PYMAJOR.$PYMINOR.a \
-DPYTHON3_VERSION_MAJOR=$PYMAJOR \
-DPYTHON3_VERSION_MINOR=$PYMINOR \
-DPYTHON3_NUMPY_INCLUDE_DIRS=$NUMPY_INCLUDE_DIR \
\
-DWITH_ADE=ON \
-DWITH_JPEG=ON \
-DWITH_PNG=ON \
-DWITH_WEBP=ON \
-DBUILD_WEBP=OFF \
-DWEBP_INCLUDE_DIR=$LIBWEBP_ROOT/include \
-DWEBP_LIBRARY=$LIBWEBP_ROOT/lib/libwebp.a \
\
-DBUILD_opencv_python3=ON \
-DBUILD_opencv_world=ON \
-DBUILD_opencv_imgcodecs=ON \
-DBUILD_opencv_videoio=ON \
-DBUILD_opencv_gapi=ON \
-DBUILD_opencv_photo=ON \
-DBUILD_opencv_stitching=ON \
-DBUILD_opencv_highgui=ON \
-DBUILD_opencv_features2d=ON \
-DBUILD_opencv_flann=ON \
-DBUILD_opencv_calib3d=ON \
-DBUILD_opencv_dnn=ON \
-DBUILD_opencv_ml=ON \
-DBUILD_opencv_objdetect=ON \
-DWITH_OPENCL=OFF \
-DOPENCV_DNN_OPENCL=OFF \
-DWITH_PROTOBUF=ON \
-DWITH_FFMPEG=ON \
\
-DPYTHON3_EXECUTABLE=python \
-DPYTHON3_LIMITED_API=ON \
-DPYTHON_DEFAULT_EXECUTABLE=python \
-DENABLE_PIC=FALSE \
-DCMAKE_BUILD_TYPE=Release \
-DCPU_BASELINE='' \
-DCPU_DISPATCH='' \
-DCV_TRACE=OFF \
-DBUILD_SHARED_LIBS=OFF \
-DWITH_1394=OFF \
-DWITH_VTK=OFF \
-DWITH_EIGEN=OFF \
-DWITH_GSTREAMER=OFF \
-DWITH_GTK=OFF \
-DWITH_GTK_2_X=OFF \
-DWITH_QT=OFF \
-DWITH_IPP=OFF \
-DWITH_JASPER=OFF \
-DWITH_OPENJPEG=OFF \
-DWITH_OPENEXR=OFF \
-DWITH_OPENGL=OFF \
-DWITH_OPENVX=OFF \
-DWITH_OPENNI=OFF \
-DWITH_OPENNI2=OFF \
-DWITH_TBB=OFF \
-DWITH_TIFF=OFF \
-DWITH_V4L=OFF \
-DWITH_OPENCL_SVM=OFF \
-DWITH_OPENCLAMDFFT=OFF \
-DWITH_OPENCLAMDBLAS=OFF \
-DWITH_GPHOTO2=OFF \
-DWITH_LAPACK=OFF \
-DWITH_ITT=OFF \
-DWITH_QUIRC=OFF \
-DBUILD_ZLIB=OFF \
-DBUILD_opencv_apps=OFF \
-DBUILD_opencv_shape=OFF \
-DBUILD_opencv_videostab=OFF \
-DBUILD_opencv_superres=OFF \
-DBUILD_opencv_java=OFF \
-DBUILD_opencv_js=OFF \
-DBUILD_opencv_python2=OFF \
-DBUILD_EXAMPLES=OFF \
-DBUILD_PACKAGE=OFF \
-DBUILD_TESTS=OFF \
-DBUILD_PERF_TESTS=OFF \
-DBUILD_DOCS=OFF \
-DWITH_PTHREADS_PF=OFF \
-DCV_ENABLE_INTRINSICS=OFF \
-DBUILD_WASM_INTRIN_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=../cmake-install \
-DCMAKE_VERBOSE_MAKEFILE=ON \
"

View File

@ -0,0 +1,49 @@
# --- FFMPEG ---
set(HAVE_FFMPEG TRUE)
set(FFMPEG_FOUND TRUE)
set(FFMPEG_ROOT_PATH "$ENV{FFMPEG_ROOT}")
set(FFMPEG_INCLUDE_DIRS "${FFMPEG_ROOT_PATH}/include")
set(FFMPEG_LIBRARIES
"${FFMPEG_ROOT_PATH}/lib/libavcodec.a"
"${FFMPEG_ROOT_PATH}/lib/libavformat.a"
"${FFMPEG_ROOT_PATH}/lib/libavutil.a"
"${FFMPEG_ROOT_PATH}/lib/libswscale.a"
"${FFMPEG_ROOT_PATH}/lib/libswresample.a"
)
ocv_add_external_target(ffmpeg "${FFMPEG_INCLUDE_DIRS}" "${FFMPEG_LIBRARIES}" "HAVE_FFMPEG")
set(__builtin_defines "")
set(__builtin_include_dirs "")
set(__builtin_libs "")
set(__plugin_defines "")
set(__plugin_include_dirs "")
set(__plugin_libs "")
if(HAVE_OPENCL)
set(__opencl_dirs "")
if(OPENCL_INCLUDE_DIRS)
set(__opencl_dirs "${OPENCL_INCLUDE_DIRS}")
elseif(OPENCL_INCLUDE_DIR)
set(__opencl_dirs "${OPENCL_INCLUDE_DIR}")
else()
set(__opencl_dirs "${OpenCV_SOURCE_DIR}/3rdparty/include/opencl/1.2")
endif()
# extra dependencies for buildin code (OpenCL dir is required for extensions like cl_d3d11.h)
# buildin HAVE_OPENCL is already defined through cvconfig.h
list(APPEND __builtin_include_dirs "${__opencl_dirs}")
# extra dependencies for
list(APPEND __plugin_defines "HAVE_OPENCL")
list(APPEND __plugin_include_dirs "${__opencl_dirs}")
endif()
# TODO: libva, d3d11
if(__builtin_include_dirs OR __builtin_include_defines OR __builtin_include_libs)
ocv_add_external_target(ffmpeg.builtin_deps "${__builtin_include_dirs}" "${__builtin_include_libs}" "${__builtin_defines}")
endif()
if(VIDEOIO_ENABLE_PLUGINS AND __plugin_include_dirs OR __plugin_include_defines OR __plugin_include_libs)
ocv_add_external_target(ffmpeg.plugin_deps "${__plugin_include_dirs}" "${__plugin_include_libs}" "${__plugin_defines}")
endif()

View File

@ -0,0 +1,65 @@
package:
name: opencv-python
version: 4.5.5.64
about:
home: https://github.com/skvark/opencv-python
PyPI: https://pypi.org/project/opencv-python
summary: Wrapper package for OpenCV python bindings.
license: MIT
source:
url: https://files.pythonhosted.org/packages/3c/61/ee4496192ed27f657532fdf0d814b05b9787e7fc5122ed3ca57282bae69c/opencv-python-4.5.5.64.tar.gz
sha256: f65de0446a330c3b773cd04ba10345d8ce1b15dcac3f49770204e37602d0b3f7
extras:
- [cmake/OpenCVFindLibsGrfmt.cmake, opencv/cmake/OpenCVFindLibsGrfmt.cmake]
- [
cmake/detect_ffmpeg.cmake,
opencv/modules/videoio/cmake/detect_ffmpeg.cmake,
]
patches:
- patches/0001-Enable-file-system.patch
requirements:
run:
- numpy
- ffmpeg
- libwebp
build:
cxxflags: |
-fPIC
-s USE_ZLIB=1
-s USE_LIBJPEG=1
-s USE_LIBPNG=1
-s SIDE_MODULE=1
ldflags: |
-ljpeg
-lz
-lpng
# Note on CMAKE_ARGS:
# CMake args are adopted from OpenCV.js (https://github.com/opencv/opencv/blob/4.x/platforms/js/build_js.py)
# But we support more of modules than OpenCV.js.
#
# Note on CMAKE_TOOLCHAIN_FILE:
# We don't want to use toolchain file provided by Emscripten,
# because our build script hijack gcc, c++, ... and replace it with emcc, em++, ..., instead of calling them directly.
#
# List of OpenCV modules can be found at: https://docs.opencv.org/4.x/
# Build configs can be found at: https://docs.opencv.org/4.x/db/d05/tutorial_config_reference.html
script: |
pip install scikit-build
# TODO: remove this line after version update (https://github.com/opencv/opencv-python/issues/648)
sed -i "s/cmake_install_dir=cmake_install_reldir/_cmake_install_dir=cmake_install_reldir/" setup.py
# export VERBOSE=1
export NUMPY_INCLUDE_DIR="$HOSTINSTALLDIR/lib/python$PYMAJOR.$PYMINOR/site-packages/numpy/core/include/"
export EMSCRIPTEN="$PYODIDE_ROOT/emsdk/emsdk/upstream/emscripten/"
export FFMPEG_ROOT="$PYODIDE_ROOT/packages/ffmpeg/build/ffmpeg-4.4.1/lib"
export LIBWEBP_ROOT="$PYODIDE_ROOT/packages/libwebp/build/libwebp-1.2.2/build/lib"
source $PYODIDE_ROOT/packages/opencv-python/cmake/build_args.sh
test:
imports:
- cv2

View File

@ -0,0 +1,75 @@
From c7e9f892204ce1e47774fe21790195e2cbd7f2b3 Mon Sep 17 00:00:00 2001
From: ryanking13 <def6488@gmail.com>
Date: Tue, 29 Mar 2022 01:58:40 +0000
Subject: [PATCH] Enable file system
---
.../include/opencv2/core/utils/plugin_loader.private.hpp | 8 ++++----
modules/core/src/utils/filesystem.cpp | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/modules/core/include/opencv2/core/utils/plugin_loader.private.hpp b/modules/core/include/opencv2/core/utils/plugin_loader.private.hpp
index d6390fc74a..c089309443 100644
--- a/opencv/modules/core/include/opencv2/core/utils/plugin_loader.private.hpp
+++ b/opencv/modules/core/include/opencv2/core/utils/plugin_loader.private.hpp
@@ -12,7 +12,7 @@
#if defined(_WIN32)
#include <windows.h>
-#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) || defined(__EMSCRIPTEN__)
#include <dlfcn.h>
#endif
@@ -65,7 +65,7 @@ void* getSymbol_(LibHandle_t h, const char* symbolName)
{
#if defined(_WIN32)
return (void*)GetProcAddress(h, symbolName);
-#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) || defined(__EMSCRIPTEN__)
return dlsym(h, symbolName);
#endif
}
@@ -79,7 +79,7 @@ LibHandle_t libraryLoad_(const FileSystemPath_t& filename)
# else
return LoadLibraryW(filename.c_str());
#endif
-#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) || defined(__EMSCRIPTEN__)
void* handle = dlopen(filename.c_str(), RTLD_NOW);
CV_LOG_IF_DEBUG(NULL, !handle, "dlopen() error: " << dlerror());
return handle;
@@ -91,7 +91,7 @@ void libraryRelease_(LibHandle_t h)
{
#if defined(_WIN32)
FreeLibrary(h);
-#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__) || defined(__EMSCRIPTEN__)
dlclose(h);
#endif
}
diff --git a/modules/core/src/utils/filesystem.cpp b/modules/core/src/utils/filesystem.cpp
index 663ec311e4..3ef4408d2d 100644
--- a/opencv/modules/core/src/utils/filesystem.cpp
+++ b/opencv/modules/core/src/utils/filesystem.cpp
@@ -34,7 +34,7 @@
#include <errno.h>
#include <io.h>
#include <stdio.h>
-#elif defined __linux__ || defined __APPLE__ || defined __HAIKU__ || defined __FreeBSD__
+#elif defined __linux__ || defined __APPLE__ || defined __HAIKU__ || defined __FreeBSD__ || defined __EMSCRIPTEN__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -343,7 +343,7 @@ private:
Impl& operator=(const Impl&); // disabled
};
-#elif defined __linux__ || defined __APPLE__ || defined __HAIKU__ || defined __FreeBSD__
+#elif defined __linux__ || defined __APPLE__ || defined __HAIKU__ || defined __FreeBSD__ || defined __EMSCRIPTEN__
struct FileLock::Impl
{
--
2.35.1

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

View File

@ -0,0 +1,551 @@
import base64
import pathlib
from pyodide_build.testing import run_in_pyodide
REFERENCE_IMAGES_PATH = pathlib.Path(__file__).parent / "reference-images"
def compare_with_reference_image(selenium, reference_image, var="img", grayscale=True):
reference_image_encoded = base64.b64encode(reference_image.read_bytes())
grayscale = "cv.IMREAD_GRAYSCALE" if grayscale else "cv.IMREAD_COLOR"
match_ratio = selenium.run(
f"""
import base64
import numpy as np
import cv2 as cv
DIFF_THRESHOLD = 2
arr = np.frombuffer(base64.b64decode({reference_image_encoded!r}), np.uint8)
ref_data = cv.imdecode(arr, {grayscale})
pixels_match = np.count_nonzero(np.abs({var}.astype(np.int16) - ref_data.astype(np.int16)) <= DIFF_THRESHOLD)
pixels_total = ref_data.size
float(pixels_match / pixels_total)
"""
)
# Due to some randomness in the result, we allow a small difference
return match_ratio > 0.95
def test_import(selenium):
selenium.set_script_timeout(60)
selenium.load_package("opencv-python")
selenium.run(
"""
import cv2
cv2.__version__
"""
)
@run_in_pyodide(packages=["opencv-python", "numpy"])
def test_image_extensions():
import cv2 as cv
import numpy as np
shape = (16, 16, 3)
img = np.zeros(shape, np.uint8)
extensions = {
"bmp": b"BM6\x03",
"jpg": b"\xff\xd8\xff\xe0",
"jpeg": b"\xff\xd8\xff\xe0",
"png": b"\x89PNG",
"webp": b"RIFF",
}
for ext, signature in extensions.items():
result, buf = cv.imencode(f".{ext}", img)
assert result
assert bytes(buf[:4]) == signature
@run_in_pyodide(packages=["opencv-python", "numpy"])
def test_io():
import cv2 as cv
import numpy as np
shape = (16, 16, 3)
img = np.zeros(shape, np.uint8)
filename = "test.bmp"
cv.imwrite(filename, img)
img_ = cv.imread(filename)
assert img_.shape == img.shape
@run_in_pyodide(packages=["opencv-python", "numpy"])
def test_drawing():
import cv2 as cv
import numpy as np
width = 100
height = 100
shape = (width, height, 3)
img = np.zeros(shape, np.uint8)
cv.line(img, (0, 0), (width - 1, 0), (255, 0, 0), 5)
cv.line(img, (0, 0), (0, height - 1), (0, 0, 255), 5)
cv.rectangle(img, (0, 0), (width // 2, height // 2), (0, 255, 0), 2)
cv.circle(img, (0, 0), radius=width // 2, color=(255, 0, 0))
cv.putText(img, "Hello Pyodide", (0, 0), cv.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
@run_in_pyodide(packages=["opencv-python", "numpy"])
def test_pixel_access():
import cv2 as cv
import numpy as np
shape = (16, 16, 3)
img = np.zeros(shape, np.uint8)
img[5, 5] = [1, 2, 3]
assert list(img[5, 5]) == [1, 2, 3]
b, g, r = cv.split(img)
img_ = cv.merge([b, g, r])
assert (img == img_).all()
@run_in_pyodide(packages=["opencv-python", "numpy"])
def test_image_processing():
import cv2 as cv
import numpy as np
# Masking
img = np.random.randint(0, 255, size=500)
lower = np.array([0])
upper = np.array([200])
mask = cv.inRange(img, lower, upper)
res = cv.bitwise_and(img, img, mask=mask)
assert not (res > 200).any()
def test_edge_detection(selenium):
original_img = base64.b64encode((REFERENCE_IMAGES_PATH / "baboon.png").read_bytes())
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
src = np.frombuffer(base64.b64decode({original_img!r}), np.uint8)
src = cv.imdecode(src, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
sobel = cv.Sobel(gray, cv.CV_8U, 1, 0, 3)
laplacian = cv.Laplacian(gray, cv.CV_8U, ksize=3)
canny = cv.Canny(src, 100, 255)
None
"""
)
assert compare_with_reference_image(
selenium, REFERENCE_IMAGES_PATH / "baboon_sobel.png", "sobel"
)
assert compare_with_reference_image(
selenium, REFERENCE_IMAGES_PATH / "baboon_laplacian.png", "laplacian"
)
assert compare_with_reference_image(
selenium, REFERENCE_IMAGES_PATH / "baboon_canny.png", "canny"
)
def test_photo_decolor(selenium):
original_img = base64.b64encode((REFERENCE_IMAGES_PATH / "baboon.png").read_bytes())
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
src = np.frombuffer(base64.b64decode({original_img!r}), np.uint8)
src = cv.imdecode(src, cv.IMREAD_COLOR)
grayscale, color_boost = cv.decolor(src)
None
"""
)
assert compare_with_reference_image(
selenium, REFERENCE_IMAGES_PATH / "baboon_decolor_grayscale.png", "grayscale"
)
assert compare_with_reference_image(
selenium,
REFERENCE_IMAGES_PATH / "baboon_decolor_color_boost.png",
"color_boost",
grayscale=False,
)
def test_stitch(selenium):
original_img_left = base64.b64encode(
(REFERENCE_IMAGES_PATH / "mountain1.png").read_bytes()
)
original_img_right = base64.b64encode(
(REFERENCE_IMAGES_PATH / "mountain2.png").read_bytes()
)
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
left = np.frombuffer(base64.b64decode({original_img_left!r}), np.uint8)
left = cv.imdecode(left, cv.IMREAD_COLOR)
right = np.frombuffer(base64.b64decode({original_img_right!r}), np.uint8)
right = cv.imdecode(right, cv.IMREAD_COLOR)
stitcher = cv.Stitcher.create(cv.Stitcher_PANORAMA)
status, panorama = stitcher.stitch([left, right])
# It seems that the result is not always the same due to the randomness, so check the status and size instead
assert status == cv.Stitcher_OK
assert panorama.shape[0] >= max(left.shape[0], right.shape[0])
assert panorama.shape[1] >= max(left.shape[1], right.shape[1])
"""
)
def test_video_optical_flow(selenium):
original_img = base64.b64encode(
(REFERENCE_IMAGES_PATH / "traffic.mp4").read_bytes()
)
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
src = base64.b64decode({original_img!r})
video_path = "video.mp4"
with open(video_path, "wb") as f:
f.write(src)
cap = cv.VideoCapture(video_path)
assert cap.isOpened()
# params for ShiTomasi corner detection
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
# Parameters for lucas kanade optical flow
lk_params = dict( winSize = (15, 15),
maxLevel = 2,
criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
# Take first frame and find corners in it
ret, old_frame = cap.read()
assert ret
old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY)
p0 = cv.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# Create a mask image for drawing purposes
mask = np.zeros_like(old_frame)
while(1):
ret, frame = cap.read()
if not ret:
break
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# calculate optical flow
p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# Select good points
if p1 is not None:
good_new = p1[st==1]
good_old = p0[st==1]
# draw the tracks
for i, (new, old) in enumerate(zip(good_new, good_old)):
a, b = new.ravel()
c, d = old.ravel()
mask = cv.line(mask, (int(a), int(b)), (int(c), int(d)), [0, 0, 255], 2)
frame = cv.circle(frame, (int(a), int(b)), 5, [255, 0, 0], -1)
img = cv.add(frame, mask)
# Now update the previous frame and previous points
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)
optical_flow = img
None
"""
)
assert compare_with_reference_image(
selenium,
REFERENCE_IMAGES_PATH / "traffic_optical_flow.png",
"optical_flow",
grayscale=False,
)
def test_flann_sift(selenium):
original_img_src1 = base64.b64encode(
(REFERENCE_IMAGES_PATH / "box.png").read_bytes()
)
original_img_src2 = base64.b64encode(
(REFERENCE_IMAGES_PATH / "box_in_scene.png").read_bytes()
)
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
src1 = np.frombuffer(base64.b64decode({original_img_src1!r}), np.uint8)
src1 = cv.imdecode(src1, cv.IMREAD_GRAYSCALE)
src2 = np.frombuffer(base64.b64decode({original_img_src2!r}), np.uint8)
src2 = cv.imdecode(src2, cv.IMREAD_GRAYSCALE)
#-- Step 1: Detect the keypoints using SIFT Detector, compute the descriptors
detector = cv.SIFT_create()
keypoints1, descriptors1 = detector.detectAndCompute(src1, None)
keypoints2, descriptors2 = detector.detectAndCompute(src2, None)
#-- Step 2: Matching descriptor vectors with a FLANN based matcher
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)
knn_matches = matcher.knnMatch(descriptors1, descriptors2, 2)
#-- Filter matches using the Lowe's ratio test
ratio_thresh = 0.3
good_matches = []
for m,n in knn_matches:
if m.distance < ratio_thresh * n.distance:
good_matches.append(m)
#-- Draw matches
matches = np.empty((max(src1.shape[0], src2.shape[0]), src1.shape[1]+src2.shape[1], 3), dtype=np.uint8)
cv.drawMatches(src1, keypoints1, src2, keypoints2, good_matches, matches, matchColor=[255, 0, 0], flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
sift_result = cv.cvtColor(matches, cv.COLOR_BGR2GRAY)
None
"""
)
assert compare_with_reference_image(
selenium,
REFERENCE_IMAGES_PATH / "box_sift.png",
"sift_result",
grayscale=True,
)
def test_dnn_mnist(selenium):
"""
Run tiny MNIST classification ONNX model
Training script: https://github.com/ryanking13/torch-opencv-mnist
"""
original_img = base64.b64encode(
(REFERENCE_IMAGES_PATH / "mnist_2.png").read_bytes()
)
tf_model = base64.b64encode((REFERENCE_IMAGES_PATH / "mnist.onnx").read_bytes())
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
model_weights = base64.b64decode({tf_model!r})
model_weights_path = './mnist.onnx'
with open(model_weights_path, 'wb') as f:
f.write(model_weights)
src = np.frombuffer(base64.b64decode({original_img!r}), np.uint8)
src = cv.imdecode(src, cv.IMREAD_GRAYSCALE)
net = cv.dnn.readNet(model_weights_path)
blob = cv.dnn.blobFromImage(src, 1.0, (28, 28), (0, 0, 0), False, False)
net.setInput(blob)
prob = net.forward()
assert "output_0" in net.getLayerNames()
assert np.argmax(prob) == 2
"""
)
def test_ml_pca(selenium):
original_img = base64.b64encode((REFERENCE_IMAGES_PATH / "pca.png").read_bytes())
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
from math import atan2, cos, sin, sqrt, pi
def drawAxis(img, p_, q_, colour, scale):
p = list(p_)
q = list(q_)
angle = atan2(p[1] - q[1], p[0] - q[0]) # angle in radians
hypotenuse = sqrt((p[1] - q[1]) * (p[1] - q[1]) + (p[0] - q[0]) * (p[0] - q[0]))
# Here we lengthen the arrow by a factor of scale
q[0] = p[0] - scale * hypotenuse * cos(angle)
q[1] = p[1] - scale * hypotenuse * sin(angle)
cv.line(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)
# create the arrow hooks
p[0] = q[0] + 9 * cos(angle + pi / 4)
p[1] = q[1] + 9 * sin(angle + pi / 4)
cv.line(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)
p[0] = q[0] + 9 * cos(angle - pi / 4)
p[1] = q[1] + 9 * sin(angle - pi / 4)
cv.line(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)
def getOrientation(pts, img):
sz = len(pts)
data_pts = np.empty((sz, 2), dtype=np.float64)
for i in range(data_pts.shape[0]):
data_pts[i,0] = pts[i,0,0]
data_pts[i,1] = pts[i,0,1]
# Perform PCA analysis
mean = np.empty((0))
mean, eigenvectors, eigenvalues = cv.PCACompute2(data_pts, mean)
# Store the center of the object
cntr = (int(mean[0,0]), int(mean[0,1]))
cv.circle(img, cntr, 3, (255, 0, 255), 2)
p1 = (cntr[0] + 0.02 * eigenvectors[0,0] * eigenvalues[0,0], cntr[1] + 0.02 * eigenvectors[0,1] * eigenvalues[0,0])
p2 = (cntr[0] - 0.02 * eigenvectors[1,0] * eigenvalues[1,0], cntr[1] - 0.02 * eigenvectors[1,1] * eigenvalues[1,0])
drawAxis(img, cntr, p1, (0, 255, 0), 1)
drawAxis(img, cntr, p2, (255, 255, 0), 5)
angle = atan2(eigenvectors[0,1], eigenvectors[0,0]) # orientation in radians
return angle
src = np.frombuffer(base64.b64decode({original_img!r}), np.uint8)
src = cv.imdecode(src, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Convert image to binary
_, bw = cv.threshold(gray, 50, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
contours, _ = cv.findContours(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
for i, c in enumerate(contours):
# Calculate the area of each contour
area = cv.contourArea(c)
# Ignore contours that are too small or too large
if area < 1e2 or 1e5 < area:
continue
# Draw each contour only for visualisation purposes
cv.drawContours(src, contours, i, (0, 0, 255), 2)
# Find the orientation of each shape
getOrientation(c, src)
pca_result = src
None
"""
)
assert compare_with_reference_image(
selenium,
REFERENCE_IMAGES_PATH / "pca_result.png",
"pca_result",
grayscale=False,
)
def test_objdetect_face(selenium):
original_img = base64.b64encode(
(REFERENCE_IMAGES_PATH / "monalisa.png").read_bytes()
)
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
from pathlib import Path
src = np.frombuffer(base64.b64decode({original_img!r}), np.uint8)
src = cv.imdecode(src, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
gray = cv.equalizeHist(gray)
face_cascade = cv.CascadeClassifier()
eyes_cascade = cv.CascadeClassifier()
data_path = Path(cv.data.haarcascades)
face_cascade.load(str(data_path / "haarcascade_frontalface_alt.xml"))
eyes_cascade.load(str(data_path / "haarcascade_eye_tree_eyeglasses.xml"))
faces = face_cascade.detectMultiScale(gray)
face_detected = src.copy()
for (x,y,w,h) in faces:
center = (x + w//2, y + h//2)
face_detected = cv.ellipse(face_detected, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4)
faceROI = gray[y:y+h,x:x+w]
eyes = eyes_cascade.detectMultiScale(faceROI)
for (x2,y2,w2,h2) in eyes:
eye_center = (x + x2 + w2//2, y + y2 + h2//2)
radius = int(round((w2 + h2)*0.25))
face_detected = cv.circle(face_detected, eye_center, radius, (255, 0, 0 ), 4)
None
"""
)
assert compare_with_reference_image(
selenium,
REFERENCE_IMAGES_PATH / "monalisa_facedetect.png",
"face_detected",
grayscale=False,
)
def test_feature2d_kaze(selenium):
original_img = base64.b64encode((REFERENCE_IMAGES_PATH / "baboon.png").read_bytes())
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
src = np.frombuffer(base64.b64decode({original_img!r}), np.uint8)
src = cv.imdecode(src, cv.IMREAD_COLOR)
detector = cv.KAZE_create()
keypoints = detector.detect(src)
kaze = cv.drawKeypoints(src, keypoints, None, color=(0, 0, 255), flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
None
"""
)
assert compare_with_reference_image(
selenium,
REFERENCE_IMAGES_PATH / "baboon_kaze.png",
"kaze",
grayscale=False,
)
def test_calib3d_chessboard(selenium):
original_img = base64.b64encode(
(REFERENCE_IMAGES_PATH / "chessboard.png").read_bytes()
)
selenium.load_package("opencv-python")
selenium.run(
f"""
import base64
import cv2 as cv
import numpy as np
src = np.frombuffer(base64.b64decode({original_img!r}), np.uint8)
src = cv.imdecode(src, cv.IMREAD_COLOR)
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, corners = cv.findChessboardCorners(gray, (9, 6), None)
cv.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
cv.drawChessboardCorners(gray, (9, 6), corners, ret)
chessboard_corners = gray
None
"""
)
assert compare_with_reference_image(
selenium,
REFERENCE_IMAGES_PATH / "chessboard_corners.png",
"chessboard_corners",
)

View File

@ -206,13 +206,18 @@ def generate_dependency_graph(
if "*" in packages:
packages.discard("*")
packages.update(
str(x) for x in packages_dir.iterdir() if (x / "meta.yaml").is_file()
str(x.name) for x in packages_dir.iterdir() if (x / "meta.yaml").is_file()
)
no_numpy_dependents = "no-numpy-dependents" in packages
if no_numpy_dependents:
packages.discard("no-numpy-dependents")
packages_exclude = list(filter(lambda pkg: pkg.startswith("!"), packages))
for pkg_exclude in packages_exclude:
packages.discard(pkg_exclude)
packages.discard(pkg_exclude[1:])
while packages:
pkgname = packages.pop()

View File

@ -494,6 +494,7 @@ def handle_command_generate_args(
if result:
new_args.append(result)
return new_args
@ -527,6 +528,19 @@ def handle_command(
if args.pkgname == "scipy":
scipy_fixes(new_args)
# FIXME: For some unknown reason,
# opencv-python tries to link a same library (libopencv_world.a) multiple times,
# which leads to 'duplicated symbols' error.
if args.pkgname == "opencv-python":
duplicated_lib = "libopencv_world.a"
_new_args = []
for arg in new_args:
if duplicated_lib in arg and arg in _new_args:
continue
_new_args.append(arg)
new_args = _new_args
returncode = subprocess.run(new_args).returncode
if returncode != 0:
sys.exit(returncode)