opencv學習之路(31)、GrabCut & FloodFill圖像分割

1、GrabCut

一、利用Rect作分割

#include "opencv2/opencv.hpp"
using namespace cv;

void main()
{
    Mat src = imread("E://bird.jpg");
    Rect rect(84, 84, 406, 318);//左上座標(X,Y)和長寬
    Mat result, bg, fg;

    grabCut(src, result, rect, bg, fg, 1, GC_INIT_WITH_RECT);
    imshow("grab", result);
    /*threshold(result, result, 2, 255, CV_THRESH_BINARY);
    imshow("threshold", result);*/

    compare(result, GC_PR_FGD, result, CMP_EQ);//result和GC_PR_FGD對應像素相等時,目標圖像該像素值置爲255
    imshow("result",result);
    Mat foreground(src.size(), CV_8UC3, Scalar(255, 255, 255));
    src.copyTo(foreground, result);//copyTo有兩種形式,此形式表示result爲mask
    imshow("foreground", foreground);
    waitKey(0);
}

grab並不是是全黑圖像,對其使用二值化後能看到低像素值的狀況 ios

二、利用mask作分割

#include "opencv2/opencv.hpp"
using namespace cv;

void main()
{
    Mat src = imread("E://bird.jpg");
    //Rect rect(84, 84, 406, 318);
    Rect rect;
    Mat bgModel, fgModel;
    Mat result(src.size(), CV_8U, Scalar(0));
    Mat ROI(result(Rect(84, 84, 406, 318)));
    ROI.setTo(GC_PR_FGD);//ROI設置爲多是前景

    grabCut(src, result, rect, bgModel, fgModel, 1, GC_INIT_WITH_MASK);
    //threshold(result, result, 2, 255, CV_THRESH_BINARY);
    imshow("grab", result);
    compare(result, GC_PR_FGD, result, CMP_EQ);
    //result = result&1;
    imshow("result", result);
    Mat foreground(src.size(), CV_8UC3, Scalar(255, 255, 255));
    src.copyTo(foreground, result);
    imshow("foreground", foreground);

    waitKey(0);
}

 

 

 2、漫水填充算法——floodFill

#include "opencv2/opencv.hpp"
using namespace cv;

void main()
{
    Mat src = imread("E://bird.jpg");
    imshow("src", src);
    Rect rect;
    //原圖,種子點,新顏色,重繪區域的最小邊界矩形,負差,正差
    floodFill(src, Point(20,20), Scalar(255, 0, 0), &rect, Scalar(10, 10, 10), Scalar(10, 10, 10));
    imshow("result", src);
    waitKey(0);
}

 

3、綜合應用(代碼來自淺墨大神)

  1 #include "opencv2/opencv.hpp"
  2 #include <iostream>
  3 using namespace std;
  4 using namespace cv;
  5 
  6 Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage;//定義原始圖、目標圖、灰度圖、掩模圖  
  7 int g_nFillMode = 1;//漫水填充的模式  
  8 int g_nLowDifference = 20, g_nUpDifference = 20;//負差最大值、正差最大值  
  9 int g_nConnectivity = 4;//表示floodFill函數標識符低八位的連通值  
 10 int g_bIsColor = true;//是否爲彩色圖的標識符布爾值  
 11 bool g_bUseMask = false;//是否顯示掩膜窗口的布爾值  
 12 int g_nNewMaskVal = 255;//新的從新繪製的像素值 
 13 
 14 static void ShowHelpText()
 15 {
 16     //輸出一些幫助信息    
 17     printf("\n\n\n\t歡迎來到漫水填充示例程序~\n\n");
 18     printf("\n\n\t按鍵操做說明: \n\n"
 19         "\t\t鼠標點擊圖中區域- 進行漫水填充操做\n"
 20         "\t\t鍵盤按鍵【ESC】- 退出程序\n"
 21         "\t\t鍵盤按鍵【1】-  切換彩色圖/灰度圖模式\n"
 22         "\t\t鍵盤按鍵【2】- 顯示/隱藏掩膜窗口\n"
 23         "\t\t鍵盤按鍵【3】- 恢復原始圖像\n"
 24         "\t\t鍵盤按鍵【4】- 使用空範圍的漫水填充\n"
 25         "\t\t鍵盤按鍵【5】- 使用漸變、固定範圍的漫水填充\n"
 26         "\t\t鍵盤按鍵【6】- 使用漸變、浮動範圍的漫水填充\n"
 27         "\t\t鍵盤按鍵【7】- 操做標誌符的低八位使用4位的鏈接模式\n"
 28         "\t\t鍵盤按鍵【8】- 操做標誌符的低八位使用8位的鏈接模式\n"
 29         "\n\n\t\t\t\t\t\t\t\t by淺墨\n\n\n"
 30     );
 31 }
 32 
 33 //鼠標消息onMouse回調函數  
 34 static void onMouse(int event, int x, int y, int, void*)
 35 {
 36     // 若鼠標左鍵沒有按下,便返回  
 37     if (event != CV_EVENT_LBUTTONDOWN)
 38         return;
 39     //-------------------【<1>調用floodFill函數以前的參數準備部分】---------------  
 40     Point seed = Point(x, y);
 41     int LowDifference = (g_nFillMode == 0) ? 0 : g_nLowDifference;//空範圍的漫水填充,此值設爲0,不然設爲全局的g_nLowDifference  
 42     int UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;//空範圍的漫水填充,此值設爲0,不然設爲全局的g_nUpDifference  
 43     int flags = g_nConnectivity + (g_nNewMaskVal << 8) +
 44         (g_nFillMode == 1 ? CV_FLOODFILL_FIXED_RANGE : 0);//標識符的0~7位爲g_nConnectivity,8~15位爲g_nNewMaskVal左移8位的值,16~23位爲CV_FLOODFILL_FIXED_RANGE或者0。  
 45 
 46                                                           //隨機生成bgr值  
 47     int b = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值  
 48     int g = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值  
 49     int r = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值  
 50     Rect ccomp;//定義重繪區域的最小邊界矩形區域  
 51 
 52     Scalar newVal = g_bIsColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114);//在重繪區域像素的新值,如果彩色圖模式,取Scalar(b, g, r);如果灰度圖模式,取Scalar(r*0.299 + g*0.587 + b*0.114)  
 53 
 54     Mat dst = g_bIsColor ? g_dstImage : g_grayImage;//目標圖的賦值  
 55     int area;
 56 
 57     //--------------------【<2>正式調用floodFill函數】-----------------------------  
 58     if (g_bUseMask)
 59     {
 60         threshold(g_maskImage, g_maskImage, 1, 128, CV_THRESH_BINARY);
 61         area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
 62             Scalar(UpDifference, UpDifference, UpDifference), flags);
 63         imshow("mask", g_maskImage);
 64     }
 65     else
 66     {
 67         area = floodFill(dst, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
 68             Scalar(UpDifference, UpDifference, UpDifference), flags);
 69     }
 70 
 71     imshow("效果圖", dst);
 72     cout << area << " 個像素被重繪\n";
 73 }
 74 
 75 void main()
 76 {
 77     system("color 2F");//改變console字體顏色 
 78     g_srcImage = imread("E://lena.jpg", 1);//載入原圖  
 79     if (!g_srcImage.data) { printf("Oh,no,讀取圖片image0錯誤~! \n"); return; }
 80     ShowHelpText();
 81 
 82     g_srcImage.copyTo(g_dstImage);//拷貝源圖到目標圖  
 83     //cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);//轉換三通道的image0到灰度圖  
 84     g_maskImage.create(g_srcImage.rows + 2, g_srcImage.cols + 2, CV_8UC1);//利用image0的尺寸來初始化掩膜mask  
 85 
 86     namedWindow("效果圖", CV_WINDOW_NORMAL);
 87     //建立Trackbar  
 88     createTrackbar("負差最大值", "效果圖", &g_nLowDifference, 255, 0);
 89     createTrackbar("正差最大值", "效果圖", &g_nUpDifference, 255, 0);
 90     //鼠標回調函數  
 91     setMouseCallback("效果圖", onMouse, 0);
 92 
 93     //循環輪詢按鍵  
 94     while (1)
 95     {
 96         //先顯示效果圖  
 97         imshow("效果圖", g_bIsColor ? g_dstImage : g_grayImage);
 98         //獲取鍵盤按鍵  
 99         int c = waitKey(0);
100         //判斷ESC是否按下,若按下便退出  
101         if ((c & 255) == 27)
102         {
103             cout << "程序退出...........\n";
104             break;
105         }
106 
107         //根據按鍵的不一樣,進行各類操做  
108         switch ((char)c)
109         {
110         case '1':    //若是鍵盤「1」被按下,效果圖在在灰度圖,彩色圖之間互換 
111             if (g_bIsColor)//若原來爲彩色,轉爲灰度圖,而且將掩膜mask全部元素設置爲0  
112             {
113                 cout << "鍵盤「1」被按下,切換彩色/灰度模式,當前操做爲將【彩色模式】切換爲【灰度模式】\n";
114                 cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
115                 g_maskImage = Scalar::all(0);   //將mask全部元素設置爲0  
116                 g_bIsColor = false; //將標識符置爲false,表示當前圖像不爲彩色,而是灰度  
117             }
118             else//若原來爲灰度圖,便將原來的彩圖image0再次拷貝給image,而且將掩膜mask全部元素設置爲0  
119             {
120                 cout << "鍵盤「1」被按下,切換彩色/灰度模式,當前操做爲將【彩色模式】切換爲【灰度模式】\n";
121                 g_srcImage.copyTo(g_dstImage);
122                 g_maskImage = Scalar::all(0);
123                 g_bIsColor = true;//將標識符置爲true,表示當前圖像模式爲彩色  
124             }
125             break;
126         case '2'://顯示/隱藏掩膜窗口  
127             if (g_bUseMask)
128             {
129                 destroyWindow("mask");
130                 g_bUseMask = false;
131             }
132             else
133             {
134                 namedWindow("mask", 0);
135                 g_maskImage = Scalar::all(0);
136                 imshow("mask", g_maskImage);
137                 g_bUseMask = true;
138             }
139             break;
140         case '3'://恢復原始圖像
141             cout << "按鍵「3」被按下,恢復原始圖像\n";
142             g_srcImage.copyTo(g_dstImage);
143             cvtColor(g_dstImage, g_grayImage, COLOR_BGR2GRAY);
144             g_maskImage = Scalar::all(0);
145             break;
146         case '4'://使用空範圍的漫水填充 
147             cout << "按鍵「4」被按下,使用空範圍的漫水填充\n";
148             g_nFillMode = 0;
149             break;
150         case '5'://使用漸變、固定範圍的漫水填充
151             cout << "按鍵「5」被按下,使用漸變、固定範圍的漫水填充\n";
152             g_nFillMode = 1;
153             break;
154         case '6'://使用漸變、浮動範圍的漫水填充 
155             cout << "按鍵「6」被按下,使用漸變、浮動範圍的漫水填充\n";
156             g_nFillMode = 2;
157             break;
158         case '7'://操做標誌符的低八位使用4位的鏈接模式  
159             cout << "按鍵「7」被按下,操做標誌符的低八位使用4位的鏈接模式\n";
160             g_nConnectivity = 4;
161             break;  
162         case '8'://操做標誌符的低八位使用8位的鏈接模式
163             cout << "按鍵「8」被按下,操做標誌符的低八位使用8位的鏈接模式\n";
164             g_nConnectivity = 8;
165             break;
166         }
167     }
168 }

 

相關文章
相關標籤/搜索