如何通过JNI操作CameraPreview bytearray? (开放式简历)
How to manipulate CameraPreview bytearray through the JNI? (OpenCV)
在我的 "public void onPreviewFrame(byte[] data, Camera camera) { .... }" 中,我想获取字节数组 "data" 并将其传递给 JNI 并应用一些 OpenCV 过滤器,以便预览发生变化,而无需 return 正在处理它。
最好的方法是什么?
目前我只传递这样的字节数组:
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);
注意:目前 return 值为 1,所以我希望将 bytearray 转换为 Mat Obejct 是可行的。但这不会更改预览,因为我不会将其改回字节数组。
I want to take the bytearray "data" and pass it to the JNI and apply some OpenCV filters so that the preview changes, without returning it.
很遗憾,这是不可能的。传递给 onPreviewFrame()
的字节数组只是预览帧的一个副本,您对其所做的任何更改都不会显示在预览中。您可以通过修改 onPreviewFrame()
函数中 Java 中的字节数组作为测试来自己测试,您不会看到任何效果。
如果您想使用 OpenCV 更改预览帧数据并在预览中查看结果 window 那么您需要将处理后的帧上传到 OpenGL 纹理,然后将其渲染到 GLSurfaceView, using a fragment shader to convert the NV21 data 到 RGB,或其他一些方法。简单地更改字节数组是行不通的。
查看这些问题了解更多信息:
PreviewCallback onPreviewFrame does not change data
onPreviewFrame doesn't change the data
您可以使用 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 包装器即可。
在我的 "public void onPreviewFrame(byte[] data, Camera camera) { .... }" 中,我想获取字节数组 "data" 并将其传递给 JNI 并应用一些 OpenCV 过滤器,以便预览发生变化,而无需 return 正在处理它。 最好的方法是什么?
目前我只传递这样的字节数组:
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);
注意:目前 return 值为 1,所以我希望将 bytearray 转换为 Mat Obejct 是可行的。但这不会更改预览,因为我不会将其改回字节数组。
I want to take the bytearray "data" and pass it to the JNI and apply some OpenCV filters so that the preview changes, without returning it.
很遗憾,这是不可能的。传递给 onPreviewFrame()
的字节数组只是预览帧的一个副本,您对其所做的任何更改都不会显示在预览中。您可以通过修改 onPreviewFrame()
函数中 Java 中的字节数组作为测试来自己测试,您不会看到任何效果。
如果您想使用 OpenCV 更改预览帧数据并在预览中查看结果 window 那么您需要将处理后的帧上传到 OpenGL 纹理,然后将其渲染到 GLSurfaceView, using a fragment shader to convert the NV21 data 到 RGB,或其他一些方法。简单地更改字节数组是行不通的。
查看这些问题了解更多信息:
PreviewCallback onPreviewFrame does not change data
onPreviewFrame doesn't change the data
您可以使用 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 包装器即可。