Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

@tfandkusu

OpenCV for Androidのlibopencv_java4.soのバイナリサイズを減らし、APKのサイズを減らす

libopencv_java4.soは(多くの場合)無駄を含んでいる

OpenCVはコンパイル済みのAndroid用ビルドが公式で配布されています。
https://github.com/opencv/opencv/releases

opencv-4.0.1-android-sdk.zipをダウンロードし、共有ライブラリlibopencv_java4.soとjavaファイル群をAndroidプロジェクトの所定の位置に置くと、AndroidでOpenCVの処理をJava/Kotlinから使うことができます。

しかし共有ライブラリlibopencv_java4.soは多くの場合無駄を含んでいます。

nmコマンドでJNI関数のシンボルを確認してみます。

wget https://github.com/opencv/opencv/releases/download/4.0.1/opencv-4.0.1-android-sdk.zip
unzip opencv-4.0.1-android-sdk.zip
cd OpenCV-android-sdk/
nm -D sdk/native/libs/arm64-v8a/libopencv_java4.so  | less

シンボル名のJava_org_opencv_の次に注目してください。

前略
00000000001f0918 T Java_org_opencv_calib3d_StereoSGBM_setUniquenessRatio_10
中略
000000000018e4bc T Java_org_opencv_core_Algorithm_clear_10
中略
00000000001c9828 T Java_org_opencv_dnn_DictValue_DictValue_10
中略
00000000001e8830 T Java_org_opencv_features2d_AKAZE_create_10
中略
00000000001d746c T Java_org_opencv_imgcodecs_Imgcodecs_haveImageReader_10
中略
00000000001a50d8 T Java_org_opencv_imgproc_CLAHE_apply_10
中略
00000000001bb888 T Java_org_opencv_ml_ANN_1MLP_create_10
中略
000000000020fb5c T Java_org_opencv_objdetect_BaseCascadeClassifier_delete
中略
00000000001c7034 T Java_org_opencv_photo_AlignExposures_delete
中略
000000000021db0c T Java_org_opencv_video_BackgroundSubtractorKNN_delete
中略
00000000001da178 T Java_org_opencv_videoio_VideoCapture_VideoCapture_10
以下略

それら、calib3d、core、dnn、features2d等はそれぞれOpenCVのモジュールに相当します。多くの場合、持っているモジュールをすべて使うことは無いと思います。私はcore、imgcodecs、imgprocしか使いません。今回はその3つだけを持つlibopencv_java4.soを自分でビルドします。

ビルド環境の構築

Android NDKをAndroid Studioからインストールします。

Android SDK、Android NDKのパスを環境変数に設定します。

.bash_profile
export ANDROID_SDK=$HOME/Library/Android/sdk
export ANDROID_NDK=$ANDROID_SDK/ndk-bundle/

Python3をpyenv等でセットアップします。

cmake、ninja、ccacheをインストールします。

# Macの場合
brew install cmake ninja ccache
# Ubuntuの場合はaptコマンド

ビルドスクリプトの編集

ソースコードをダウンロード、展開し、ビルドスクリプトを編集します。

wget https://github.com/opencv/opencv/archive/4.0.1.tar.gz
tar -xvzf 4.0.1.tar.gz
cd opencv-4.0.1/platforms/
# エディタで android/build_sdk.py を開く

build_library関数のcmake_varsを編集します。このスクリプトは内部でcmakeコマンドを呼んでいて、この編集はcmakeの引数を変更するものになります。

android/build_sdk.py
    def build_library(self, abi, do_install):
        cmd = ["cmake", "-GNinja"]
        cmake_vars = dict(
            CMAKE_TOOLCHAIN_FILE=self.get_toolchain_file(),
            INSTALL_CREATE_DISTRIB="ON",
            WITH_OPENCL="OFF",
            WITH_IPP=("ON" if abi.haveIPP() else "OFF"),
            WITH_TBB="ON",
            BUILD_EXAMPLES="OFF",
            BUILD_TESTS="OFF",
            BUILD_PERF_TESTS="OFF",
            BUILD_DOCS="OFF",
            BUILD_ANDROID_EXAMPLES="OFF", # ビルドに失敗するのでOFF
            INSTALL_ANDROID_EXAMPLES="OFF",  # ビルドに失敗するのでOFF
            BUILD_LIST="core,imgcodecs,imgproc,java" # 追加する
        )

用途に応じてBUILD_LISTを変更します。例えば局所特徴量が必要な場合はfeatures2dを追加します。

あとはこのスクリプトを実行するだけです。ビルドが始まります。

android/build_sdk.py

生成物

OpenCV-android-sdkディレクトリにlibopencv_java4.soとjavaファイル群が作成されました。

find OpenCV-android-sdk/sdk/native/libs -type f
OpenCV-android-sdk/sdk/native/libs/armeabi-v7a/libopencv_java4.so
OpenCV-android-sdk/sdk/native/libs/x86/libopencv_java4.so
OpenCV-android-sdk/sdk/native/libs/arm64-v8a/libopencv_java4.so
OpenCV-android-sdk/sdk/native/libs/x86_64/libopencv_java4.so
find OpenCV-android-sdk/sdk/java/src -type f
OpenCV-android-sdk/sdk/java/src/org/opencv/core/Scalar.java
OpenCV-android-sdk/sdk/java/src/org/opencv/core/MatOfFloat6.java
OpenCV-android-sdk/sdk/java/src/org/opencv/core/Size.java
以下略

シンボルを確認すると、確かにcore、imgcodecs、imgprocしか含まれていません。

nm -D OpenCV-android-sdk/sdk/native/libs/arm64-v8a/libopencv_java4.so | less
前略
00000000000fc2c4 T Java_org_opencv_core_Algorithm_clear_10
中略
0000000000116cb8 T Java_org_opencv_imgcodecs_Imgcodecs_haveImageReader_10
中略
0000000000114044 T Java_org_opencv_imgproc_CLAHE_apply_10
以下略

削減した容量

libopencv_java4.soに含めるモジュールをcore,imgcodecs,imgprocだけにすると、以下のようにバイナリサイズを削減できました。

ABI 元のファイルサイズ 今回のファイルサイズ
armeabi-v7a 9MB 5MB
arm64-v8a 17MB 9MB

追記 ABIがx86とx86_64のsoファイルの容量を削減する

build_sdk.pyをもう1行変更しないと、ABIがx86とx86_64の容量が大きいままでした。

android/build_sdk.py
def haveIPP(self):
    return False #self.name == "x86" or self.name == "x86_64"
ABI haveIPP関数そのまま haveIPP関数の戻り値False
x86 25M 10M
x86_64 39M 11M
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What are the problem?