前言
上一章已经成功导入了opencv,但并没说如何展示从摄像头获取图像并展示出来,这章将简单的说说怎么展示,以及里面出现的问题作修正
一、使用opencv正常展示图像
首先准备一个空的activity页面,在其xml布局中添加JavaCameraView,这个view宽高都可以,不过,我为了在这个view下面添加功能按钮,所以给了高度限制
示例代码
<org.opencv.android.JavaCameraView
android:id="@+id/cameraView"
android:layout_width="@dimen/dp_300"
android:layout_height="@dimen/dp_250"
android:layout_gravity="center"
/>
添加后,在activity中对其生命周期作一下简单的绑定,我个人是写在onResume,onPause和onDestroy三个生命周期中去了
示例代码
onResume中的代码
override fun onResume() {
super.onResume()
{你自己的的JavaCameraView的名字}.connectCamera(width, height)
}
onResume中的代码
override fun onResume() {
super.onResume()
//这里的width和height是view的宽高,方便去获取一个最佳的展示的分辨率,毕竟你不想在一个小格子里展示4k图,也不想在一个大格子里展示160x120分辨率的图 by yinjun
{你自己的的JavaCameraView的名字}.connectCamera(width, height)
}
onPause中的代码
override fun onPause() {
super.onPause()
//临时关闭camera,别锁屏还一直录,小心烧了你那4k摄像头 by yinjun
{你自己的的JavaCameraView的名字}.cameraView.releaseCamera()
}
onDestroy中的代码
override fun onDestroy() {
super.onDestroy()
//直接释放摄像头,页面都没了,还要摄像头干嘛?by yinjun
{你自己的的JavaCameraView的名字}.cameraView.disableView()
}
做完上面的操作,运行到手机上,你的opencv就可以正常展示第一个图像。。。等等,似乎有一点点不对劲?
![请添加图片描述](https://img-blog.csdnimg.cn/a472609ad9e74433aa8b3df51d640aef.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd2VpeGluXzQ3NDkxNjY4,size_20,color_FFFFFF,t_70,g_se,x_16
这个东西,为啥是歪着的?看来得作一些小小的调优
二、opencv抓取画面调优
1.错误的角度调整
首先,是吧图片给转过来,让其可以正常展示图片,JavaCameraView中有一个监听方法setCvCameraViewListener,这个监听器除了能监听当前摄像头是开启还是关闭以外,它的onCameraFrame方法所返回的mat就是javaCameraView中展示的东西,吧这个mat旋转,展示正确的图像,需要注意的地方都写注释里了
代码如下(示例):
cameraView.setCvCameraViewListener(object : CameraBridgeViewBase.CvCameraViewListener2 {
override fun onCameraViewStarted(width: Int, height: Int) {
Log.e("hehe", "开始")
}
override fun onCameraViewStopped() {
Log.e("hehe", "结束")
}
override fun onCameraFrame(inputFrame: CameraBridgeViewBase.CvCameraViewFrame?): Mat {
var result: Mat? = null
//因为里面要干的事情有点多,这个回调又相当于子线程干完活要回主线程作展示,所以这里最好加个锁 by yinjun
synchronized(this) {
if (result != null) {
//先把图片摆正
var angle = 90
//这里注意一下,如果直接旋转90度,不做其他处理会导致调用前摄像头时直接上下翻转,所以要根据当前是不是前摄像头来改旋转值by yinjun
if (cameraView.getmCameraIndex() == CameraBridgeViewBase.CAMERA_ID_FRONT) {
angle = 270
}
//记得,吧你那图像的宽高一起改一下,不改?等着看扁扁图吧 by yinjun
var size = Size(result.width().toDouble(), result.height().toDouble())
Imgproc.warpAffine(result, result, Imgproc.getRotationMatrix2D(Point((result.width() / 2).toDouble(), (result.height() / 2).toDouble()), angle.toDouble(), -1.0), size)
}
}
//这个返回的mat就是你要用来展示的图像,你可用对其作其他更改,比如变灰,加框什么的操作之后再返回,但这就是后话了
return result!!
}
})
写到这里,肯定有人稍微有些蒙蔽,我的javaCameraView里没有getmCameraIndex啊,因为这个参在opencv哪里是一个私有的参,你需要自己去手写一个方法调取,写的也很简单,直接在javaCameraView中添加一个方法就可以了
public int getmCameraIndex(){
return mCameraIndex;
}
2.如何旋转摄像头
上面的注释里写了需要吧前摄转270°,可是opencv里似乎没有直接转摄像头的方法,怎么办?自己来办,直接准备一个按钮,为其配置以下点击事件
{你的按钮的名字}.setOnClickListener {
//现在是前摄,切回后摄,现在是后摄,切回前摄 by yinjun
if (cameraView.getmCameraIndex() == CameraBridgeViewBase.CAMERA_ID_FRONT) {
cameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK)
} else {
cameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT)
}
//设定完新的摄像头下标后,就可用停用,然后重启摄像头了 by yinjun
cameraView.releaseCamera();
cameraView.connectCamera(width, height)
}
结尾
上述操作完成后,你就可以正常使用opencv展示摄像头出现的图像了,并且自由切换前后摄像头了,opencv的mat的宽高是通过connectCamera(width, height)中传入的宽高,在你摄像头支持分辨率中找到一个最佳的分辨率,所以不需要担心我这8k摄像头的手机,会不会一直拿8k图像,读爆我的内存之类的,不会,至此,opencv部分的操作基本上就大功告成了,后面会说如何接入tensorflow以及如何用tensorflow-lite作人脸识别和口罩识别并展示出是否佩戴口罩
ps:本来早就准备好一起上,但opencv对人连带口罩时的读取识别度太低了,dlib表现不错,但dlib性能问题堪忧,而且还因为用的一个模型比较大,用在移动端上有点内存杀手的意思,所以选内存占用更小的tensorflow-lite,但tensorflowlite的人脸识别的模型构建我还没看,估计要一段时间了,可能会先出一个opencv读取人脸的教程混混?