0

我正在开发一个在 Android 和 IOS 上运行的移动应用程序。它能够实时处理视频流。在 Android 上,我通过 android.hardware.Camera.PreviewCallback.onPreviewFrame 获得相机的 Preview-Videostream。我决定使用 NV21 格式,因为所有 Android 设备都应该支持它,而 RGB 不支持(或者只是 RGB565)。

对于我的算法(主要用于模式识别),我需要灰度图像以及颜色信息。灰度不是问题,但从 NV21 到 BGR 的颜色转换耗时太长。

如上所述,我使用以下方法捕获图像;

在应用程序中,我覆盖了相机的 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 对象中获取数据作为本地引用。然后将其转换为 unsigned char* 字节流并调用以下 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 上它需要大约 30 毫秒,对于这样一个“微不足道”的预处理步骤来说,这是不可接受的。(我的分析方法经过双重检查并且可以正常工作以进行实时测量)

现在我正在拼命地寻找从 NV21 到 BGR 的颜色转换的更快实现。这是我已经做过的;

  1. 采用本主题提供的代码“convertYUV420_NV21toRGB8888”到C++ (转换时间的倍数)
  2. 将代码从 1 修改为仅使用整数运算(openCV-Solution 的转换时间加倍)
  3. 浏览了其他几个实现,都具有相似的转换时间
  4. 检查 OpenCV-Implementation,他们使用大量位移来获得性能。猜我自己不能做得更好

您是否有建议/知道好的实现,甚至有完全不同的方法来解决这个问题?我不知何故需要从 Android 相机捕获 RGB/BGR 帧,它应该可以在尽可能多的 Android 设备上工作。

感谢您的回复!

4

1 回答 1

1

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

于 2013-09-12T09:42:08.713 回答