书到用时方恨少,事非经过不知难。这篇文章主要讲述Android JNI:将cv :: Mat转换为jbyteArray相关的知识,希望能为你提供帮助。
我有C / C ++源代码(在Windows上运行良好)将输入帧转换为新帧。
现在我想将这个C / C ++源代码移植到我的android应用程序来转换设备Camera2的框架。
我将从java应用程序获得Camera2的连续byte []帧,然后将其输入到JNI以接收转换后的字节new_frame。
所以我在JNI的流程必须是:
- 将byte []框架从Java转换为JNI jarrayByte
- 将jarrayByte转换为jyte *
- 从jbyte *创建新的cv :: Mat原创*
- 将输入cv :: Mat orignal转换为使用C / C ++函数转换的新cv :: Mat
- 现在,我需要转换回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;
}
推荐阅读
- 如何在没有Android Studio的情况下编译JNI共享库,并在[关闭]中编译依赖项
- 如何在Android模拟器上显示Mat图像(使用NDK)
- 当SDL_init()时,FFmpeg2.3.3和SDL2-2.0.3的Android Media播放器出错。错误是关于SDL_main.h
- 使用Android Studio调试C ++库
- 如何将http C库正确包含到Android项目中()
- 如何调查随机Android原生函数调用错误()
- 从Android Activity onCreate方法调用QCoreApplication方法
- 如何使用/合并CPP文件到Android项目()
- Android JNI - 调用AttachCurrentThread而不使用DetachCurrentThread