【问题标题】:How to set a mask image for grabCut in OpenCV?如何在 OpenCV 中为 GrabCut 设置蒙版图像?
【发布时间】:2012-12-16 05:02:39
【问题描述】:

如何在 OpenCV 中为 grabCut 函数设置蒙版图像? 我想用选项做 GC_INIT_WITH_MASK

GC_BGD    = 0,
GC_FGD    = 1,
GC_PR_BGD = 2,
GC_PR_FGD = 3,

如果你能用 JavaCV 回答这个问题,那就太好了,因为我在 Scala/Java 中这样做。

【问题讨论】:

    标签: opencv javacv


    【解决方案1】:

    初始图像掩码是grabCut 的第二个参数,因此您应该能够使用CvMat.create() 创建图像,然后将值适当地设置为GC_BGD, GC_FGC, GC_PR_BGD, GC_PR_FGD,例如(无法在这台电脑):

    val mask = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1)
    // Set mask pixel values to what you want
    mask.put(offset, GC_BGD)
    ...
    grabCut(image, mask, ... <your other options here>)
    

    我对 javacv 不是最熟悉,可能有一种很好的方法来设置掩码的范围或块中的值,而不是一次设置一个像素。

    另外,根据docsgrabCut

    "注意GC_INIT_WITH_RECT和GC_INIT_WITH_MASK是可以组合的, 然后自动初始化 ROI 之外的所有像素 与 GC_BGD"

    【讨论】:

      【解决方案2】:

      OpenCV 中的工作示例:

      //Fill with the background value
      Mat mask = cv::Mat::ones(src.size(), CV_8U) * cv::GC_BGD;
      
      //Fill a smaller rectangle with the probably-foreground value.
      Rect area;
      area.x=10;  area.y=10;
      area.width=250; area.height=250;
      rectangle(mask, area , cv::Scalar(cv::GC_PR_FGD),-1,8,0);
      
      //Fill a smaller rectangle with the foreground value.
      area.x=50;  area.y=50;
      area.width=20;  area.height=20;
      rectangle(mask, area , cv::Scalar(cv::GC_FGD),-1,8,0);
      
      Mat bgd,fgd;
      cv::grabCut(src, mask, area, bgd, fgd, 1, cv::GC_INIT_WITH_MASK);
      
      //Visualize results.
      compare(mask,cv::GC_FGD,mask,cv::CMP_EQ);
      Mat foreground(src.size(),CV_8UC3, cv::Scalar(0,0,0));
      src.copyTo(foreground,mask);
      imshow("segm",foreground);
      

      【讨论】:

      • 嗯似乎不起作用。它只返回用 cv::GC_FGD 填充的区域
      • 原来GC_FGD区域没有被grabCut改变,GC_PR_BGD和GC_PR_FGD都改变了。
      【解决方案3】:
      public class ImageSegment {
      
          public static void main(String[] args) {
              System.loadLibrary("opencv_java244");
      
              Mat image = null;
              image = Highgui.imread("syh.jpg");
      
              Rect rectangle = new Rect(25,25,image.cols()-64,image.rows()-64);
              Mat result = new Mat();
              Mat bgdModel = new Mat();
              Mat fgdModel = new Mat();
              Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(3));
              Imgproc.grabCut(image, result, rectangle, bgdModel, fgdModel, 1, 0);
              Core.compare(result, source,result, Core.CMP_EQ);
              Mat foreground= new Mat(image.size(), CvType.CV_8UC1, new Scalar(0, 0, 0));
              image.copyTo(foreground, result);
              Highgui.imwrite("sucess1.jpg", foreground);
              System.out.println("grabcut sucess!");
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        输入图片(lena.png、lena_mask.png):

        代码(JAVA)

        import org.opencv.core.Core;
        import org.opencv.core.CvType;
        import org.opencv.core.Mat;
        import org.opencv.core.Rect;
        import org.opencv.core.Scalar;
        import org.opencv.highgui.Highgui;
        import org.opencv.imgproc.Imgproc;
        
        /**
         * Example how to use grabCut algorithm in OpenCV using GC_INIT_WITH_MASK.
         *
         */
        public class ImageSegmentByMask {
        
            public static void main(String[] args) {
                System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        
                // will read image
                Mat image = Highgui.imread("lena.png");
                Mat mask = Highgui.imread("lena_mask.png", Highgui.CV_LOAD_IMAGE_GRAYSCALE);
        
                Rect rectangle = new Rect(10, 10, image.cols() - 20, image.rows() - 20);
        
                Mat bgdModel = new Mat(); // extracted features for background
                Mat fgdModel = new Mat(); // extracted features for foreground
                Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(0));
        
                convertToOpencvValues(mask); // from human readable values to OpenCV values 
        
                int iterCount = 1;
                Imgproc.grabCut(image, mask, rectangle, bgdModel, fgdModel, iterCount, Imgproc.GC_INIT_WITH_MASK);
        
        
                convertToHumanValues(mask); // back to human readable values
                Imgproc.threshold(mask,mask,128,255,Imgproc.THRESH_TOZERO);
        
                Mat foreground = new Mat(image.size(), CvType.CV_8UC1, new Scalar(0, 0, 0));
                image.copyTo(foreground, mask);
        
                Highgui.imwrite("sandbox/sucess1.jpg", foreground);
            }
        
            private static void convertToHumanValues(Mat mask) {
                byte[] buffer = new byte[3];
                for (int x = 0; x < mask.rows(); x++) {
                    for (int y = 0; y < mask.cols(); y++) {
                        mask.get(x, y, buffer);
                        int value = buffer[0];
                        if (value == Imgproc.GC_BGD) {
                            buffer[0] = 0; // for sure background
                        } else if (value == Imgproc.GC_PR_BGD) {
                            buffer[0] = 85; // probably background
                        } else if (value == Imgproc.GC_PR_FGD) {
                            buffer[0] = (byte) 170; // probably foreground
                        } else {
                            buffer[0] = (byte) 255; // for sure foreground
        
                        }
                        mask.put(x, y, buffer);
                    }
                }
            }
        
            /**
             * Converts level of grayscale into OpenCV values. White - foreground, Black
             * - background.
             * 
             * @param mask
             */
            private static void convertToOpencvValues(Mat mask) {
                byte[] buffer = new byte[3];
                for (int x = 0; x < mask.rows(); x++) {
                    for (int y = 0; y < mask.cols(); y++) {
                        mask.get(x, y, buffer);
                        int value = buffer[0];
                        if (value >= 0 && value < 64) {
                            buffer[0] = Imgproc.GC_BGD; // for sure background
                        } else if (value >= 64 && value < 128) {
                            buffer[0] = Imgproc.GC_PR_BGD; // probably background
                        } else if (value >= 128 && value < 192) {
                            buffer[0] = Imgproc.GC_PR_FGD; // probably foreground
                        } else {
                            buffer[0] = Imgproc.GC_FGD; // for sure foreground
        
                        }
                        mask.put(x, y, buffer);
                    }
                }
        
            }
        
        }
        

        结果

        【讨论】:

        • 0,64,128,192 中的数字 convertToOpencvValues85,170,255 分别表示 convertToHumanValues 中的数字是多少?
        • 它们是蒙版中的阈值(如您所见,蒙版使用不同的灰度级别:白色=我绝对确定,它应该是我生成的片段的一部分,黑色=我不喜欢这些部分当然,浅灰度=在结果片段中可能是,深灰度=可能不在结果片段中)。灰度值范围为 0-255,范围为 0-85-170-255。
        猜你喜欢
        • 2017-07-17
        • 2014-08-29
        • 1970-01-01
        • 1970-01-01
        • 2011-11-20
        • 2020-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多