我正在尝试创建一个实时处理相机图像并在屏幕上显示它们的应用程序。我正在使用camera2 API。我创建了一个本机库来使用OpenCV处理图像。
到目前为止,我已设法设置一个ImageReader,接收YUV_420_888格式的图像。
mImageReader = ImageReader.newInstance(
mPreviewSize.getWidth(),
mPreviewSize.getHeight(),
ImageFormat.YUV_420_888,
4);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mImageReaderHandler);
从那里我可以获得图像平面(Y,U和V),获取它们的ByteBuffer对象并将它们传递给我的原生函数。这发生在mOnImageAvailableListener
:
Image image = reader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
Image.Plane YPlane = planes[0];
Image.Plane UPlane = planes[1];
Image.Plane VPlane = planes[2];
ByteBuffer YPlaneBuffer = YPlane.getBuffer();
ByteBuffer UPlaneBuffer = UPlane.getBuffer();
ByteBuffer VPlaneBuffer = VPlane.getBuffer();
myNativeMethod(YPlaneBuffer, UPlaneBuffer, VPlaneBuffer, w, h);
image.close();
在本机方面,我能够从缓冲区获取数据指针,从数据创建cv::Mat
并执行图像处理。
现在下一步是显示我的处理输出,但我不确定如何显示我处理过的图像。任何帮助将不胜感激。
答案 0 :(得分:4)
一般来说,您需要将处理后的图像数据发送到Android视图。
最高性能的选项是获取要绘制的android.view.Surface对象 - 您可以从SurfaceView(通过SurfaceHolder)或TextureView(通过SurfaceTexture)获取一个。然后你可以通过JNI将Surface传递给你的本机代码,并使用NDK方法:
使用setBuffersGeometry()配置输出大小,然后使用lock()获取ANativeWindow_Buffer。将您的图像数据写入ANativeWindow_Buffer.bits,然后使用unlockAndPost()发送缓冲区。
通常,您应该坚持使用RGBA_8888作为最兼容的格式;从技术上讲,只有它和其他两种RGB变体才得到官方支持。因此,如果您处理的图像是YUV,则需要先将其转换为RGBA。
您还需要确保输出视图的宽高比与您设置的尺寸的宽高比相匹配;默认情况下,Android的视图会将这些内部缓冲区缩放到输出视图的大小,可能会在此过程中将其拉伸。
您也可以将格式设置为Android内部YUV格式之一,但 保证无法正常工作!
答案 1 :(得分:0)
我已尝试过ANativeWindow方法,但设置起来很痛苦,我无法正确设置。最后,我放弃并导入了OpenCV4Android库,通过在后台将相机数据转换为RGBA Mat来简化操作。