我正在开发一个在Android和IOS上运行的移动应用程序。它能够实时处理视频流。在Android上,我通过android.hardware.Camera.PreviewCallback.onPreviewFrame获取相机的Preview-Videostream。我决定使用NV21格式,因为它应该得到所有Android设备的支持,而RGB不是(或只是RGB565)。
对于我的算法,主要用于模式识别,我需要灰度图像以及颜色信息。灰度不是问题,但从NV21到BGR的颜色转换时间过长。
如上所述,我使用以下方法捕获图像;
在App中,我覆盖了Camera的onPreviewFrame-Handler。这是在CameraPreviewFrameHandler.java中完成的:
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
{
try {
AvCore.getInstance().onFrame(data, _prevWidth, _prevHeight, AvStreamEncoding.NV21);
} catch (NativeException e)
{
e.printStackTrace();
}
}
然后,onFrame-Function调用一个本机函数,该函数从Java-Objects中获取数据作为本地引用。然后将其转换为unsigned char * bytestream并调用以下c ++函数,该函数使用OpenCV将NV21转换为BGR:
void CoreManager::api_onFrame(unsigned char* rImageData, avStreamEncoding_t vImageFormat, int vWidth, int vHeight)
{
// rImageData is a local JNI-reference to the java-byte-array "data" from onPreviewFrame
Mat bgrMat; // Holds the converted image
Mat origImg; // Holds the original image (OpenCV-Wrapping around rImageData)
double ts; // for profiling
switch(vImageFormat)
{
// other formats
case NV21:
origImg = Mat(vHeight + vHeight/2, vWidth, CV_8UC1, rImageData); // fast, only creates header around rImageData
bgrMat = Mat(vHeight, vWidth, CV_8UC3); // Prepare Mat for target image
ts = avUtils::gettime(); // PROFILING START
cvtColor(origImg, bgrMat, CV_YUV2BGRA_NV21);
_onFrameBGRConversion.push_back(avUtils::gettime()-ts); // PROFILING END
break;
}
[...APPLICATION LOGIC...]
}
正如人们可能从代码中的评论中得出的结论,我已经对转换进行了分析,结果证明我的Nexus 4需要大约30ms,这对于这样一个“微不足道”的预处理步骤来说是不可接受的。 (我的分析方法经过双重检查,可以正常进行实时测量)
现在我正在拼命寻找从NV21到BGR的这种颜色转换的更快实现。这就是我已经做过的事情;
您是否有建议/了解良好的实施方案,甚至有完全不同的方法来解决这个问题?我不知何故需要从Android-Camera捕获RGB / BGR帧,它应该可以在尽可能多的Android设备上运行。
感谢您的回复!
答案 0 :(得分:1)
你尝试过libyuv吗?我过去使用它,如果你用NEON支持编译它,它使用针对ARM处理器优化的asm代码,你可以从那里开始进一步优化你的特殊情况。