如何通过 JNI 操作 CameraPreview 字节数组?(公开简历)

How to manipulate CameraPreview bytearray through the JNI? (OpenCV)

本文关键字:数组 JNI 何通过 操作 CameraPreview 字节数 字节      更新时间:2023-10-16

>在我的"public void onPreviewFrame(byte[] data, Camera camera) { .... }"我想获取字节数组"数据"并将其传递给 JNI 并应用一些 OpenCV 过滤器,以便预览更改,而不返回它。最好的方法是什么?

目前我只像这样传递字节数组:

JNIEXPORT jint JNICALL Java_example_jnitest_Lib_filterfunc
      (JNIEnv * je, jclass jc, jbyteArray byteData){
    try {
         jbyte* _b_data= je->GetByteArrayElements(byteData, 0);
         int height = base;
         int width = base2;
         Mat mdata(height, width, CV_8UC4, (unsigned char *)_b_data);
         Mat myMat = imdecode(mdata,1);
         je->ReleaseByteArrayElements(byteData, _b_data, 0);
         return 1;
    } catch(const exception& ex){
        return 0;
    }
}

在 Java 代码中:

 public static native int filterfunc(byte[] byteData);

注意:目前返回值是一个,所以我希望将字节数组转换为 Mat Obejct 是有效的。但这不会更改预览,因为我不会将其更改回字节数组。

我想获取字节数组"数据"并将其传递给 JNI 并应用一些 OpenCV 过滤器,以便预览更改,而不返回它。

不幸的是,这是不可能的。传递给onPreviewFrame()的字节数组只是预览帧的副本,您对它所做的任何更改都不会显示在预览中。您可以通过修改 Java 中的字节数组作为测试来自己测试onPreviewFrame(),您不会看到任何效果。

如果要使用 OpenCV 更改预览帧数据并在预览窗口中查看结果,则需要将处理后的帧上传到 OpenGL 纹理,然后将其渲染到 GLSurfaceView,使用片段着色器将 NV21 数据转换为 RGB,或其他一些方法。简单地更改字节数组是行不通的。

有关详细信息,请参阅以下问题:

PreviewCallback onPreviewFrame 不更改数据

onPreviewFrame 不会更改数据

您可以使用 OpenCV 实现来访问相机。

下面是使用 OpenCV4android 的示例代码。

public class SampleCameraFrameAccessActivity extends Activity implements        CvCameraViewListener2, OnTouchListener{
private static final String  TAG = "SampleCameraFrameAccessActivity";
protected CameraBridgeViewBase cameraPreview;
protected Mat mRgba;
protected BaseLoaderCallback  mLoaderCallback = new BaseLoaderCallback(this) {
    @Override
    public void onManagerConnected(int status) {
        switch (status) {
            case LoaderCallbackInterface.SUCCESS:
            {
                Log.i(TAG, "OpenCV loaded successfully");
//                    mOpenCvCameraView.enableView();
//                    mOpenCvCameraView.setOnTouchListener(ColorRegionDetectionActivity.this);
                cameraPreview.enableView();
            } break;
            default:
            {
                super.onManagerConnected(status);
            } break;
        }
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.camera_sample_layout);
    cameraPreview = (CameraBridgeViewBase) findViewById(R.id.sample_test_camera_view);
    cameraPreview.setCvCameraViewListener(this);
}
@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
}
@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    if(cameraPreview != null){
        cameraPreview.disableView();
    }
}
@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
@Override
public void onCameraViewStarted(int width, int height) {
    // TODO Auto-generated method stub
    mRgba =  new Mat(height, width, CvType.CV_8UC4);
}
@Override
public void onCameraViewStopped() {
    // TODO Auto-generated method stub
    mRgba.release();
}
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    // TODO Auto-generated method stub
    mRgba = inputFrame.rgba();
    return mRgba;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
    // TODO Auto-generated method stub
    return false;
}

}

XML布局文件是:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/sample_test_layout" >
    <org.opencv.android.JavaCameraView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/sample_test_camera_view" />
</RelativeLayout>

在 onCameraFrame 方法中,您可以从相机的帧缓冲区访问每个帧。 如果你想应用OpenCV滤镜,你可以简单地将帧缓冲区传递给JNI或使用OpenCV4Android包装器来完成。