Android JNI(将cv :: Mat转换为jbyteArray)

书到用时方恨少,事非经过不知难。这篇文章主要讲述Android JNI:将cv :: Mat转换为jbyteArray相关的知识,希望能为你提供帮助。
我有C / C ++源代码(在Windows上运行良好)将输入帧转换为新帧。
现在我想将这个C / C ++源代码移植到我的android应用程序来转换设备Camera2的框架。
我将从java应用程序获得Camera2的连续byte []帧,然后将其输入到JNI以接收转换后的字节new_frame。
所以我在JNI的流程必须是:

  1. 将byte []框架从Java转换为JNI jarrayByte
  2. 将jarrayByte转换为jyte *
  3. 从jbyte *创建新的cv :: Mat原创*
  4. 将输入cv :: Mat orignal转换为使用C / C ++函数转换的新cv :: Mat
  5. 现在,我需要转换回cv :: Mat转换为jByteArray以返回Java函数=> 我正在坚持这一步
所以我的问题是如何将cv :: mat转换回jbyteArray以返回Java层的应用程序?
extern "C" JNIEXPORT jbyteArray JNICALL Java_com_xyz_NativeUtil_convertFrame(JNIEnv *env, jobject obj, jbyteArray yuvFrame) { // convert jByteArray to jbyte* jbyte* yuvByte = env-> GetByteArrayElements(yuvFrame, 0); // convert jbyte* to cv::Mat cv::Mat frame_original_yuv = cv::Mat(height + height/2, width, CV_8UC1, yuvByte); // convert YUV cv::Mat to RGBA cv::Mat cv::Mat frame_original_rgba = cv::Mat(height, width, CV_8UC4); cv::cvtColor(frame_original_yuv, frame_original_rgba, CV_YUV2RGBA_NV21); env-> ReleaseByteArrayElements(yuvFrame, yuvByte, 0); // convert frame cv::Mat frame_converted = convert_frame(frame_original_rgba); frame_original_yuv.release(); if (frame_converted .empty()) { frame_converted = frame_original_rgba; } frame_original_rgba.release(); // convert cv::Mat to jbyteArray jbyteArray result = ???return result;

}
我的Java代码:
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Image image = reader.acquireLatestImage(); if (image == null) return; Image.Plane Y = image.getPlanes()[0]; Image.Plane U = image.getPlanes()[1]; Image.Plane V = image.getPlanes()[2]; int Yb = Y.getBuffer().remaining(); int Ub = U.getBuffer().remaining(); int Vb = V.getBuffer().remaining(); byte[] yuvFrame = new byte[Yb + Ub + Vb]; Y.getBuffer().get(yuvFrame, 0, Yb); U.getBuffer().get(yuvFrame, Yb, Ub); V.getBuffer().get(yuvFrame, Yb + Ub, Vb); image.close(); } }, mBackgroundHandler);

答案让我们假设您要将本机cv::Mat对象传递给Java并将其转换为Bitmap
在这种情况下,最好将其转换为jintArray,所以我将使用它编写一个示例,但您可以轻松修改该代码以使用jbyteArray代替
【Android JNI(将cv :: Mat转换为jbyteArray)】请注意,在该代码中,我假设您的cv::Mat有4个通道(bgra),相应地进行更改。如果您的垫子是灰色的 - 将r, g, b设置为相同的灰色,并将a设置为255.如果您的垫子是bgr- 将a设置为255。
jintArray matToBitmapArray(JNIEnv *env, const cv::Mat & image) { jintArray resultImage = env-> NewIntArray(image.total()); jint *_data = https://www.songbingjia.com/android/new jint[image.total()]; for (int i = 0; i < image.total(); i++) { char r = image.data[4 * i + 2]; char g = image.data[4 * i + 1]; char b = image.data[4 * i + 0]; char a = image.data[4 * i + 3]; _data[i] = (((jint) a < < 24) & 0xFF000000) + (((jint) r < < 16) & 0x00FF0000) + (((jint) g < < 8) & 0x0000FF00) + ((jint) b & 0x000000FF); } env-> SetIntArrayRegion(resultImage, 0, image.total(), _data); delete[]_data; return resultImage; }

BGR案例:
jintArray matToBitmapArray(JNIEnv *env, const cv::Mat & image) { jintArray resultImage = env-> NewIntArray(image.total()); jint *_data = https://www.songbingjia.com/android/new jint[image.total()]; for (int i = 0; i < image.total(); i++) { char r = image.data[3 * i + 2]; char g = image.data[3 * i + 1]; char b = image.data[3 * i + 0]; char a = (char)255; _data[i] = (((jint) a < < 24) & 0xFF000000) + (((jint) r < < 16) & 0x00FF0000) + (((jint) g < < 8) & 0x0000FF00) + ((jint) b & 0x000000FF); } env-> SetIntArrayRegion(resultImage, 0, image.total(), _data); delete[]_data; return resultImage; }

灰色案例:
jintArray matToBitmapArray(JNIEnv *env, const cv::Mat & image) { jintArray resultImage = env-> NewIntArray(image.total()); jint *_data = https://www.songbingjia.com/android/new jint[image.total()]; for (int i = 0; i < image.total(); i++) { // Note that you can use better gray-> rgba conversion char r = image.data[i]; char g = image.data[i]; char b = image.data[i]; char a = (char)255; _data[i] = (((jint) a < < 24) & 0xFF000000) + (((jint) r < < 16) & 0x00FF0000) + (((jint) g < < 8) & 0x0000FF00) + ((jint) b & 0x000000FF); } env-> SetIntArrayRegion(resultImage, 0, image.total(), _data); delete[]_data; return resultImage; }

而在java方面
Bitmap bitmap = Bitmap.createBitmap(ourNativeArray, width, height, Bitmap.Config.ARGB_8888);

编辑
考虑到你有BGRA 4通道图像,这里是你如何将它转换为jbyteArray
jbyteArray matToByteArray(JNIEnv *env, const cv::Mat & image) { jbyteArray resultImage = env-> NewByteArray(image.total() * 4); jbyte *_data = https://www.songbingjia.com/android/new jbyte[image.total() * 4]; for (int i = 0; i < image.total() * 4; i++) { _data[i] = image.data[i]; } env-> SetByteArrayRegion(resultImage, 0, image.total() * 4, _data); delete[]_data; return resultImage; }


    推荐阅读