一. 说明
前次的博客说了怎样使用opencv训练识别一些指定的物体,既然有了自己的模型,那么我们是否可以将这个模型用于手机端,结合app进行一些更方便的检测任务呢,回答是肯定的,本篇博客主要记录一下用于物体检测的opencv怎样移植到安卓移动端进行使用的。
二. 准备工作
1. 需要的环境
Android studio(这里使用了2.3.3版本)
opencv-3.4.0-android-sdk
地址:https://jaist.dl.sourceforge.net/project/opencvlibrary/opencv-android/3.4.0/opencv-3.4.0-android-sdk.zip
三. 开始集成
1. 下载opencv-3.4.0-android-sdk并解压缩
2. 新建安卓项目,在项目的根目录新建libraries文件夹,复制 Android SDK 中目录 sdk 下的 java 文件夹到刚刚创建的 libraries 目录中,并将拷贝进去的java文件夹名称修改为 opencv
3. 在重命名的 opencv 文件夹下创建一个 build.gradle 文件,
内容如下图所示:
apply plugin: 'android-library'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
android {
compileSdkVersion 25
buildToolsVersion "27.0.3"
defaultConfig {
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
res.srcDirs = ['res']
aidl.srcDirs = ['src']
}
}
}
注: minSdkVersion , targetSdkVersion , versionCode , versionName 等可依实际情况而定
4. 编辑安卓项目中的settings.gradle 文件,添加一行代码:include ':libraries:opencv',然后点击右上方的Sync Now进行同步
5. 右键工程, Open Module Settings , 左边选中应用的module名称,右边点击 Dependencies 选项,再点击 + 按钮,添加依赖。选择 Module dependency, 会出现一个含有多个module的列表,选择 :libraries:opencv。
6. /app/src/main/ 下创建一个 jniLibs 文件夹在,将OpenCV Android SDK 中 sdk/native/libs 下的所有文件夹复制到创建的 jniLibs 目录下,点击右上方的Sync Now进行同步。
至此完成了opencv的基本环境配置。
四. 测试使用
1. 在安卓项目的res文件夹下新建raw文件夹,将我们之前训练好的舌头模型tongue.xml(制作教程链接:https://blog.csdn.net/qq_27063119/article/details/79247266), (如果没有训练,可以使用gopencv自带的人脸模型OpenCV-android-sdk\sdk\etc\haarcascades\haarcascade_frontalface_alt2.xml)
2. 在Activity里面添加初始化opencv的函数
private void initializeOpenCVDependencies() {
try {
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
// File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
// File mCascadeFile = new File(cascadeDir, "haarcascade_frontalface_alt2.xml");
File mCascadeFile = new File(cascadeDir, "tongue.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();
// Load the cascade classifier
cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
if (cascadeClassifier.empty()) {
Log.e("initializeOpenCVDependencies : ", "Failed to load cascade classifier");
cascadeDir = null;
} else{
Log.i("initializeOpenCVDependencies : ", "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());
}
} catch (Exception e) {
Log.e("OpenCVActivity", "Error loading cascade", e);
}
// openCvCameraView.enableView();
}
使用静态方法进行加载:
/**
* 此方式配置的opencv必须要静态方式加载
*/
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
initializeOpenCVDependencies();
break;
default:
super.onManagerConnected(status);
break;
}
}
};
接下来就可以对拍照后的图片:Bitmap类型进行 物体检测了:
检测所用的工具类:FaceRtspUtil,添加检测的方法:detectFrame2()
/**
* 人脸检测工具
*/
public class FaceRtspUtil {
private static final String TAG = "FaceUtil";
private Mat grayscaleImage;
private CascadeClassifier cascadeClassifier = null;
public FaceRtspUtil(CascadeClassifier cascadeClassifier, int width, int height) {
this.cascadeClassifier = cascadeClassifier;
//人脸的宽高最小也要是原图的height的 10%
grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
}
/**
* 测试有没有人脸
* @param oldBitmap
* @return
*/
public boolean detectFrame2(Bitmap oldBitmap) {
Mat aInputFrame = new Mat();
if (oldBitmap == null) {
return false;
}
Utils.bitmapToMat(oldBitmap, aInputFrame);
if (grayscaleImage == null) {
Log.i(TAG, "detectFrame: aInputFrame == null || grayscaleImage == null");
return false;
}
Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
MatOfRect faces = new MatOfRect();
// 使用级联分类器 检测物体
if (cascadeClassifier != null) {
//不获取60*60以下的物体
cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2 , new Size(60, 60), new Size());
}
//facesArray里保存所有检测到的人脸的位置及大小
Rect[] facesArray = faces.toArray();
if (facesArray == null || facesArray.length == 0) {
//如果没有人脸,直接退出
Log.i(TAG, "detectFrame: 该图片中没有人脸");
return false;
}else{
Log.i(TAG, "detectFrame: OK ! 检测到人脸");
return true;
}
}
}
最后就是提供一下调用了,拍照后调用方式:
//调用opencv检测物体
FaceRtspUtil mFaceUtil = new FaceRtspUtil(cascadeClassifier, PIC_WIDTH, PIC_HEIGHT);
//对保存在本地的图片进行人脸检测,并获取截到的所有人脸
boolean hasSubstance = mFaceUtil.detectFrame2(rightBitmap);
如果想自动进行检测到人脸(物体) 自动拍照,可以使用线程进行间断性抓拍,然后将图片递交给opencv检测,如果是检测正确的话就进行存储。
这里放一下android的效果图:
android 源码下载地址,8个积分(由于集成opencv后项目太大1.2G, 因此不包含opencv集成的文件,自行去文中给的官方链接下载即可) :
https://download.csdn.net/download/qq_27063119/10346007