8

我正在开发一个机器人项目,使用 Android 手机作为主处理器和摄像头来检测运动。我从 OpenCV 获得了 Android 二进制包并正确安装。我可以使用 OpenCV 原生相机捕捉图像并将它们显示到屏幕上。不过,我在使用背景减法类时遇到了问题。我可以在构造函数中创建一个新的 BackgroundSubtractorMOG 对象,但是当我尝试运行下面的代码时,它会强制退出我从本机代码中收到错误“BackgroundSubtractorMOG 仅支持 1 通道和 3 通道 8 位图像”。我尝试将 Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA 更改为 Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB,然后它不会强制退出,但我得到的只是黑屏。我很确定 FRAME_RGB 的 bmp 仍然为空,因为屏幕保持黑色,并且我在位图之后立即绘制的 fps 计数器(为清楚起见并作为故障排除步骤从下面发布的代码中删除)没有出现。

我查看了此函数的 OpenCV C++ 代码(此处为第 388 行),如果图像类型不是 CV_8UC1 或 CV_8UC3,则会出现图像类型错误,因此我尝试使用 java CvType.CV_8UC3 而不是 Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA capture.retrieve(),但它强制关闭,我收到“不支持输出帧格式”错误。

我猜我刚刚遇到了类型转换问题,但我一生都无法弄清楚 OpenCV 的 Android 特定图像类型与记录的常规图像类型在哪里匹配。任何帮助,将不胜感激。

变量:

private SurfaceHolder mHolder;
private VideoCapture mCamera;
private Mat mRgba;
private Mat mFGMask;
private BackgroundSubtractorMOG mBGSub;

我的 SurfaceView 的 run() 函数:

public void run() {    
    Bitmap bmp = null;

    synchronized (this) {
        if (mCamera == null)
            break;

        if (!mCamera.grab()) {
            Log.e(TAG, "mCamera.grab() failed");
            break;
        }

        processFrame(mCamera);
        bmp = Bitmap.createBitmap(mFGMask.cols(), mFGMask.rows(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(mFGMask, bmp);
    }

    if (bmp != null) {
        Canvas canvas = mHolder.lockCanvas();
        if (canvas != null) {
            canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, (canvas.getHeight() - bmp.getHeight()) / 2, null);
            mHolder.unlockCanvasAndPost(canvas);
        }
        bmp.recycle();
    }
}

run() 中引用的 processFrame() 函数:

protected void processFrame(VideoCapture capture) {
    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
    mBGSub.apply(mRgba, mFGMask);
}

编辑:

最终工作的解决方案:

protected void processFrame(VideoCapture capture) {
    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB);
    //GREY_FRAME also works and exhibits better performance
    //capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_GREY_FRAME);
    mBGSub.apply(mRgba, mFGMask, 0.1);
    Imgproc.cvtColor(mFGMask, mRgba, Imgproc.COLOR_GRAY2BGRA, 4);
}
4

3 回答 3

4

您是否尝试过使用cvtColor和. 因此,也许尝试将帧 RGBA 转换为 RGB,然后进行背景减法。像这样的东西:CV_RGB2RGBACV_RGBA2RGB

protected void processFrame(VideoCapture capture) {
    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
    Mat rgb;
    Imgproc.cvtColor(mRgba, rgb, Imgproc.COLOR_RGBA2RGB);
    mBGSub.apply(rgb, mFGMask);
}

编辑:您可以查看BackgroundSubtractorMOG位于此处的 OpenCV 单元测试。但是,测试已经fail("Not yet implemented");在主测试用例中。

我不确定这是否意味着测试没有完成,或者BackgroundSubtractorMOG没有实现对的支持。您可以尝试运行此单元测试中包含的代码,看看它是否真的有效。

此外,C++ 示例segment_objects.cpp作为使用示例可能会有所帮助。

希望有帮助!:)

于 2012-02-12T05:48:37.457 回答
2

非常感谢你们!对于访问此页面的未来观众,您可能需要调整这些知识才能使事情正常进行。在 SDK v2.4.4 中,我在 onCameraFrame 方法中应用了它。回想一下,该方法从相机获取输入帧。您使用输入并返回要在您的 android 设备屏幕上显示的帧。这是一个例子:

//Assume appropriate imports    
private BackgroundSubtractorMOG sub = new BackgroundSubtractorMOG(3, 4, 0.8);
private Mat mGray = new Mat();
private Mat mRgb = new Mat();
private Mat mFGMask = new Mat();

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    mGray = inputFrame.gray(); //I chose the gray frame because it should require less resources to process
    Imgproc.cvtColor(mGray, mRgb, Imgproc.COLOR_GRAY2RGB); //the apply function will throw the above error if you don't feed it an RGB image
    sub.apply(mRgb, mFGMask, learningRate); //apply() exports a gray image by definition

    return mFGMask;
}

为了理解我关于 apply() 产生的灰色图像的观点,如果你想做一个 RGBA 版本,你可能必须在调用 apply() 之后使用 cvtcolor:

private Mat mRgba = new Mat();

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    mRgba = inputFrame.rgba();
    Imgproc.cvtColor(mRgba, mRgb, Imgproc.COLOR_RGBA2RGB); //the apply function will throw the above error if you don't feed it an RGB image
    sub.apply(mRgb, mFGMask, learningRate); //apply() exports a gray image by definition
    Imgproc.cvtColor(mFGMask, mRgba, Imgproc.COLOR_GRAY2RGBA);

    return mRgba;
}
于 2013-03-05T07:24:12.240 回答
0

同样使用最新的openCV,您需要初始化:

私有BackgroundSubtractorMOG2 Sub = Video.createBackgroundSubtractorMOG2();

于 2016-02-10T05:45:45.913 回答