将 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中将图像从Android发送到OpenCV Mat中的JNI的最有效方式
Android Camera App 使用 CameraX 将图像保存为 YUV_420_888 格式
将 YUV_420_888 转换为 JPEG 并保存文件导致图像失真