Open marclee44 opened 2 years ago
之前写了OpenCV初探之C#篇,今天我们来试试在Android上使用OpenCV
第一步 下载OpenCV Android SDK
可以在以下任一地址下载OpenCV Android SDK:
在任意版本下选择Android版本即可。 这里选用了4.5.3版本作为示例。 下载完成后,解压至固定文件夹待用。 嗯,如果开发是使用Java而非Kotlin,请顺便修改解压目录下的sdk\build.gradle文件,注释其中的apply plugin: 'kotlin-android'
sdk\build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'com.android.library' //apply plugin: 'kotlin-android' def openCVersionName = "4.5.3" def openCVersionCode = ((4 * 100 + 5) * 100 + 3) * 10 + 0
第二步 新建项目
新建一个Native C++项目,等待加载完成。此时,若你还未安装CMake和NDK,Android Studio会自动下载,并对项目进行基本配置。 当然,如果并不会用到一些C++特性的话,也可以新建一个普通项目。 不过这样,CMake和NDK就变成需要提前安装的前置任务了。这个我在Android超声波数据传输初探中已有详述。
Native C++
第三步 导入OpenCV Android SDK
local.properties
sdk.dir=D\:\\Android\\android-sdk ndk.dir=D\:\\Android\\android-sdk\\ndk\\22.1.7171670
settings.gradle
include ':opencv' project(':opencv').projectDir = new File('D:\\Android\\OpenCV-android-sdk\\sdk')
build.gradle
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':opencv') ... }
好了,点击工具栏的小乌龟同步项目(Sync Project with Gradle Files)。 等待opencv的导入及自动编译完成。
Sync Project with Gradle Files
最后 从sample改一个人脸检测
嗯,由于OpenCV Android SDK自带的sample:face-detection始终无法编译通过,只能自己尝试改一个出来。
face-detection
人脸Haar特征库的xml文件似乎只能以Native C++方式使用,故我们新建Native C++项目。
将face-detection中cpp下的Android.mk、Application.mk、CMakeLists.txt、DetectionBasedTracker_jni.cpp与DetectionBasedTracker_jni.h这几个文件,复制到新建项目的cpp下。
Android.mk
Application.mk
CMakeLists.txt
DetectionBasedTracker_jni.cpp
DetectionBasedTracker_jni.h
修改DetectionBasedTracker_jni.cpp和DetectionBasedTracker_jni.h,将其中JNIEXPORT jlong JNICALL声明的方法前缀,Java_org_opencv_samples_facedetect_全部改为项目包名。例如包名为com.test.opencv,则改为Java_com_test_opencv_。
JNIEXPORT jlong JNICALL
Java_org_opencv_samples_facedetect_
com.test.opencv
Java_com_test_opencv_
修改app的build.gradle文件中cmake内容
android { ... defaultConfig { applicationId "com.test.opencv" ... externalNativeBuild { cmake { arguments "-DOpenCV_DIR=" + project(':opencv').projectDir + "/native/jni", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_shared" targets "detection_based_tracker" } } } ... }
复制face-detection中的工具类DetectionBasedTracker.java及Haar特征库文件lbpcascade_frontalface.xml到项目相应位置
DetectionBasedTracker.java
lbpcascade_frontalface.xml
Activity中的主要代码
private int mDetectorType = JAVA_DETECTOR; private Mat mRgba; private Mat mGray; private File mCascadeFile; private CascadeClassifier mJavaDetector; private DetectionBasedTracker mNativeDetector; private CameraBridgeViewBase mOpenCvCameraView; ... private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { //在OpenCV初始化完成后,加载native library System.loadLibrary("detection_based_tracker"); try { //加载Haar特征库文件 InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface); File cascadeDir = getDir("cascade", Context.MODE_PRIVATE); mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml"); FileOutputStream os = new FileOutputStream(mCascadeFile); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } is.close(); os.close(); mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath()); if (mJavaDetector.empty()) { //加载失败 mJavaDetector = null; } mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0); cascadeDir.delete(); } catch (IOException e) { e.printStackTrace(); } mOpenCvCameraView.enableView(); } break; default: { super.onManagerConnected(status); } break; } } }; public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { mRgba = inputFrame.rgba(); mGray = inputFrame.gray(); if (mAbsoluteFaceSize == 0) { int height = mGray.rows(); if (Math.round(height * mRelativeFaceSize) > 0) { mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize); } mNativeDetector.setMinFaceSize(mAbsoluteFaceSize); } MatOfRect faces = new MatOfRect(); if (mDetectorType == JAVA_DETECTOR) { if (mJavaDetector != null) mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size()); } else if (mDetectorType == NATIVE_DETECTOR) { if (mNativeDetector != null) mNativeDetector.detect(mGray, faces); } else { Log.e(TAG, "Detection method is not selected!"); } Rect[] facesArray = faces.toArray(); for (int i = 0; i < facesArray.length; i++) Imgproc.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3); return mRgba; }
可以看到主要检测方法,与C#区别并不大
之前写了OpenCV初探之C#篇,今天我们来试试在Android上使用OpenCV
可以在以下任一地址下载OpenCV Android SDK:
在任意版本下选择Android版本即可。 这里选用了4.5.3版本作为示例。 下载完成后,解压至固定文件夹待用。 嗯,如果开发是使用Java而非Kotlin,请顺便修改解压目录下的
sdk\build.gradle
文件,注释其中的apply plugin: 'kotlin-android'
新建一个
Native C++
项目,等待加载完成。此时,若你还未安装CMake和NDK,Android Studio会自动下载,并对项目进行基本配置。 当然,如果并不会用到一些C++特性的话,也可以新建一个普通项目。 不过这样,CMake和NDK就变成需要提前安装的前置任务了。这个我在Android超声波数据传输初探中已有详述。local.properties
文件,加入NDK指向settings.gradle
文件,加入OpenCV Android SDK的指向build.gradle
文件,引用opencv module好了,点击工具栏的小乌龟同步项目(
Sync Project with Gradle Files
)。 等待opencv的导入及自动编译完成。嗯,由于OpenCV Android SDK自带的sample:
face-detection
始终无法编译通过,只能自己尝试改一个出来。人脸Haar特征库的xml文件似乎只能以
Native C++
方式使用,故我们新建Native C++
项目。将
face-detection
中cpp下的Android.mk
、Application.mk
、CMakeLists.txt
、DetectionBasedTracker_jni.cpp
与DetectionBasedTracker_jni.h
这几个文件,复制到新建项目的cpp下。修改
DetectionBasedTracker_jni.cpp
和DetectionBasedTracker_jni.h
,将其中JNIEXPORT jlong JNICALL
声明的方法前缀,Java_org_opencv_samples_facedetect_
全部改为项目包名。例如包名为com.test.opencv
,则改为Java_com_test_opencv_
。修改app的
build.gradle
文件中cmake内容复制
face-detection
中的工具类DetectionBasedTracker.java
及Haar特征库文件lbpcascade_frontalface.xml
到项目相应位置Activity中的主要代码
可以看到主要检测方法,与C#区别并不大