OpenCV Grabcut выводит только то, что помечено как GC_FGD - PullRequest
0 голосов
/ 06 ноября 2019

Я использую JavaCV версии 3.4.2 вместе с Android SDK 27. Я пытаюсь сначала использовать grabcut с маской.

Вот мое входное изображение (слева) и маска (справа):

imageimage

Обратите внимание, что здесь я показываю маску с подложкой рубашки. Маска фактически вся черная, с зелеными отметками = GC_FGD и красным = GC_BGD.

Вот результат: (

image

Код, который запускает grabcut:

Mat mask = imageView.mask;

// Create ROI
Rect bounding_box = new Rect(0, 0, mask.cols(), mask.rows());

// extracted features for foreground & bg
Mat bgdModel = new Mat();
Mat fgdModel = new Mat();

// Get original image and convert from RGBA to RGB
Mat original_image = new Mat();
Utils.bitmapToMat(imageView.original_bitmap, original_image);
Imgproc.cvtColor(original_image, original_image, Imgproc.COLOR_RGBA2RGB);

// Do extraction
Imgproc.grabCut(original_image, mask, bounding_box, bgdModel, fgdModel,
        /*iterCount:*/1, Imgproc.GC_INIT_WITH_MASK);

Mat foreground = new Mat(original_image.size(), CvType.CV_8UC1,
        new Scalar(0, 0, 0));
Bitmap output_image = Bitmap.createBitmap(mask.cols(), mask.rows(),
        Bitmap.Config.ARGB_8888);
Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(0));

original_image.copyTo(foreground, mask);
Utils.matToBitmap(foreground, output_image);

Вот код, который создает маску(буквально рисует на ковре с помощью GC_BGD или GC_FGD в зависимости от того, какой цвет выбран в пользовательском интерфейсе. Зеленый - это fg, а красный - bg):

// I am thinking that the issue lies here. It is assuming all black is DEF bg. Idk how to circumvent this.
mask = new Mat (bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(Imgproc.GC_BGD)); 
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        byte[] buffer = new byte[3];
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                downx = getPointerCoords(event)[0];//event.getX();
                downy = getPointerCoords(event)[1];//event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                upx = getPointerCoords(event)[0];//event.getX();
                upy = getPointerCoords(event)[1];//event.getY();
                canvas.drawLine(downx, downy, upx, upy, paint);
                Imgproc.line(mask, new Point(downx, downy), new Point(upx, upy),
                        new Scalar(
                                paint.getColor() == Color.parseColor("#1de9b6") ?
                                        (byte)Imgproc.GC_FGD : (byte)Imgproc.GC_BGD
                        ), 10);
                invalidate();
                downx = upx;
                downy = upy;
                break;
            case MotionEvent.ACTION_UP:
                upx = getPointerCoords(event)[0];//event.getX();
                upy = getPointerCoords(event)[1];//event.getY();
                canvas.drawLine(downx, downy, upx, upy, paint);
                Imgproc.line(mask, new Point(downx, downy), new Point(upx, upy),
                        new Scalar(
                                paint.getColor() == Color.parseColor("#1de9b6") ?
                                (byte)Imgproc.GC_FGD : (byte)Imgproc.GC_BGD
                        ), 10);
                invalidate();
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }

1 Ответ

0 голосов
/ 07 ноября 2019

Мне удалось исправить мою проблему. Было много проблем с реализацией. Причина, по которой я вывел только выбранную строку GC_FDG, заключается в том, что все остальное в маске было GC_BGD. Вместо этого я изменил всю свою маску, чтобы она была заполнена GC_PR_BGD, а затем пометил детали с помощью GC_FDG и GC_BGD.

Это, наконец, создало другую маску, но результат остался прежним. Маска, сгенерированная GrabCut, была GC_FGD, которую я аннотировал, GC_PR_BGD, которая была автоматически сгенерирована grabcut (прогноз моего изображения), выбранным мной GC_BGD и всем остальным GC_PR_BGD.

Из-за этого я использовал Core.compare для генерации соответствующих масок. Мой обновленный код здесь:

Выполнение GrabCut:

// Get masked from the drawing we made
Mat mask = imageView.mask;

// Create ROI
Rect bounding_box = new Rect(10, 10, mask.cols()-10,
        mask.rows()-10);

// Get original image and convert from RGBA to RGB
Mat original_image = new Mat();
Utils.bitmapToMat(imageView.original_bitmap, original_image);
Imgproc.cvtColor(original_image, original_image, Imgproc.COLOR_RGBA2RGB);

// Do extraction
Imgproc.grabCut(original_image, mask, bounding_box, new Mat(), new Mat(),
        NUM_ITERATIONS, Imgproc.GC_INIT_WITH_MASK);

// New mask to hold ONLY what was marked GC_PR_FGD by grabcut on our mask.
Mat probable_fgd_mask = new Mat();
Core.compare(mask, new Scalar(Imgproc.GC_PR_FGD), probable_fgd_mask, Core.CMP_EQ);

// Reusing mask variable, store into mask only what was marked as GC_FGD
// inside of mask.
Core.compare(mask, new Scalar(Imgproc.GC_FGD), mask, Core.CMP_EQ);

// Combine both masks so that we have GC_FGD + GC_PR_FGD
Core.add(probable_fgd_mask, mask, mask);

// We will store the foreground into an all-black Mat,
Mat foreground = new Mat(original_image.size(), CvType.CV_8UC1,
        new Scalar(0, 0, 0));

// Copy the original image to 'foreground', but mask it with our newly created
// mask (GC_FGD + GC_PR_FGD)
original_image.copyTo(foreground, mask);

, и единственное изменение в коде, который создает маску, - это то, как мы создаем Мат:

ОТ:

mask = new Mat (bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(Imgproc.GC_BGD));

К:

mask = new Mat (bmp.getHeight(), bmp.getWidth(), CvType.CV_8U, new Scalar(Imgproc.GC_PR_BGD));

Надеюсь, это поможет кому-то еще :) Я застрял на этом полтора дня!

...