Java 如何通过JNI操作CameraPreview bytearray?(OpenCV)

Java 如何通过JNI操作CameraPreview bytearray?(OpenCV),java,android,c++,opencv,java-native-interface,Java,Android,C++,Opencv,Java Native Interface,在我的“public void onPreviewFrame(byte[]data,Camera-Camera){..}”中,我想获取bytearray“data”并将其传递给JNI并应用一些OpenCV过滤器,以便预览更改,而不返回它。 最好的方法是什么? 目前我只通过这样的通道: JNIEXPORT jint JNICALL Java_example_jnitest_Lib_filterfunc (JNIEnv * je, jclass jc, jbyteArray byteDa

在我的“public void onPreviewFrame(byte[]data,Camera-Camera){..}”中,我想获取bytearray“data”并将其传递给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);
注意:当前返回值为1,因此我希望将bytearray转换为Mat Obejct是可行的。但这不会更改预览,因为我不会将其更改回bytearray

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

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

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

有关更多信息,请参见以下问题:


您可以使用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包装器即可。

谢谢,先来点东西。然而,r=myMat.cols;返回0,因此即使它只是一个副本,我也应该能够将bytearray传递给JNI,并在不显示它的情况下进行一些处理(例如,返回某些像素的RGB值)。你知道那里出了什么问题吗。。。积分正确通过。CV_8UC4为8位,4个通道。但是,您从预览中获得的数据(默认情况下)将为NV21格式(请参阅我答案中的链接)。您需要将预览设置为使用其他格式,或者执行以下操作。这是一种平面格式,因此字节数组的第一部分将是每像素灰度1字节,因此在RGB转换正常之前,您可能可以使用CV_8UC1进行灰度图像。哦,对了,谢谢。。就这样。忽略了它是NV21。