OpenCV Android Вычитание Фона


Я работаю над робототехническим проектом, используя телефон Android в качестве основного процессора и камеры для обнаружения движения. Я получил бинарный пакет Android от OpenCV и правильно установил его. Я могу снимать изображения с помощью встроенной камеры OpenCV и выводить их на экран. Однако у меня возникли проблемы с использованием класса вычитания фона. Я могу создать новый объект BackgroundSubtractorMOG в конструкторе, но когда я пытаюсь запустить приведенный ниже код, он принудительно завершает работу. ошибка" только 1 - и 3-канальные 8-битные изображения поддерживаются в BackgroundSubtractorMOG " из собственного кода. Я попытался изменить Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA на Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB, и тогда это не заставит выйти, но все, что я получаю, это черный экран. Я почти уверен, что bmp по-прежнему null с FRAME_RGB, потому что экран остается черным, а счетчик 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;

Функция run() My SurfaceView:

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();
    }
}

Функция processFrame (), на которую ссылается run ():

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);
}
3 8

3 ответа:

Вы пробовали использовать cvtColor с CV_RGB2RGBA и CV_RGBA2RGB. Так, может быть, попробовать преобразовать кадр RGBA в RGB, а затем сделать вычитание фона. Что-то вроде этого:

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);
}

EDIT: вы можете проверить модульный тест OpenCV для BackgroundSubtractorMOG, расположенный здесь. Однако тест имеет fail("Not yet implemented"); в основном тестовом случае.

Я не уверен, означает ли это, что тест не завершен, или поддержка BackgroundSubtractorMOG не реализована. Вы можете попробовать запустить код, содержащийся в этом модульном тесте чтобы посмотреть, действительно ли это работает.

Также пример C++ segment_objects.cpp может быть полезен в качестве примера использования.

Надеюсь, это поможет! :)

Большое вам спасибо, ребята! И для будущих зрителей, которые придут на эту страницу, вам, возможно, придется изменить эти знания, чтобы заставить вещи работать. В SDK версии 2.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 версия, Возможно, вам придется использовать cvtcolor после вызова apply ():

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;
}

Также с последним openCV вам нужно инициализировать с помощью:

Private BackgroundSubtractorMOG2 Sub = Видео.createBackgroundSubtractorMOG2 ();