Slim OpenCV
Scanly ships a self-built OpenCV 5.0.0 that contains only the modules the app uses, instead of
the full org.opencv:opencv:5.0.0.1 Maven AAR. Each APK gets about 32 MB smaller (both ABIs),
and the app's results and speed stay the same.
| Official 5.0.0.1 | Slim 5.0.0 | |
|---|---|---|
libopencv_java5.so arm64-v8a | 33.4 MB | 14.3 MB |
libopencv_java5.so armeabi-v7a | 22.3 MB | 9.3 MB |
| GitHub release APK (both ABIs) | 146.2 MB | 113.9 MB |
What is in it
- Modules:
core,imgproc,geometry(imgprocneeds it, and Indra callsGeometry.getRotationMatrix2D),flann(geometryneeds it),java,imgcodecsandvideoio. OpenCV's Android Java classes always includeorg.opencv.android.Utils(importsImgcodecs) andNativeCameraView(importsvideoio), so they do not compile without those two. - Codecs: every image codec in
imgcodecsis off. The app never encodes or decodes images through OpenCV.videoioon Android is only the system MediaNDK backend. - Same as the official build: source tag, NDK 27.2.12479018, CMake 3.22.1, compiler flags
and
-O3, CPU baseline and dispatch (arm64: NEON FP16 baseline, NEON_DOTPROD / NEON_FP16 / NEON_BF16 dispatch), KleidiCV 26.03 and carotene acceleration, TBB 2022.1, ITT and 16 KB page alignment. Comparethird_party/opencv/build-info-<abi>.txt(OpenCV'sgetBuildInformation()for the slim library) with the official library's build information. - Left out:
dnn,features,calib,objdetect,photo,stitching,video,ptcloud,stereoandhighgui. The app uses none of them; the Java classes of those modules are absent.
Building it
app/build.gradle.kts uses third_party/opencv/opencv-5.0.0-slim.aar when it exists and falls
back to the Maven artifact otherwise, which has the same API. Release builds stop with an error
without the slim AAR, so a release never ships the full library by accident. To build a release
with the full library on purpose (for an A/B comparison), move the AAR aside and pass
-Pscanly.allowFullOpenCv=true.
Requirements: Android SDK with ndk/27.2.12479018 and cmake/3.22.1, JDK 17 in JAVA_HOME
(OpenCV's Gradle projects use Kotlin 1.8.20, which rejects newer JVM targets), Python 3.8+ and
internet access (OpenCV source, KleidiCV, TBB, Gradle). From the repo root:
$env:JAVA_HOME = "<path to JDK 17>"
python scripts/opencv/build_slim_opencv.py --sdk "$env:LOCALAPPDATA/Android/Sdk" --work C:/ocvb
The script runs OpenCV's own platforms/android/build_sdk.py and build_java_shared_aar.py
(the scripts behind the official AAR) with scripts/opencv/slim.config.py. A full build takes
about 40 minutes. It works on Windows, Linux and macOS; on Windows it starts Gradle through
gradlew.bat, which is the only change to how OpenCV's scripts run.
Checking a new build
OpenCvParityHarnessTest (androidTest) runs every OpenCV code path in the app on fixed generated
pages: all filter presets at three intensities, the adjustment sliders, signature extraction,
the image analysis and Indra preprocessing. It logs a SHA-256 of every output and median timings
to logcat (tag OcvParity). Run it once with each library on the same phone and diff the HASH
lines; see the test's KDoc for the commands. It only runs when the opencvParity instrumentation
argument is true.
Results for the first slim build, on a Galaxy S20 FE (Android 13):
- All 344 output hashes were identical between the official and the slim library in every run (the official library itself is deterministic run to run).
- Total time of the 18 timed operations, alternating official and slim APKs: −0.1%, −0.6% and −0.4% for the slim library in the three pairs the phone did not start throttling in.
Upgrading OpenCV
Change OPENCV_VERSION and NDK_VERSION in scripts/opencv/build_slim_opencv.py to match the
new official release's build information, rebuild, compare build-info-<abi>.txt with the
official library, and run the parity harness against the official AAR before switching.