在Android中使用OpenCV进行实时流视频处理

3
我们如何在Android平台上使用OpenCV(Opencv4Android)对从摄像头传来的实时视频帧执行某些基本的图像处理技术?

你遇到了什么问题? - Pervez Alam
你需要实现什么?根据任务的不同,这可能非常容易实现,也可能由于计算成本高昂的图像处理技术而变得痛苦。 - alvaro.delaserna
我需要访问和操作存储在Mat对象中的帧的各个像素值。 - user3836098
1个回答

8

提供这么少的信息,我们无法提供太多帮助。不过,我会发布一些代码,用于对相机流执行简单的图像处理技术:将帧转换为灰度。

您需要声明以下内容:

private CameraBridgeViewBase mOpenCvCameraView;
public CvCameraViewListener2 camListener;

接下来,您需要初始化OpenCV。在调用您的onCreate()方法之前,您需要添加以下代码块:

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
    @Override
    public void onManagerConnected(int status) {
        switch (status) {
        case LoaderCallbackInterface.SUCCESS:
        {
            Log.i("TAG", "OpenCV loaded successfully");
            mOpenCvCameraView.enableView();
            System.loadLibrary("nameOfYourNativeLibrary"); // if you are working with JNI
            run();
        } break;
        default:
        {
            super.onManagerConnected(status);
        } break;
        }
    }
};

您可以调用

if (!OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback)){
    Log.e("ERR", "Cannot connect to OpenCV Manager");
}else Log.i("SUCCESS", "opencv successfull");

你需要在onCreate()方法中编辑,但是你真正需要的是重写onResume()方法:

@Override
public void onResume()
{
    super.onResume();
    OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
    mOpenCvCameraView.enableView();
}

mOpenCvCameraView是一个JavaCameraView。如果您对此不熟悉,这是您的MainActivityxml布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:opencv="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.yourapp.MainActivity$PlaceholderFragment" >

<org.opencv.android.JavaCameraView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="visible"
    android:id="@+id/HelloOpenCvView"
    opencv:show_fps="false"
    opencv:camera_id="any" />

</RelativeLayout>

所以你的onCreate()方法应该像这样:
@Override
public void onCreate(Bundle savedInstanceState) {
    Log.i("APP", "called onCreate");
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.fragment_main);
    mOpenCvCameraView = (CameraBridgeViewBase)findViewById(R.id.HelloOpenCvView);
    if (!OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback)){
        Log.e("OPENCV", "Cannot connect to OpenCV Manager");
    }else Log.i("OPENCV", "opencv successfull");
}

在缺失的run()方法中,您应该添加想要执行的图像处理。在这种情况下,我们将把帧转换为灰度并显示它们:

private void run(){
    camListener = new CvCameraViewListener2() {

        @Override
        public void onCameraViewStopped() {
            // TODO Auto-generated method stub
        }

        @Override
        public void onCameraViewStarted(int width, int height) {
            // TODO Auto-generated method stub          
        }

        @Override
        public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
            rgb = inputFrame.rgba();
            // here you could just return inputframe.gray(), but for illustration we do the following
            Mat gray = new Mat();
            Imgproc.cvtColor(rgb, gray, Imgproc.COLOR_RGB2GRAY);
            return gray;
        }
    };

    mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
    mOpenCvCameraView.setCvCameraViewListener(camListener);

}

我希望这可以帮到你。如果你需要其他帮助,请告诉我。 更新 如果你想要访问一个Mat对象的像素值,你需要像这样做:
double mean = 0;
double size = mat.rows()*mat.cols();
for(int k=0; k<mat.rows(); k++){
    for(int j=0; j<mat.cols(); j++){
        mean += mat.get(k, j)[0]/size;
    }
}

请注意,在这种情况下,我的Mat对象只有一个通道(这意味着如果您尝试访问mat.get(k, j)[1],您将获得一个数组越界异常)。对于RGB Mat对象,您应该能够访问所有的mat.get(k, j)[0]mat.get(k, j)[1]mat.get(k, j)[2]

我需要访问和操作存储在Mat对象中的帧的各个像素值。谢谢! - user3836098
我已经编写了一个用于物体(识别)跟踪的算法,并希望使用OpenCV在Android上实现相同的功能。为此,我需要访问和操作像素(颜色)值。您能否帮助我解决这个问题?谢谢。 - user3836098
我在我的答案末尾添加了一些代码,其中包括如何访问Mat对象的像素值的示例。具体来说,我正在计算平均值。 - alvaro.delaserna
我猜mat.get()方法需要一些时间来获取像素值。谢谢! - user3836098

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接