How to build OpenCV from source for Android
![]()
Recently, I had to use OpenCV in an Android Studio project and unfortunately, the off-the-shelf, ready-to-use binaries on the internet were not entirely compatible with my setup.
So it took me a couple of days to work out the issues and I thought it might be helpful to document the process for later use by me or someone else.
Pre Requisities
- Use a Linux OS. It is assumed that
Arch Linuxis used. - Install the latest version of
Android Studio. - Use
SDK MangerofAndroid Studioto install yourSDK 25,NDK 21.4.7075529, andBuildTools 25.0.3of your choice. - Install the packages that we are going to need on your linux: sudo pacman -S cmake git aria2 ant unzip ant
- Make sure you have a suitable python2, python3, and jdk
OpenCV Versions
If you need the cv1 interface of OpenCV, you should use version<4. Versions>=4 only have the cv2 interface.
We are going to use OpenCV 3.4.16 .
Android SDK Tools
The android executable of Android SDK located at sdk/tools/android which is used by OpenCV’s CMake scripts to set up the java module project is deprecated by Google. Unfortunately, OpenCV, even the latest versions of it, still use this deprecated executable. The workaround is to download an older version of this file from Google and use it instead.
(as described here)
Downgrading Sdk/tools
$ cd ~/Downloads
$ aria2 -x8 http://dl-ssl.google.com/android/repository/tools_r25.2.5-linux.zip
$ mv ~/Android/Sdk/tools ~/Android/Sdk/tools.ORIG
$ unzip tools_r25.2.5-linux.zip -d ~/Android/Sdk/
Get OpenCV Source
$ cd ~
$ mkdir opencv_repo
$ cd opencv_repo
$ aria2 -x8 https://github.com/opencv/opencv/archive/refs/tags/3.4.16.zip
$ aria2 -x8 https://github.com/opencv/opencv_contrib/archive/refs/tags/3.4.16.zip
$ unzip opencv-3.4.16.zip
$ unzip opencv_contrib-3.4.16.zip
$ cd opencv-3.4.16
$ aria2 https://gist.githubusercontent.com/salehjg/2ce2ef90071eaa3ba7f3404f4094ae12/raw/41f1533729283affb1c02c00af4fd81e9d57aa2b/cmake_conf.sh
Now open cmake_conf.sh and edit the path lines. Save it and continue.
$ mkdir 00_build
$ mkdir 01_ndk_outputs
$ cd 00_build
$ bash ../cmake_conf.sh
$ make all -j8
$ make install
The NDK version of OpenCV should be available in 01_ndk_outputs now.
Android SDK Tools
Now that we are finished with the old android executable, we have to restore the original version of the sdk/tools directory.
Resoring the original Sdk/tools
$ rm -rf ~/Android/Sdk/tools
$ mv ~/Android/Sdk/tools.ORIG ~/Android/Sdk/tools
Setting up the Android Studio project
- Assuming that the OpenCV shared library for Android is already built, follow the steps below.
- Create a new project, Java, MinSDK API26.
- In
Project Side Bar, right-click onAppand selectNew -> Folder -> JNI Folder. - Check the
Change Folder Locationcheck box and rename the last part of the path fromsrc/main/jni/tosrc/main/jniLibs/. - Go to your
OpenCV/01_ndk_outputs/sdk/native/libssource directory and select all the folders and copy them intojniLibsof your Android Studio project. - It is assumed that your phone is an
arm64-v8a. - Open your app’s
build.gradleand add this todefaultConfigentry:
externalNativeBuild{ cmake{ cppFlags "-frtti -fexceptions" abiFilters 'arm64-v8a' } } - Also, make sure that app’s
build.gradle, theandroidentry has this member (you can skip steps 3 and 4, createjniLibsmanualy and copy this intobuild.gradle):
sourceSets { main { jni { srcDirs 'src/main/jni', 'src/main/jniLibs' } } } - Copy
opencv/01_ndk_outputs/sdkinto the base directory of your Android Studio project and then rename thesdkintoopencv. - Inside the
opencvdirectory, openbuild.gradlewith a code editor. - Edit
compileSdkVersion,targetSdkVersion, andminSdkVersionto match your Android Studio project. - Edit
JavaVersionand change it toVERSION_1_8, otherwise your app will crash on startup. - In Android Studio, change the
Project Side Barmode fromAndroidtoProject. - Find the
opencvdirectory and openlocal.propertiesand make sure thesdk.diris set correctly. - Find and open
settings.gradlein theProject Side BaronProjectmode and appendinclude ':opencv'to it andSyncthe gradle script. - Find and open app’s
build.gradleand addimplementation project(path: ':opencv')to thedependenciesentry andSyncthe gradle script. -
Open
activity_main.xmland copy this:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:opencv="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <org.opencv.android.JavaCameraView android:layout_width="fill_parent" android:layout_height="fill_parent" android:visibility="gone" android:id="@+id/HelloOpenCvView" opencv:show_fps="true" opencv:camera_id="any" /> </LinearLayout> -
Open
AndroidManifest.xmland add these outside theapplicationentry:<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.camera.front" /> <uses-feature android:name="android.hardware.camera.front.autofocus" /> -
Open
MainActivity.javaand replace the content with:public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 { private CameraBridgeViewBase mOpenCvCameraView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.loadLibrary("opencv_java3"); Mat a = new Mat(100,200, CvType.CV_8UC1); Mat b = new Mat(100,200, CvType.CV_8UC1); getPermissions(); mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.HelloOpenCvView); mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE); mOpenCvCameraView.setCvCameraViewListener(this); } private void getPermissions() { String[] requiredPermission = { android.Manifest.permission.CAMERA, }; ActivityCompat.requestPermissions(MainActivity.this, requiredPermission, 100); } @Override public void onRequestPermissionsResult (int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){ super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 100) { boolean allPermission = true; for (int i = 0; i < grantResults.length-2; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { allPermission = false; } } if (allPermission) { Toast.makeText(this, "Perms granted.", Toast.LENGTH_SHORT).show(); mOpenCvCameraView.enableView(); } else { Toast.makeText(this, "Failed to get the perms.", Toast.LENGTH_SHORT).show(); } } } @Override public void onCameraViewStarted(int width, int height) {} @Override public void onCameraViewStopped() {} @Override public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { Mat src = inputFrame.rgba(); Mat gray = new Mat(src.rows(), src.cols(), src.type()); Mat edges = new Mat(src.rows(), src.cols(), src.type()); org.opencv.imgproc.Imgproc.cvtColor(src, gray, org.opencv.imgproc.Imgproc.COLOR_RGB2GRAY); org.opencv.imgproc.Imgproc.Canny(gray, edges, 100, 100*3); return edges; } @Override public void onPause() { super.onPause(); if (mOpenCvCameraView != null) mOpenCvCameraView.disableView(); } public void onDestroy() { super.onDestroy(); if (mOpenCvCameraView != null) mOpenCvCameraView.disableView(); } } - Build the project.
- Connect your phone and run the app on the device.
- On the device (mine is API26) accept the permissions.
- Now you should be able to see the live camera feed with
Cannyalgorithm applied.