【问题标题】:OpenCV Grabcut outputs only what is marked as GC_FGDOpenCV Grabcut 仅输出标记为 GC_FGD 的内容
【发布时间】:2020-03-02 17:59:30
【问题描述】:

我正在使用 JavaCV 版本 3.4.2 和 Android SDK 27。我正在尝试先使用带有蒙版的抓取。

这是我的输入图像(左)和蒙版(右):

请注意,这里我展示的是带有衬衣的面具。面具实际上是全黑的,绿色标记为 = GC_FGD 和红色 = GC_BGD。

结果如下:(

运行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);

以下是创建遮罩的代码(字面意思是使用 wither GC_BGD 或 GC_FGD 绘制到垫子上,具体取决于在 UI 上选择了哪种颜色。绿色是 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;
        }

【问题讨论】:

  • /*iterCount:*/1 似乎很可疑......使用更多迭代怎么样?
  • @Miki 我把它改成了10次迭代,结果是一样的。 Here is the result.
  • Question 看起来相关。

标签: java android opencv image-processing computer-vision


【解决方案1】:

我能够解决我的问题。实施存在多个问题。我的输出只是选定的GC_FDG 行的原因是掩码中的其他所有内容都是GC_BGD。我将我的所有面具都改为用GC_PR_BGD 填充,然后用GC_FDGGC_BGD 注释这些部分。

这最终创建了一个不同的掩码,但输出仍然相同。 GrabCut生成的掩码是我注释的GC_FGD,由grabcut(预测我的图像是什么)自动生成的GC_PR_BGD,我选择的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);

创建遮罩的代码的唯一变化是我们如何创建 Mat:

来自:

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

希望这对其他人有帮助 :) 我被困了一天半!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-17
    • 1970-01-01
    相关资源
    最近更新 更多