Skip to content

Commit 30fc604

Browse files
committed
Rework opencv's recipe (enable cv2.so and the extra opencv libraries)
We enable the build of the cv2.so library to be able to interact with opencv from python and also we enable the build of most of the opencv's libraries or we will not be able to perform operation with videos, photos, images and others.
1 parent fe58ae1 commit 30fc604

File tree

2 files changed

+132
-17
lines changed

2 files changed

+132
-17
lines changed
Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import os
1+
from os.path import join
22
import sh
33
from pythonforandroid.recipe import NDKRecipe
44
from pythonforandroid.toolchain import (
@@ -9,43 +9,125 @@
99

1010

1111
class OpenCVRecipe(NDKRecipe):
12+
'''
13+
.. versionchanged:: 0.7.1
14+
rewrote recipe to support the python bindings (cv2.so) and enable the
15+
build of most of the libraries of the opencv's package, so we can
16+
process images, videos, objects, photos...
17+
'''
1218
version = '4.0.1'
1319
url = 'https://github.com/opencv/opencv/archive/{version}.zip'
1420
depends = ['numpy']
21+
patches = ['patches/p4a_build.patch']
22+
generated_libraries = [
23+
'libopencv_features2d.so',
24+
'libopencv_imgproc.so',
25+
'libopencv_stitching.so',
26+
'libopencv_calib3d.so',
27+
'libopencv_flann.so',
28+
'libopencv_ml.so',
29+
'libopencv_videoio.so',
30+
'libopencv_core.so',
31+
'libopencv_highgui.so',
32+
'libopencv_objdetect.so',
33+
'libopencv_video.so',
34+
'libopencv_dnn.so',
35+
'libopencv_imgcodecs.so',
36+
'libopencv_photo.so'
37+
]
38+
39+
def get_lib_dir(self, arch):
40+
return join(self.get_build_dir(arch.arch), 'build', 'lib', arch.arch)
1541

1642
def get_recipe_env(self, arch):
1743
env = super(OpenCVRecipe, self).get_recipe_env(arch)
1844
env['ANDROID_NDK'] = self.ctx.ndk_dir
1945
env['ANDROID_SDK'] = self.ctx.sdk_dir
2046
return env
2147

22-
def should_build(self, arch):
23-
return True
24-
2548
def build_arch(self, arch):
26-
build_dir = os.path.join(self.get_build_dir(arch.arch), 'build')
49+
build_dir = join(self.get_build_dir(arch.arch), 'build')
2750
shprint(sh.mkdir, '-p', build_dir)
2851
with current_directory(build_dir):
2952
env = self.get_recipe_env(arch)
53+
54+
python_major = self.ctx.python_recipe.version[0]
55+
python_include_root = self.ctx.python_recipe.include_root(arch.arch)
56+
python_site_packages = self.ctx.get_site_packages_dir()
57+
python_link_root = self.ctx.python_recipe.link_root(arch.arch)
58+
python_link_version = self.ctx.python_recipe.major_minor_version_string
59+
if 'python3' in self.ctx.python_recipe.name:
60+
python_link_version += 'm'
61+
python_library = join(python_link_root,
62+
'libpython{}.so'.format(python_link_version))
63+
python_include_numpy = join(python_site_packages,
64+
'numpy', 'core', 'include')
65+
3066
shprint(sh.cmake,
67+
'-DP4A=ON',
3168
'-DANDROID_ABI={}'.format(arch.arch),
32-
'-DCMAKE_TOOLCHAIN_FILE={}/build/cmake/android.toolchain.cmake'.format(self.ctx.ndk_dir),
33-
'-DPYTHON_NUMPY_INCLUDE_DIR={}/numpy/core/include'.format(self.ctx.get_site_packages_dir()),
69+
'-DANDROID_STANDALONE_TOOLCHAIN={}'.format(self.ctx.ndk_dir),
70+
'-DANDROID_NATIVE_API_LEVEL={}'.format(self.ctx.ndk_api),
3471
'-DANDROID_EXECUTABLE={}/tools/android'.format(env['ANDROID_SDK']),
35-
'-DBUILD_TESTS=OFF', '-DBUILD_PERF_TESTS=OFF', '-DENABLE_TESTING=OFF',
36-
'-DBUILD_EXAMPLES=OFF', '-DBUILD_ANDROID_EXAMPLES=OFF',
37-
'-DBUILD_opencv_imgproc=OFF', '-DBUILD_opencv_flann=OFF',
38-
'-DBUILD_opencv_python3=ON',
72+
73+
'-DCMAKE_TOOLCHAIN_FILE={}'.format(
74+
join(self.ctx.ndk_dir, 'build', 'cmake',
75+
'android.toolchain.cmake')),
76+
# Make the linkage with our python library, otherwise we
77+
# will get dlopen error when trying to import cv2's module.
78+
'-DCMAKE_SHARED_LINKER_FLAGS=-L{path} -lpython{version}'.format(
79+
path=python_link_root,
80+
version=python_link_version),
81+
3982
'-DBUILD_WITH_STANDALONE_TOOLCHAIN=ON',
40-
'-DPYTHON_PACKAGES_PATH={}'.format(self.ctx.get_site_packages_dir()),
41-
'-DANDROID_STANDALONE_TOOLCHAIN={}'.format(self.ctx.ndk_dir),
42-
'-DANDROID_NATIVE_API_LEVEL={}'.format(self.ctx.android_api),
83+
# Force to build as shared libraries the cv2's dependant
84+
# libs or we will not be able to link with our python
85+
'-DBUILD_SHARED_LIBS=ON',
86+
'-DBUILD_STATIC_LIBS=OFF',
87+
88+
# Disable some opencv's features
89+
'-DBUILD_opencv_java=OFF',
90+
# '-DBUILD_opencv_imgproc=OFF',
91+
# '-DBUILD_opencv_flann=OFF',
92+
'-DBUILD_TESTS=OFF',
93+
'-DBUILD_PERF_TESTS=OFF',
94+
'-DENABLE_TESTING=OFF',
95+
'-DBUILD_EXAMPLES=OFF',
96+
'-DBUILD_ANDROID_EXAMPLES=OFF',
97+
98+
# Force to only build our version of python
99+
'-DBUILD_OPENCV_PYTHON{major}=ON'.format(major=python_major),
100+
'-DBUILD_OPENCV_PYTHON{major}=OFF'.format(
101+
major='2' if python_major == '3' else '3'),
102+
103+
# Force to install the `cv2.so` library directly into
104+
# python's site packages (otherwise the cv2's loader fails
105+
# on finding the cv2.so library)
106+
'-DOPENCV_SKIP_PYTHON_LOADER=ON',
107+
'-DOPENCV_PYTHON{major}_INSTALL_PATH={site_packages}'.format(
108+
major=python_major, site_packages=python_site_packages),
109+
110+
# Define python's paths for: exe, lib, includes, numpy...
111+
'-DPYTHON_DEFAULT_EXECUTABLE={}'.format(self.ctx.hostpython),
112+
'-DPYTHON{major}_EXECUTABLE={host_python}'.format(
113+
major=python_major, host_python=self.ctx.hostpython),
114+
'-DPYTHON{major}_INCLUDE_PATH={include_path}'.format(
115+
major=python_major, include_path=python_include_root),
116+
'-DPYTHON{major}_LIBRARIES={python_lib}'.format(
117+
major=python_major, python_lib=python_library),
118+
'-DPYTHON{major}_NUMPY_INCLUDE_DIRS={numpy_include}'.format(
119+
major=python_major, numpy_include=python_include_numpy),
120+
'-DPYTHON{major}_PACKAGES_PATH={site_packages}'.format(
121+
major=python_major, site_packages=python_site_packages),
122+
43123
self.get_build_dir(arch.arch),
44124
_env=env)
45-
shprint(sh.make, '-j', str(cpu_count()))
125+
shprint(sh.make, '-j' + str(cpu_count()), 'opencv_python' + python_major)
126+
# Install python bindings (cv2.so)
46127
shprint(sh.cmake, '-DCOMPONENT=python', '-P', './cmake_install.cmake')
47-
sh.cp('-a', sh.glob('./lib/{}/lib*.a'.format(arch.arch)), self.ctx.get_libs_dir(arch.arch))
48-
self.ctx.get_libs_dir(arch.arch)
128+
# Copy third party shared libs that we need in our final apk
129+
sh.cp('-a', sh.glob('./lib/{}/lib*.so'.format(arch.arch)),
130+
self.ctx.get_libs_dir(arch.arch))
49131

50132

51133
recipe = OpenCVRecipe()
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
This patch allow that the opencv's build command correctly detects our version
2+
of python, so we can successfully build the python bindings (cv2.so)
3+
--- opencv-4.0.1/cmake/OpenCVDetectPython.cmake.orig 2018-12-22 08:03:30.000000000 +0100
4+
+++ opencv-4.0.1/cmake/OpenCVDetectPython.cmake 2019-01-31 11:33:10.896502978 +0100
5+
@@ -175,7 +175,7 @@ if(NOT ${found})
6+
endif()
7+
endif()
8+
9+
- if(NOT ANDROID AND NOT IOS)
10+
+ if(P4A OR NOT ANDROID AND NOT IOS)
11+
if(CMAKE_HOST_UNIX)
12+
execute_process(COMMAND ${_executable} -c "from distutils.sysconfig import *; print(get_python_lib())"
13+
RESULT_VARIABLE _cvpy_process
14+
@@ -244,7 +244,7 @@ if(NOT ${found})
15+
OUTPUT_STRIP_TRAILING_WHITESPACE)
16+
endif()
17+
endif()
18+
- endif(NOT ANDROID AND NOT IOS)
19+
+ endif(P4A OR NOT ANDROID AND NOT IOS)
20+
endif()
21+
22+
# Export return values
23+
--- opencv-4.0.1/modules/python/CMakeLists.txt.orig 2018-12-22 08:03:30.000000000 +0100
24+
+++ opencv-4.0.1/modules/python/CMakeLists.txt 2019-01-31 11:47:17.100494908 +0100
25+
@@ -3,7 +3,7 @@
26+
# ----------------------------------------------------------------------------
27+
if(DEFINED OPENCV_INITIAL_PASS) # OpenCV build
28+
29+
-if(ANDROID OR APPLE_FRAMEWORK OR WINRT)
30+
+if(ANDROID AND NOT P4A OR APPLE_FRAMEWORK OR WINRT)
31+
ocv_module_disable_(python2)
32+
ocv_module_disable_(python3)
33+
return()

0 commit comments

Comments
 (0)