最近一个新项目需要用的到人脸检测,想着之前见过opencv,就在网上找了配置教程,结果一直无法成功,鉴于网上的基本都是330版本,想着可能比较老,去官网下载了最新版(那个下载速度啊,真的是…)建议可以去github上面下载,我下的是3.4.0(为什么不是最新版呢?因为我下过了,不行,后面看到有人说不要下载最新版 ^ 笑哭^)
好了, 配置看上面的有人的文章就好了
万一有人的文章不进了呢,那我还是复制一下吧
-
导入modul
就常规的import module啊 选择下载的文件里面sdk 文件夹下面的 java文件夹 导入就好了 -
修改配置文件
修改导入module的build.gradle
(1)将apply plugin: 'com.android.application’修改为apply plugin: ‘com.android.library’
(2)将applicationId “org.opencv”"删去
(3)将compileSdkVersion 、buildToolsVersion、minSdkVersion 、targetSdkVersion 属性值的设置与app对应的build.gradle文件的配置一致 -
增加依赖库
这个都会吧 不用记了 -
最重要的来了
将下载的文件夹里面的sdk → native → libs文件下的文件复制到项目的主module的lib文件夹下面(也不用全部放进去啦 要哪个就加哪个就好了)
然后就是在主module里面配置假如的so文件啦 这个也会吧
现在就可以验证了哦
private BaseLoaderCallback loaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
super.onManagerConnected(status);
switch (status) {
case LoaderCallbackInterface.SUCCESS:
try {
//加载人脸检测XML
//OpenCV的人脸模型文件: lbpcascade_frontalface_improved
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface_improved);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface_improved.xml");
FileOutputStream fos = new FileOutputStream(cascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
is.close();
fos.close();
cascadeClassifier = new CascadeClassifier(cascadeFile.getAbsolutePath());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mVB.viewCamera.enableView();
break;
default:
super.onManagerConnected(status);
break;
}
}
};
@Override
protected void onResume() {
super.onResume();
if (OpenCVLoader.initDebug()) {
loaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
} else {
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_4_0, XmApplication.getInstance(), loaderCallback);
}
}
- 人脸检测
implements CameraBridgeViewBase.CvCameraViewListener2
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mGrayImage = inputFrame.gray();
mRgbaImage = inputFrame.rgba();
int rotation = mVB.viewCamera.getDisplay().getRotation();
//函数很简单,一个输入Mat,一个输出Mat,flipCode有三种情况,0为绕X轴翻转,大于的0代表绕Y轴翻转,-1代表即桡X轴也绕Y轴翻转。
if (Constants.isCameraBack) {
Core.flip(mRgbaImage, mRgbaImage, 1);
Core.flip(mGrayImage, mGrayImage, 1);
}
MatOfRect faces = new MatOfRect();
if (rotation == Surface.ROTATION_0) {
Core.rotate(mGrayImage, mGray, Core.ROTATE_90_COUNTERCLOCKWISE);
Core.rotate(mRgbaImage, mRgba, Core.ROTATE_90_COUNTERCLOCKWISE);
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 2, 2, new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
}
org.opencv.core.Rect[] faceArray = faces.toArray();
if (mCameraBitmap == null && faceArray.length >= 1) {
//WillWolf 获取人脸Bitmap
Mat tmMat = new Mat(mRgba, faceArray[0]);
Bitmap bitmap = Bitmap.createBitmap(tmMat.cols(), tmMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(tmMat, bitmap);
mCameraBitmap = bitmap;
}
Core.rotate(mRgba, mRgbaImage, Core.ROTATE_90_COUNTERCLOCKWISE);
} else {
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(mGrayImage, faces, 1.1, 2, 2, new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
}
org.opencv.core.Rect[] faceArray = faces.toArray();
for (int i = 0; i < faceArray.length; i++) {
Imgproc.rectangle(mRgbaImage, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
}
}
return mRgbaImage;
}
@Override
public void onCameraViewStarted(int width, int height) {
mRgbaImage = new Mat(width, height, CvType.CV_8UC4);
mGrayImage = new Mat(height, width, CvType.CV_8UC4);
mRgba = new Mat(width, height, CvType.CV_8UC4);
mGray = new Mat(width, height, CvType.CV_8UC4);
mAbsoluteFaceSize = (int) (height * 0.2);
}
@Override
public void onCameraViewStopped() {
/*
mGray.release();
mRgba.release();
*/
mGrayImage.release();
mRgbaImage.release();
mRgba.release();
mGray.release();
}
补充
补充一下关于预览界面翻转的问题
其实就是修改opencv的一个库文件CameraBridgeViewBase.java 文件里面的deliverAndDrawFrame
protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
Mat modified;
if (mListener != null) {
modified = mListener.onCameraFrame(frame);
} else {
modified = frame.rgba();
}
boolean bmpValid = true;
if (modified != null) {
try {
Utils.matToBitmap(modified, mCacheBitmap);
} catch (Exception e) {
Log.e(TAG, "Mat type: " + modified);
Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
bmpValid = false;
}
}
if (bmpValid && mCacheBitmap != null) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
/*
//原来的方法
if (BuildConfig.DEBUG)
Log.d(TAG, "mStretch value: " + mScale);
if (mScale != 0) {
canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
(int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
} else {
canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
(canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
(canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
(canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
}
*/
//解决竖屏图像翻转问题
Matrix matrix = new Matrix();
if (getDisplay().getRotation() == Surface.ROTATION_0) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(90f, (canvas.getWidth()) / 2, (canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_90) {
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_180) {
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
matrix.postRotate(270f, (canvas.getWidth()) / 2, (canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
} else if (getDisplay().getRotation() == Surface.ROTATION_270) {
matrix.postRotate(180f, (canvas.getWidth()) / 2, (canvas.getHeight()) / 2);
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
}
if (mFpsMeter != null) {
mFpsMeter.measure();
mFpsMeter.draw(canvas, 20, 30);
}
getHolder().unlockCanvasAndPost(canvas);
}
}
}
但是该方法要是在AndroidManifest.xml里锁定竖屏
<activity
android:name=".ui.MainActivity"
android:screenOrientation="portrait" />
最后补一句 解决竖屏的问题 也是我抄的 大佬在这里