Opencv For Android: 如何显示摄像头预览
它是在 CameraBridgeBase 这个类里有一个 方法, deliverAndDrawFrame(CvCameraViewFrame ), 在这个函数里面, 它将CvCameraViewListener2 的onCameraFrame 返回的Mat 转换为 bitmap , 然后通过canvas画在 surfaceView 持有holder的 surface上。 注意,onCameraFrame是我们要具体去实现的接口, 而且也是我们处理图像主要战场 而我们也可以通过继承 deliverAndDrawFrame 这个方法来 通过opengl 加载bitmap纹理,显示图像到 opengl es绑定的surface上,。 深入一点, deliverAndDrawFrame 的参数 CvCameraViewFrame 怎么来的? 如果玩过 Android 摄像头的人都知道, 在initializeCamera 就是 打开摄像头和设置摄像头的地方, 显示摄像头也有两种方式: 1 通过 setPreviewDisplay(SurfaceHolder holder) 这种,一般与 SurfaceView搭配, 通过SurfaceView.getHolder() 2 通过 setPreviewTexture(SurfaceTexture surfaceTexture) 这种,一般与 OpenGL的 Surface搭配,根据 我的 另一篇博客, SurfaceView通过 Holder 可以得到Surface,而在Native层,通过ANativeWindow_fromSurface来获得本地的window窗口, 然后,通过于该window获取EGLDisplay连接,进而创建EGLSurface及EGLContext, 这样就与Opengl关联起来 而SurfaceTexture 是绑定了一个Texture, 因此,摄像头通过 EGLSurface将,数据写到Surface上,即这个Texture的buffer里面, Opengl 通过其draw方法,显示出图像预览来。 Camera的 PreviewCallback接口: PreviewCallback在 摄像头预览显示每一帧到Surface上时,会通过Copy一份,通过接口 public void onPreviewFrame(byte[] frame)来获得 其中, frame就是我们获取的图像数据, 在内存中按字节连续存放。获取的预览图像格式是yuv。 OpenCV 的mat矩阵: Mat类能够接收 byte[]数组, 在initializeCamera的 方法里面, 创建了两个Mat矩阵, mFrameChain[0], mFrameChain[1] 这两个Mat矩阵的目的是, 交替存放 PreviewCallback回掉回来的byte[] yuv数据。 CvCameraViewFrame: 是一个 Interface,里面提供了 转rgba, 和 gray的接口, 在继承的实现的子类里,JavaCameraFrame 接受了三个参数: Mat, width, height 其中, Mat接受, mFrameChain[0]或者mFrameChain[1] 而通过 JavaCameraFrame的 rgba, 和 gray可以将yuv 转换为rgb或者灰度图像。 与 我们实现算法的战场 onCameraFrame的关系: 上一步转换过来的 rgb或者灰度图像 传给 onCameraFrame,onCameraFrame处理后 给deiverAndDrawFrame 显示 如果用opengl ,如何实现,性能有哪些提高的猜想: 在获取数据方面: opengl es: 通过SurfaceTexture拿到 texture纹理 opencv: 通过 onPreviewCallback 拿到 byte[] 以上, gl是 16ms以内, onPreviewCallback需要30ms以上 在算法处理上: 都在native层实现 opengl: 在shader可以并行处理,每一点像素,就像PC端cuda一样。如果处理 opencv: Mat矩阵 需要两个for循环 但是算法上,opencv 大大优于 opengl的实现 opengl 实现会很复杂,具体问题具体以后再分析,这里只是稍微提下