title: Android OpenCV环境搭建与Demo展示
tags: Opencv
date: 2020-2-02 00:53:00
最终效果
视频展示:
https://www.bilibili.com/video/av86393649/
【Android opencv】硬件工程师假期无聊硬撸安卓opencv开发
【Android opencv】优化动态修改参数UI
前言:
首先,这个项目说实话我做了两年,上学的时候很想做这个东西,由于当时能力不足,对于编程方面的知识储备也不足,而且对于未知的东西有种渴望,但是无奈心有余而力不足,导致自己的很多想法都放弃了,有些甚至夭折了。
环境配置:
Android studio版本:V3.5.2
OpenCV版本:3.4.6
接下来我将逐一给大家截图分析环境的搭建过程,后面应该还会录制一期视频来讲解。
资料下载:
工程仓库地址:
https://github.com/az666/Android-Opencv
opencv-3.4.6-android-sdk.zip
https://download.csdn.net/download/switch_love_case/12129739
SO库:libopencv_info.so (用于免Manager APP) https://download.csdn.net/download/wawayuchibang/10614343
博主APK文件: https://fir.im/ve24
备注: 下面的所有流程成立的前提是你的AndroidStudio能够正常工作!即代表你的AndroidStudio的运行环境是OK的。不然后面出现问题不好排查。
- 首先,在你的Android Studio能正常工作的前提下,新建一个项目,注意新版的Android Studio
是可以直接新建C++依赖的。
- 注意这里要选择C++14
- 到这里如果编译无错,证明你的Android Studio是可以正常运行的(如果有错误,需要你自己排查下,因为版本不同,我不在讲解错误排查),可以暂停一下,由于OpenCV需要NDK和Cmake支持,这里需要配置一下,勾选下载即可。
OpenCV—JAVA库安装
- 接下来开始安装Opencv库支持
- 导入刚刚下载的opencvSDK里面的JAVA库
- 这个时候,等待初始化完成,不出意外地话 应该会报错:
删除掉报错的那一行即可,因为新版的Android Studio已经不允许在First文件里声明最小版本了,删除即可。
OpenCV—JAVA库依赖
- 下面开始添加依赖
致此,已基本配置OK
OpenCV—免Manger APP配置
- 官方的Opencv Android支持是需要配合另外一个APP来实现的图像处理,这样使用起来很不友好,接下来进行移植。 按照图中文件路径,将文件夹下所有文件拷贝至 jniLibs文件夹下(如果没有自己新建一个)
人脸级联分类库移植
- 将下载的SDK文件夹下(G:\2019_AI_learn\opencv-3.4.6-android-sdk\OpenCV-android-sdk\sdk\etc\lbpcascades)的人脸数据拷贝至如图路径下的raw文件夹(新建一个)下即可。
最终测试代码移植与调试
MainActivity.java代码:
public class MainActivity extends AppCompatActivity implements
CameraBridgeViewBase.CvCameraViewListener2, View.OnClickListener {
private CameraBridgeViewBase cameraView;
private CascadeClassifier classifier;
private Mat mGray;
private Mat mRgba;
private int mAbsoluteFaceSize = 0;
private boolean isFrontCamera;
// 手动装载openCV库文件,以保证手机无需安装OpenCV Manager 不加这里将导致无法初始化 级联分类器(开机闪退)
static {
System.loadLibrary("opencv_java3");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA}, 1);
}
initWindowSettings();
setContentView(R.layout.activity_main);
cameraView = (CameraBridgeViewBase) findViewById(R.id.camera_view);
cameraView.setCvCameraViewListener(this); // 设置相机监听
initClassifier();
cameraView.enableView();
Button switchCamera = (Button) findViewById(R.id.switch_camera);
switchCamera.setOnClickListener(this); // 切换相机镜头,默认后置
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.switch_camera:
cameraView.disableView();
if (isFrontCamera) {
cameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);
isFrontCamera = false;
} else {
cameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);
isFrontCamera = true;
}
cameraView.enableView();
break;
default:
}
}
// 初始化窗口设置, 包括全屏、横屏、常亮
private void initWindowSettings() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
// 初始化人脸级联分类器,必须先初始化
private void initClassifier() {
try {
InputStream is = getResources()
.openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
FileOutputStream os = new FileOutputStream(cascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
is.close();
os.close();
classifier = new CascadeClassifier(cascadeFile.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onCameraViewStarted(int width, int height) {
mGray = new Mat();
mRgba = new Mat();
}
@Override
public void onCameraViewStopped() {
mGray.release();
mRgba.release();
}
@Override
// 这里执行人脸检测的逻辑, 根据OpenCV提供的例子实现(face-detection)
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
// 翻转矩阵以适配前后置摄像头
if (isFrontCamera) {
Core.flip(mRgba, mRgba, 1);
Core.flip(mGray, mGray, 1);
} else {
//如果发现后摄出现了镜像 把下面的注释打开即可 魅族不需要
// Core.flip(mRgba, mRgba, -1);
// Core.flip(mGray, mGray, -1);
}
float mRelativeFaceSize = 0.2f;
if (mAbsoluteFaceSize == 0) {
int height = mGray.rows();
if (Math.round(height * mRelativeFaceSize) > 0) {
mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
}
}
MatOfRect faces = new MatOfRect();
if (classifier != null)
classifier.detectMultiScale(mGray, faces, 1.1, 2, 2,
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
Rect[] facesArray = faces.toArray();
Scalar faceRectColor = new Scalar(0, 255, 0, 255);
for (Rect faceRect : facesArray)
Imgproc.rectangle(mRgba, faceRect.tl(), faceRect.br(), faceRectColor, 3);
return mRgba;
}
@Override
protected void onPause() {
super.onPause();
if (cameraView != null) {
cameraView.disableView();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
cameraView.disableView();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "权限拒绝", Toast.LENGTH_SHORT).show();
}
}
}
}
activity_main.xml代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<org.opencv.android.JavaCameraView
android:id="@+id/camera_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<Button
android:layout_margin="10dp"
android:text="'皮'"
android:id="@+id/switch_camera"
android:layout_width="43dp"
android:layout_height="37dp"
android:layout_gravity="center_vertical" />
</LinearLayout>
接下来不出意外地话,代码错误会比较少,如下:
是由于依赖库冲突导致,利用快捷键更改为Opencv即可。
修改完以后编译,直接真机调试,会出现下图错误,原因为Opencv库的版本(过低)或者与本APP版本不一致,修改一下即可
APP真机安装调试
致此,所有流程完毕。后续会有更详细的视频讲解。
物联网学习群:476840321
UP博客: http://wenzheng.club