我可以使用 TextureView 同时显示相机预览和检测到的线吗?
Can I use TextureView to show the camera preview and detected line at the same time?
我想显示我实时检测到的相机和线(使用 i.MX6 和 Android 4.4)。我使用 Android 相机 .addCallbackBuffer 获取帧并使用 TextureView 显示相机预览。
JNI (C++) : 获取帧缓冲区->将 byte[] 转换为 Mat->然后使用 OpenCV 进行图像处理
JNI 可以 return Mat(使用 .getNativeObjAddr()) 已经在其上画线或 return 作为线的起点和终点的两个坐标
此代码在 JNI 中新建 Mat 并希望只是 return 两个坐标。如果此方法不起作用,我将在 JAVA 中新建 Mat 并将 .getNativeObjAddr() 发送到 JNI,然后 return Mat。在 TextureView 中显示垫子?
问题:
如何使用TextureView同时显示相机预览和检测线?
在MainActivity.java
public class MainActivity extends Activity implements TextureView.SurfaceTextureListener, PreviewCallback {
protected Camera mCamera;
private TextureView mTextureView;
public byte[][] cameraBuffer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
setContentView(mTextureView);
}
....
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open(0);
int bufferSize = mCamera.getParameters().getPictureSize().width * mCamera.getParameters().getPictureSize().height
* ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat()) / 8;
cameraBuffer = new byte[3][bufferSize];
thread = new getFrameThread( this, kCameraWidth, kCameraHeight);
for (int i = 0; i < 3; ++i)
mCamera.addCallbackBuffer(cameraBuffer[i]);
mCamera.setPreviewCallbackWithBuffer(this);
thread.start();
if (mCamera == null) {
throw new RuntimeException("Default camera not available");
}
try {
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
} catch (IOException ioe) {
// Something bad happened
}
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
camera.addCallbackBuffer(data);//callback data to cameraBuffer
thread.refresh(data, countFrame);//send new frame data to JNI
}
....
static {
System.loadLibrary("opencv_java"); //load opencv_java lib
System.loadLibrary("testLib");
}
public native void getRawFrame(byte[] data,int width, int height, int count);
}
在getFrameThread中(线程到运行 JNI函数'getRawFrame')
public class getFrameThread extends Thread{
public byte[] data;
{
.....
mainActivity.getRawFrame(data, 480, 720);
.....
}
public void refresh(byte[] data, int countFrame){
this.data = data;
}
}
在 JNI 中
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace cv;
extern"C"
{
.....
JNIEXPORT void JNICALL Java_com_example_adas_MainActivity_getRawFrame( JNIEnv* env, jobject thisobject,
jbyteArray data, jint width, jint height){
int length = env->GetArrayLength(data);
unsigned char *bufferIn = (unsigned char*) env->GetPrimitiveArrayCritical(data, NULL);
yuvMat = Mat(height * 3/2, width, CV_8UC1, bufferIn);
cvtColor(yuvMat, grayMat, cv::COLOR_YUV2GRAY_I420);
//Do lines detected
.....
env->ReleasePrimitiveArrayCritical(data, bufferIn, JNI_ABORT);
}
你可以用图像视图覆盖相机实时TextureView,让这个图像部分透明是可以的。但这不是增强现实的好解决方案。原因是从 OpenCV 生成的内容带有延迟。这种延迟可能不是很明显,但对用户来说可能非常烦人。
如果隐藏实时摄像头流并显示由 OpenCV 处理更改的图像(来自 onPreviewFrame()
),结果会更好。屏幕上显示的 AR 会延迟几毫秒(与相机实时取景相比),但场景会与检测到的线条一致。我在这个 blog post.
中找到了一个很好的例子(和详细的编程说明)
您仍然需要 TextureView,因为 Android 相机 API 要求您有实时预览以接收 onPreviewFrame()
回调。要隐藏它,您可以将其与其他视图叠加,或在 OpenGL 级别上操作纹理。
您还可以使用 OpenGL 来显示 OpenCV 的结果:通常这种工作流程的性能比使用其他方式显示图像要好得多。
您也可以使用 OpenGL 绘制线条 - OpenCV 处理的结果 - 不是 位图 的形式,并将相机预览用作单独的纹理。
我想显示我实时检测到的相机和线(使用 i.MX6 和 Android 4.4)。我使用 Android 相机 .addCallbackBuffer 获取帧并使用 TextureView 显示相机预览。
JNI (C++) : 获取帧缓冲区->将 byte[] 转换为 Mat->然后使用 OpenCV 进行图像处理
JNI 可以 return Mat(使用 .getNativeObjAddr()) 已经在其上画线或 return 作为线的起点和终点的两个坐标
此代码在 JNI 中新建 Mat 并希望只是 return 两个坐标。如果此方法不起作用,我将在 JAVA 中新建 Mat 并将 .getNativeObjAddr() 发送到 JNI,然后 return Mat。在 TextureView 中显示垫子?
问题: 如何使用TextureView同时显示相机预览和检测线?
在MainActivity.java
public class MainActivity extends Activity implements TextureView.SurfaceTextureListener, PreviewCallback {
protected Camera mCamera;
private TextureView mTextureView;
public byte[][] cameraBuffer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
setContentView(mTextureView);
}
....
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open(0);
int bufferSize = mCamera.getParameters().getPictureSize().width * mCamera.getParameters().getPictureSize().height
* ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat()) / 8;
cameraBuffer = new byte[3][bufferSize];
thread = new getFrameThread( this, kCameraWidth, kCameraHeight);
for (int i = 0; i < 3; ++i)
mCamera.addCallbackBuffer(cameraBuffer[i]);
mCamera.setPreviewCallbackWithBuffer(this);
thread.start();
if (mCamera == null) {
throw new RuntimeException("Default camera not available");
}
try {
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
} catch (IOException ioe) {
// Something bad happened
}
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
camera.addCallbackBuffer(data);//callback data to cameraBuffer
thread.refresh(data, countFrame);//send new frame data to JNI
}
....
static {
System.loadLibrary("opencv_java"); //load opencv_java lib
System.loadLibrary("testLib");
}
public native void getRawFrame(byte[] data,int width, int height, int count);
}
在getFrameThread中(线程到运行 JNI函数'getRawFrame')
public class getFrameThread extends Thread{
public byte[] data;
{
.....
mainActivity.getRawFrame(data, 480, 720);
.....
}
public void refresh(byte[] data, int countFrame){
this.data = data;
}
}
在 JNI 中
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace cv;
extern"C"
{
.....
JNIEXPORT void JNICALL Java_com_example_adas_MainActivity_getRawFrame( JNIEnv* env, jobject thisobject,
jbyteArray data, jint width, jint height){
int length = env->GetArrayLength(data);
unsigned char *bufferIn = (unsigned char*) env->GetPrimitiveArrayCritical(data, NULL);
yuvMat = Mat(height * 3/2, width, CV_8UC1, bufferIn);
cvtColor(yuvMat, grayMat, cv::COLOR_YUV2GRAY_I420);
//Do lines detected
.....
env->ReleasePrimitiveArrayCritical(data, bufferIn, JNI_ABORT);
}
你可以用图像视图覆盖相机实时TextureView,让这个图像部分透明是可以的。但这不是增强现实的好解决方案。原因是从 OpenCV 生成的内容带有延迟。这种延迟可能不是很明显,但对用户来说可能非常烦人。
如果隐藏实时摄像头流并显示由 OpenCV 处理更改的图像(来自 onPreviewFrame()
),结果会更好。屏幕上显示的 AR 会延迟几毫秒(与相机实时取景相比),但场景会与检测到的线条一致。我在这个 blog post.
您仍然需要 TextureView,因为 Android 相机 API 要求您有实时预览以接收 onPreviewFrame()
回调。要隐藏它,您可以将其与其他视图叠加,或在 OpenGL 级别上操作纹理。
您还可以使用 OpenGL 来显示 OpenCV 的结果:通常这种工作流程的性能比使用其他方式显示图像要好得多。
您也可以使用 OpenGL 绘制线条 - OpenCV 处理的结果 - 不是 位图 的形式,并将相机预览用作单独的纹理。