将 YUV_420_888 中的图像从 Android 发送到 OpenCV Mat 中的 JNI 的最有效方法

Posted

技术标签:

【中文标题】将 YUV_420_888 中的图像从 Android 发送到 OpenCV Mat 中的 JNI 的最有效方法【英文标题】:Most Efficient way to send Image in YUV_420_888 from Android to JNI in OpenCV Mat 【发布时间】:2018-11-13 13:57:09 【问题描述】:

我有一个 android 应用程序,我想在其中对来自 android Camera2 API 的实时图像运行一些 OpenCV 图像处理。目前,如果我不做任何处理,我可以在 OnImageAvailble 函数中以 30 fps 的速度接收常规 1280x720 帧的图像。

现在,作为一个肮脏的黑客,我从 ImageReader 请求 JPEG 格式的图像,然后将位图传递给 jni,这大大降低了性能。

将 YUV 帧传递给 cv Mat 对象中的 jni 的最有效方法是什么。另外,我想将此帧转换为RGB 以进行进一步处理。我应该更改 Java 端的格式还是应该将 Mat 对象传递给 jni 并仅在此处转换颜色空间。

【问题讨论】:

可能的重复项:***.com/questions/9325861/… 和 ***.com/questions/30510928/…。选择您喜欢的答案。 您是否考虑过使用javaCV。 您可以使用 Utils.bitmapToMat 函数将您的位图直接转换为 Java 大小的 OpenCV Mat。 【参考方案1】:

出于显而易见的原因,您在 C++ 中执行的任何操作都比 Java 中的等价物快得多,包括 YUV 到 RGB 的转换(即使 Java 实现依赖于已编译的库)。

您可以通过 JNI 将 java 中现有 Mat 中的指针直接传递给 C++。假设我想使用 C++ 和 JNI 执行 Canny(),并且我有一个这样定义的 JNI 函数:

// In Java
public static native boolean nativeCanny(long iAddr);

注意 long iAddr 参数,它是指向我在 Java 中的 Mat 的直接指针。你可以这样调用它:

// In Java
nativeCanny(myImage.getNativeObjAddr());

这个函数在 C++ 中的实现会以与 this 类似的方式接收这个指针(如果这不起作用,用 jlong​​ 替换 long):

// In C++
JNIEXPORT jboolean JNICALL
VeryLongName_nativeCanny(JNIEnv *env, jobject instance, long iAddr) 
    cv::Mat* img = (cv::Mat*) iAddr;
    cv::Canny(*img, *img, 80, 100, 3);
    return true;

无论我对 img Mat 做了什么,也会发生在 java myImage Mat 中,毕竟它是一个指针,所以我们从未复制过。

据我所知,这是最快的。

【讨论】:

【参考方案2】:

也许对您有帮助:由于我们进行了大量图像处理,因此我们在公司为此编写了一个库。它不是用 C 语言编写的,但它的性能非常好。 转换后,您可以简单地将 Mat 指针通过 JNI 传递给您的 C 代码。

它将 YUV(标准 Android 相机格式 YUV_420_888)转换为 RGB Mats。此外,它还允许在转换之前对 YUV 进行有效剪辑(对于非常大的图像很重要,否则您需要转换整个图像,然后进行剪辑,这很昂贵)。用法很简单:

Mat mat = Yuv.toMat(image)

https://github.com/quickbirdstudios/yuvToMat

【讨论】:

以上是关于将 YUV_420_888 中的图像从 Android 发送到 OpenCV Mat 中的 JNI 的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

如何保存 YUV_420_888 图像?

在YUV_420_888中将图像从Android发送到OpenCV Mat中的JNI的最有效方式

Android Camera App 使用 CameraX 将图像保存为 YUV_420_888 格式

将 YUV_420_888 转换为 JPEG 并保存文件导致图像失真

在Android camera2下将YUV_420_888转换为位图的图像不正确

使用新的 Android camera2 api 从 YUV_420_888 进行 JPEG 编码时的绿色图像