Max*_*ysh 5 java macos android opencv android-emulator
我在使用Android模拟器和OpenCV时遇到了一个奇怪的问题CameraBridgeViewBase
.
使用onCameraFrame
我得到一张看起来没有正确解码的图片.
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
return inputFrame.rgba();
}
Run Code Online (Sandbox Code Playgroud)
使用'inputFrame.gray()'我得到了预期的结果 - 黑白图像没有文物或任何其他问题.
这就是我得到的:
到目前为止我尝试过的:
一切都在我真正的Android设备上按预期工作.
在查看了CameraBridgeViewBase
Java和Native相机类的来源之后,我决定在解码图像时出现问题.平台特定的相机输出格式(YUV,NV21)可能存在问题.然而,奇怪的是.gray()给出了一个合适的图像(没有工件).
如果重要的话,我正在使用带有"Facetime HD"相机的Mac OS X 10.10 Yosemite和MacBook Air.
任何关于如何克服这个问题并帮助找到问题根源的想法都非常感谢!
因此,在深入研究问题之后,我找到了问题的根源.
我们来看看OpenCV JavaCameraView
类及其CameraBridgeViewBase
基类.问题是byte[]
在onPreviewFrame
方法中作为数组接收的相机帧被错误地解码.
解码过程发生的代码的确切位置是Mat rgba()
内部JavaCameraFrame
类中的方法的实现JavaCameraView
:
public Mat rgba() {
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4);
return mRgba;
}
Run Code Online (Sandbox Code Playgroud)
如我们所见,Imgproc.cvtColor(...)方法用于将帧从YUV转换为RGBA.NV21 YUV -> RGBA
转换发生在那里.在初始化过程中,我们将格式设置为NV21,因此这应该是正确的.此外,每个Android设备都应该支持NV21.另外,我们可以使用调试器检查设备是否接受了格式:
protected boolean initializeCamera(int width, int height) {
...
params.setPreviewFormat(ImageFormat.NV21);
...
mCamera.setParameters(params);
...
params = mCamera.getParameters();
Log.d(TAG, String.format("Actual preview format is 0x%X", params.getPreviewFormat()));
}
Run Code Online (Sandbox Code Playgroud)
据报道,手机(HTC Sensation)和仿真器都使用NV21.
但是,如果我们COLOR_YUV2RGBA_NV21
改为COLOR_YUV2RGB_I420
(YV12和I420是相同的,只有Y和V反转;)我们将看到模拟器最终会得到一个合适的颜色空间.将NV21改为YV12 params.setPreviewFormat(ImageFormat.NV21);
我们会得到类似的结果.看起来像Imgproc.cvtColor或Android中的错误.
这是解决方案.
更改public Mat rgba()
以下方式:
public Mat rgba() {
if (previewFormat == ImageFormat.NV21) {
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4);
}
else if (previewFormat == ImageFormat.YV12) {
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_I420, 4); // COLOR_YUV2RGBA_YV12 produces inverted colors
}
return mRgba;
}
Run Code Online (Sandbox Code Playgroud)
previewFormat
它是一个新int
变量,它以这种方式声明:
private int previewFormat = ImageFormat.NV21;
Run Code Online (Sandbox Code Playgroud)
在初始化中添加以下更改:
protected boolean initializeCamera(int width, int height) {
...
params.setPreviewFormat(ImageFormat.NV21);
// "generic" = android emulator
if (Build.BRAND.equalsIgnoreCase("generic")) {
params.setPreviewFormat(ImageFormat.YV12);
}
...
mCamera.setParameters(params);
params = mCamera.getParameters();
previewFormat = params.getPreviewFormat();
...
}
Run Code Online (Sandbox Code Playgroud)
重要提示:
请注意:这只是一个临时解决方案,以便在我的情况下使OpenCV可以与模拟器一起使用.应该进行进一步的研究.检查设备是否在onPreviewFrame中使用正确的图像格式非常容易.我有时间的时候会回到这里.