YUV(NV21)到移动设备上的BGR转换(本地代码)

时间:2013-09-12 09:08:32

标签: android c++ opencv yuv bgr

我正在开发一个在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的这种颜色转换的更快实现。这就是我已经做过的事情;

  1. 将代码“convertYUV420_NV21toRGB8888”通过C ++提供in this topic(转换时间的倍数)
  2. 修改了1中的代码,仅使用整数运算(openCV-Solution的转换时间加倍)
  3. 浏览了几个其他实现,所有实现都有类似的转换时间
  4. 检查OpenCV-Implementation,他们使用大量的位移来获得性能。猜猜我自己无法做得更好
  5. 您是否有建议/了解良好的实施方案,甚至有完全不同的方法来解决这个问题?我不知何故需要从Android-Camera捕获RGB / BGR帧,它应该可以在尽可能多的Android设备上运行。

    感谢您的回复!

1 个答案:

答案 0 :(得分:1)

你尝试过libyuv吗?我过去使用它,如果你用NEON支持编译它,它使用针对ARM处理器优化的asm代码,你可以从那里开始进一步优化你的特殊情况。