OpenCV - C++ Practical Combat (06) — Grabcut Image Segmentation

Table of contents

Chapter 6 Image Segmentation

6.1 Grabcut implementation

6.1.1 Defining foreground and background

6.1.2   cv::grabCut()

6.1.3 cv::compare()

6.1.4 Algorithm
implementation


Github code address: GitHub - Qinong/OpenCV

Chapter 6 Image Segmentation

        Opencv provides a commonly used image segmentation algorithm Grabcut. The Grabcut algorithm is relatively complex and requires a lot of calculations, but it has high accuracy.

6.1 Grabcut implementation

6.1.1 Defining foreground and background

        The usage of the cv::grabCut function is very simple. You only need to mark the input image as "belongs to the background" or "belongs to the front". Based on this local mark, the algorithm will calculate the foreground/background dividing line for the entire image.

        You can specify local foreground/background labels of the input image by defining a rectangle.

// 定义一个带边框的矩形
// 矩形外部的像素会被标记为背景
cv::Rect rectangle(100,120,650,350);

 

6.1.2   cv::grabCut()

        How the GrabCut algorithm works is: Reference article

Accepts an input image with either (1) a bounding box we want to segment or (2) a mask i.e. approximate segmentation involving the position of the object specified in the image

        Repeat these steps:

        Step 1: Estimate the color distribution of foreground and background via Gaussian Mixture Model (GMM)

        Step 2: Construct a Markov random field on the pixel labels (i.e., foreground vs. background)

        Step 3: Apply graph cut optimization for final segmentation

         GrabCut is an improved version of Graph Cut, an iterative Graph Cut. The GrabCut algorithm in OpenCV is implemented based on the article ""GrabCut" - Interactive Foreground Extraction using Iterated Graph Cuts". This algorithm utilizes the texture (color) information and boundary (contrast) information in the image, and can obtain better segmentation results with only a small amount of user interaction. Unlike Graph cut, which specifies two vertices, grabcut only needs to specify a rough border that can frame the target to complete a good segmentation.

        Although neural network segmentation has taken over the mainstream, in many cases such intensive training is not required, so GrabCut is also one of the options.

void grabCut( InputArray img, 
              InputOutputArray mask,
              Rect rect,                        
              InputOutputArray bgdModel, 
              InputOutputArray fgdModel,
              int iterCount, 
              int mode = GC_EVAL );
  • img: input image
  • mask: Get the mask matrix, whose values ​​are the following four

             cv::GC_BGD == 0//Indicates background

             cv::GC_FGD == 1//Indicates the foreground

              cv::GC_PR_BGD == 2//Indicates it may be background

              cv::GC_PR_FGD == 3//Indicates that it may be the foreground

  • rect: the specified matrix containing the target object
  • bdgModel: background model. If it is null, a bgdModel will be automatically created inside the function; bgdModel must be a single-channel floating point (CV_32FC1) image, and the number of rows can only be 1 and the number of columns can only be 13*5
  • fgdModel: Foreground model, if it is null, a fgdModel will be automatically created inside the function; fgdModel must be a single-channel floating point (CV_32FC1) image, and the number of rows can only be 1 and the number of columns can only be 13x5; (bgdModel, fgdModel can be in Used under cv::GC_INIT_WITH_MASK, you can continue to iterate based on the information they saved based on previous iterations)
  • iterCount: Specifies the number of iterations
  • mode: There are three values ​​available

          cv::GC_INIT_WITH_RECT//Initialize grabCut with matrix

          cv::GC_INIT_WITH_MASK//Initialize grabCut with mask

          cv::GC_EVAL//Perform splitting

6.1.3 cv::compare()

        cv:: compare () is mainly used to compare pixels between two images and output the comparison results. The specific usage is as follows:

bool cv::compare(cv::InputArray src1, // 输入数组1
                 cv::InputArray src2, // 输入数组2
                 cv::OutputArray dst, // 输出数组
                 int cmpop // 比较操作子,见注释 
  •     cmpop: comparison operator

        cv::CMP_EQ    src==src1
        cv::CMP_GT    src>src1
        cv::CMP_GE    src>=src1
        cv::CMP_LT    src<src1
        cv::CMP_LE    src<=src1
        cv::CMP_NE    src!=src1

6.1.4 Algorithm implementation

int main()
{
	cv::Mat image= cv::imread("Ferrar_F8.png");
	if (!image.data)
		return 0; 
	cv::namedWindow("Image");
	cv::imshow("Image",image);

	// 定义边框矩形
	cv::Rect rectangle(100,120,650,350);
	// 定义前景、背景和分割结果
	cv::Mat bgModel,fgModel,result; 

	// GrabCut分割
	cv::grabCut(image,
                result,
                rectangle,
                bgModel,
                fgModel, 
                5,        
                cv::GC_INIT_WITH_RECT); // use rectangle

	// 标记可能属于前景的区域
	cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);
	// or:
    //	result= result&1;

	// 创建前景图像
	cv::Mat foreground(image.size(), CV_8UC3, cv::Scalar(255, 255, 255));
	image.copyTo(foreground,result); // 复制前景图像

	// 在原图像绘制矩形区域
	cv::rectangle(image, rectangle, cv::Scalar(200,0,200),4);
	cv::namedWindow("Rectangle");
	cv::imshow("Rectangle",image);
	cv::namedWindow("Foreground");
	cv::imshow("Foreground",foreground);

	cv::waitKey();
	return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_41921826/article/details/129149125