Skip to content

Rework opencv's recipe (enable cv2.so and the extra opencv libraries) #1661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ci/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class TargetPython(Enum):
'x3dh',
'pynacl',
'doubleratchet',
# The opencv recipe fails to pass travis tests due to the long processing
# when building it and the lack of console output, so, it's only broken
# for travis, see: https://github.com/kivy/python-for-android/pull/1661
'opencv',
'omemo',
# requires `libpq-dev` system dependency e.g. for `pg_config` binary
'psycopg2',
Expand Down Expand Up @@ -74,6 +78,10 @@ class TargetPython(Enum):
'icu',
# https://github.com/kivy/python-for-android/issues/1354
'kivent_core', 'kivent_cymunk', 'kivent_particles', 'kivent_polygen',
# The opencv recipe fails to pass travis tests due to the long processing
# when building it and the lack of console output, so, it's only broken
# for travis, see: https://github.com/kivy/python-for-android/pull/1661
'opencv',
# requires `libpq-dev` system dependency e.g. for `pg_config` binary
'psycopg2',
'netifaces',
Expand Down
118 changes: 101 additions & 17 deletions pythonforandroid/recipes/opencv/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os
from os.path import join
import sh
from pythonforandroid.recipe import NDKRecipe
from pythonforandroid.toolchain import (
Expand All @@ -9,43 +9,127 @@


class OpenCVRecipe(NDKRecipe):
'''
.. versionchanged:: 0.7.1
rewrote recipe to support the python bindings (cv2.so) and enable the
build of most of the libraries of the opencv's package, so we can
process images, videos, objects, photos...
'''
version = '4.0.1'
url = 'https://github.com/opencv/opencv/archive/{version}.zip'
depends = ['numpy']
patches = ['patches/p4a_build.patch']
generated_libraries = [
'libopencv_features2d.so',
'libopencv_imgproc.so',
'libopencv_stitching.so',
'libopencv_calib3d.so',
'libopencv_flann.so',
'libopencv_ml.so',
'libopencv_videoio.so',
'libopencv_core.so',
'libopencv_highgui.so',
'libopencv_objdetect.so',
'libopencv_video.so',
'libopencv_dnn.so',
'libopencv_imgcodecs.so',
'libopencv_photo.so'
]

def get_lib_dir(self, arch):
return join(self.get_build_dir(arch.arch), 'build', 'lib', arch.arch)

def get_recipe_env(self, arch):
env = super(OpenCVRecipe, self).get_recipe_env(arch)
env['ANDROID_NDK'] = self.ctx.ndk_dir
env['ANDROID_SDK'] = self.ctx.sdk_dir
return env

def should_build(self, arch):
return True

def build_arch(self, arch):
build_dir = os.path.join(self.get_build_dir(arch.arch), 'build')
build_dir = join(self.get_build_dir(arch.arch), 'build')
shprint(sh.mkdir, '-p', build_dir)
with current_directory(build_dir):
env = self.get_recipe_env(arch)

python_major = self.ctx.python_recipe.version[0]
python_include_root = self.ctx.python_recipe.include_root(arch.arch)
python_site_packages = self.ctx.get_site_packages_dir()
python_link_root = self.ctx.python_recipe.link_root(arch.arch)
python_link_version = self.ctx.python_recipe.major_minor_version_string
if 'python3' in self.ctx.python_recipe.name:
python_link_version += 'm'
python_library = join(python_link_root,
'libpython{}.so'.format(python_link_version))
python_include_numpy = join(python_site_packages,
'numpy', 'core', 'include')

shprint(sh.cmake,
'-DP4A=ON',
'-DANDROID_ABI={}'.format(arch.arch),
'-DCMAKE_TOOLCHAIN_FILE={}/build/cmake/android.toolchain.cmake'.format(self.ctx.ndk_dir),
'-DPYTHON_NUMPY_INCLUDE_DIR={}/numpy/core/include'.format(self.ctx.get_site_packages_dir()),
'-DANDROID_STANDALONE_TOOLCHAIN={}'.format(self.ctx.ndk_dir),
'-DANDROID_NATIVE_API_LEVEL={}'.format(self.ctx.ndk_api),
'-DANDROID_EXECUTABLE={}/tools/android'.format(env['ANDROID_SDK']),
'-DBUILD_TESTS=OFF', '-DBUILD_PERF_TESTS=OFF', '-DENABLE_TESTING=OFF',
'-DBUILD_EXAMPLES=OFF', '-DBUILD_ANDROID_EXAMPLES=OFF',
'-DBUILD_opencv_imgproc=OFF', '-DBUILD_opencv_flann=OFF',
'-DBUILD_opencv_python3=ON',

'-DCMAKE_TOOLCHAIN_FILE={}'.format(
join(self.ctx.ndk_dir, 'build', 'cmake',
'android.toolchain.cmake')),
# Make the linkage with our python library, otherwise we
# will get dlopen error when trying to import cv2's module.
'-DCMAKE_SHARED_LINKER_FLAGS=-L{path} -lpython{version}'.format(
path=python_link_root,
version=python_link_version),

'-DBUILD_WITH_STANDALONE_TOOLCHAIN=ON',
'-DPYTHON_PACKAGES_PATH={}'.format(self.ctx.get_site_packages_dir()),
'-DANDROID_STANDALONE_TOOLCHAIN={}'.format(self.ctx.ndk_dir),
'-DANDROID_NATIVE_API_LEVEL={}'.format(self.ctx.android_api),
# Force to build as shared libraries the cv2's dependant
# libs or we will not be able to link with our python
'-DBUILD_SHARED_LIBS=ON',
'-DBUILD_STATIC_LIBS=OFF',

# Disable some opencv's features
'-DBUILD_opencv_java=OFF',
'-DBUILD_opencv_java_bindings_generator=OFF',
# '-DBUILD_opencv_highgui=OFF',
# '-DBUILD_opencv_imgproc=OFF',
# '-DBUILD_opencv_flann=OFF',
'-DBUILD_TESTS=OFF',
'-DBUILD_PERF_TESTS=OFF',
'-DENABLE_TESTING=OFF',
'-DBUILD_EXAMPLES=OFF',
'-DBUILD_ANDROID_EXAMPLES=OFF',

# Force to only build our version of python
'-DBUILD_OPENCV_PYTHON{major}=ON'.format(major=python_major),
'-DBUILD_OPENCV_PYTHON{major}=OFF'.format(
major='2' if python_major == '3' else '3'),

# Force to install the `cv2.so` library directly into
# python's site packages (otherwise the cv2's loader fails
# on finding the cv2.so library)
'-DOPENCV_SKIP_PYTHON_LOADER=ON',
'-DOPENCV_PYTHON{major}_INSTALL_PATH={site_packages}'.format(
major=python_major, site_packages=python_site_packages),

# Define python's paths for: exe, lib, includes, numpy...
'-DPYTHON_DEFAULT_EXECUTABLE={}'.format(self.ctx.hostpython),
'-DPYTHON{major}_EXECUTABLE={host_python}'.format(
major=python_major, host_python=self.ctx.hostpython),
'-DPYTHON{major}_INCLUDE_PATH={include_path}'.format(
major=python_major, include_path=python_include_root),
'-DPYTHON{major}_LIBRARIES={python_lib}'.format(
major=python_major, python_lib=python_library),
'-DPYTHON{major}_NUMPY_INCLUDE_DIRS={numpy_include}'.format(
major=python_major, numpy_include=python_include_numpy),
'-DPYTHON{major}_PACKAGES_PATH={site_packages}'.format(
major=python_major, site_packages=python_site_packages),

self.get_build_dir(arch.arch),
_env=env)
shprint(sh.make, '-j', str(cpu_count()))
shprint(sh.make, '-j' + str(cpu_count()), 'opencv_python' + python_major)
# Install python bindings (cv2.so)
shprint(sh.cmake, '-DCOMPONENT=python', '-P', './cmake_install.cmake')
sh.cp('-a', sh.glob('./lib/{}/lib*.a'.format(arch.arch)), self.ctx.get_libs_dir(arch.arch))
self.ctx.get_libs_dir(arch.arch)
# Copy third party shared libs that we need in our final apk
sh.cp('-a', sh.glob('./lib/{}/lib*.so'.format(arch.arch)),
self.ctx.get_libs_dir(arch.arch))


recipe = OpenCVRecipe()
33 changes: 33 additions & 0 deletions pythonforandroid/recipes/opencv/patches/p4a_build.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
This patch allow that the opencv's build command correctly detects our version
of python, so we can successfully build the python bindings (cv2.so)
--- opencv-4.0.1/cmake/OpenCVDetectPython.cmake.orig 2018-12-22 08:03:30.000000000 +0100
+++ opencv-4.0.1/cmake/OpenCVDetectPython.cmake 2019-01-31 11:33:10.896502978 +0100
@@ -175,7 +175,7 @@ if(NOT ${found})
endif()
endif()

- if(NOT ANDROID AND NOT IOS)
+ if(P4A OR NOT ANDROID AND NOT IOS)
if(CMAKE_HOST_UNIX)
execute_process(COMMAND ${_executable} -c "from distutils.sysconfig import *; print(get_python_lib())"
RESULT_VARIABLE _cvpy_process
@@ -244,7 +244,7 @@ if(NOT ${found})
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
endif()
- endif(NOT ANDROID AND NOT IOS)
+ endif(P4A OR NOT ANDROID AND NOT IOS)
endif()

# Export return values
--- opencv-4.0.1/modules/python/CMakeLists.txt.orig 2018-12-22 08:03:30.000000000 +0100
+++ opencv-4.0.1/modules/python/CMakeLists.txt 2019-01-31 11:47:17.100494908 +0100
@@ -3,7 +3,7 @@
# ----------------------------------------------------------------------------
if(DEFINED OPENCV_INITIAL_PASS) # OpenCV build

-if(ANDROID OR APPLE_FRAMEWORK OR WINRT)
+if(ANDROID AND NOT P4A OR APPLE_FRAMEWORK OR WINRT)
ocv_module_disable_(python2)
ocv_module_disable_(python3)
return()