OpenCV学习笔记(九): 漫水填充:floodFill()
OpenCV學(xué)習(xí)筆記(九): 漫水填充:floodFill()
定義:
漫水填充法是一種用特定的顏色填充聯(lián)通區(qū)域(自動選中了和種子點相連的區(qū)域,接著將該區(qū)域替換成指定的顏色)通過設(shè)置可連通像素的上下限以及連通方式來達到不同的填充效果的方法。
使用:
1)經(jīng)常被用來標(biāo)記或分離圖像的一部分,以便對其進行進一步處理或分析。
2)從輸入圖像獲取掩碼區(qū)域(掩碼會加速處理過程,或只處理掩碼指定的像素點,操作的結(jié)果總是某個連續(xù)的區(qū)域)
算子:
// PS:
1、漫水填充不會填充掩膜mask的非零像素區(qū)域。例如,一個邊緣檢測算子的輸出可以用來作為掩膜,以防止填充到邊緣。同樣的,也可以在多次的函數(shù)調(diào)用中使用同一個掩膜,以保證填充的區(qū)域不會重疊。另外需要注意的是,
掩膜mask會比需填充的圖像大,所以 mask 中與輸入圖像(x,y)像素點相對應(yīng)的點的坐標(biāo)為(x+1,y+1)。
2、
1)低八位(第0~7位)用于控制算法的連通性,可取4 (4為缺省值) 或者 8。
2)高八位部分(16~23位)可以為0 或者如下兩種選項標(biāo)識符的組合:
FLOODFILL_FIXED_RANGE - 如果設(shè)置為這個標(biāo)識符的話,就會考慮當(dāng)前像素與種子像素之間的差, 否則就考慮當(dāng)前像素與其相鄰像素的差。也就是說,這個范圍是浮動的。 FLOODFILL_MASK_ONLY - 如果設(shè)置為這個標(biāo)識符的話,函數(shù)不會去填充改變原始圖像 (也就是忽略第三個參數(shù)newVal), 而是去填充掩模圖像(mask)。3)中間八位部分,上面關(guān)于高八位FLOODFILL_MASK_ONLY標(biāo)識符中已經(jīng)說的很明顯,需要輸入符合要求的掩碼。Floodfill的flags參數(shù)的中間八位的值就是用于指定填充掩碼圖像的值的。但如果flags中間八位的值為0,則掩碼會用1來填充。
//如果想用8鄰域填充,并填充固定像素值范圍,填充掩碼而不是填充源圖像,以及設(shè)填充值為38 flags=8 | FLOODFILL_MASK_ONLY | FLOODFILL_FIXED_RANGE | (38<<8)示例代碼:
#include <opencv2/opencv.hpp>using namespace cv; using namespace std;Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage; //定義原始圖、目標(biāo)圖、灰度圖、掩模圖 int g_nFillMode = 1; //漫水填充的模式 int g_nLowDifference = 20, g_nUpDifference = 20; //負差最大值、正差最大值 int g_nConnectivity = 4; //表示floodFill函數(shù)標(biāo)識符低八位的連通值 bool g_bIsColor = true; //是否為彩色圖的標(biāo)識 bool g_bUseMask = false; //是否顯示掩膜窗口的標(biāo)識 int g_nNewMaskVal = 255; //新的重新繪制的像素值int main() {//顯示幫助文字ShowHelpText();// 1、載入原圖g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/TEST/2.jpg", 1);if( !g_srcImage.data ){printf("讀取圖片image0錯誤~! \n");return false;}// 2、拷貝源圖到目標(biāo)圖g_srcImage.copyTo(g_dstImage);// 3、轉(zhuǎn)換三通道的image0到灰度圖cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);// 4、利用image0的尺寸來初始化掩膜maskg_maskImage.create(g_srcImage.rows+2, g_srcImage.cols+2, CV_8UC1);// 5、創(chuàng)建TrackbarnamedWindow( "效果圖",WINDOW_AUTOSIZE );createTrackbar( "負差最大值", "效果圖", &g_nLowDifference, 255, 0 ); // 無滑動條事件,只改變滑動條值(0~255)createTrackbar( "正差最大值" ,"效果圖", &g_nUpDifference, 255, 0 ); // 無滑動條事件,只改變滑動條值(0~255)// 6、鼠標(biāo)回調(diào)函數(shù)(鼠標(biāo)點擊便觸發(fā))// 將mask所有元素設(shè)置為0(背景設(shè)為黑色)g_maskImage = Scalar::all(0); setMouseCallback( "效果圖", onMouse, 0 );// 7、循環(huán)輪詢按鍵while(1){//先顯示效果圖imshow("效果圖", g_bIsColor ? g_dstImage : g_grayImage);//獲取鍵盤按鍵int c = waitKey(0);//判斷ESC是否按下,若按下便退出if( (c & 255) == 27 ){cout << "程序退出...........\n";break;}//根據(jù)按鍵的不同,進行各種操作switch( (char)c ){//如果鍵盤“1”被按下,效果圖在在灰度圖,彩色圖之間互換case '1':if( g_bIsColor )//若原來為彩色,轉(zhuǎn)為灰度圖,并且將掩膜mask所有元素設(shè)置為0{cout << "鍵盤“1”被按下,切換彩色/灰度模式,當(dāng)前操作為將【彩色模式】切換為【灰度模式】\n";cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);g_maskImage = Scalar::all(0); //將mask所有元素設(shè)置為0g_bIsColor = false; //將標(biāo)識符置為false,表示當(dāng)前圖像不為彩色,而是灰度}else//若原來為灰度圖,便將原來的彩圖image0再次拷貝給image,并且將掩膜mask所有元素設(shè)置為0{cout << "鍵盤“1”被按下,切換彩色/灰度模式,當(dāng)前操作為將【彩色模式】切換為【灰度模式】\n";g_srcImage.copyTo(g_dstImage);g_maskImage = Scalar::all(0);g_bIsColor = true; //將標(biāo)識符置為true,表示當(dāng)前圖像模式為彩色}break;//如果鍵盤按鍵“2”被按下,顯示/隱藏掩膜窗口case '2':if( g_bUseMask ){destroyWindow( "mask" );g_bUseMask = false;}else{namedWindow( "mask", 0 );//g_maskImage = Scalar::all(0); // 清空置零imshow("mask", g_maskImage);g_bUseMask = true;}break;//如果鍵盤按鍵“3”被按下,恢復(fù)原始圖像case '3':cout << "按鍵“3”被按下,恢復(fù)原始圖像\n";g_srcImage.copyTo(g_dstImage);cvtColor(g_dstImage, g_grayImage, COLOR_BGR2GRAY);g_maskImage = Scalar::all(0);break;// 改變”漫水填充“操作標(biāo)識:// 1、如果鍵盤按鍵“4”被按下,使用空范圍的漫水填充case '4':cout << "按鍵“4”被按下,使用空范圍的漫水填充\n";g_nFillMode = 0;break;// 2、如果鍵盤按鍵“5”被按下,使用漸變、固定范圍的漫水填充case '5':cout << "按鍵“5”被按下,使用漸變、固定范圍的漫水填充\n";g_nFillMode = 1;break;// 3、如果鍵盤按鍵“6”被按下,使用漸變、浮動范圍的漫水填充case '6':cout << "按鍵“6”被按下,使用漸變、浮動范圍的漫水填充\n";g_nFillMode = 2;break;// 4、如果鍵盤按鍵“7”被按下,操作標(biāo)志符的低八位使用4位的連接模式case '7':cout << "按鍵“7”被按下,操作標(biāo)志符的低八位使用4位的連接模式\n";g_nConnectivity = 4;break;// 5、如果鍵盤按鍵“8”被按下,操作標(biāo)志符的低八位使用8位的連接模式case '8':cout << "按鍵“8”被按下,操作標(biāo)志符的低八位使用8位的連接模式\n";g_nConnectivity = 8;break;}} }輸出一些幫助信息
static void ShowHelpText() {printf("\n\n\t漫水填充示例程序~");printf("\n\n\t根據(jù)鼠標(biāo)選取的點搜索圖像中與之顏色相近的點,并用不同顏色標(biāo)注。");printf("\n\n\t按鍵操作說明: \n\n""\t\t鼠標(biāo)點擊圖中區(qū)域- 進行漫水填充操作\n""\t\t鍵盤按鍵【ESC】- 退出程序\n""\t\t鍵盤按鍵【1】- 切換彩色圖/灰度圖模式\n""\t\t鍵盤按鍵【2】- 顯示/隱藏掩膜窗口\n""\t\t鍵盤按鍵【3】- 恢復(fù)原始圖像\n""\t\t鍵盤按鍵【4】- 使用空范圍的漫水填充\n""\t\t鍵盤按鍵【5】- 使用漸變、固定范圍的漫水填充\n""\t\t鍵盤按鍵【6】- 使用漸變、浮動范圍的漫水填充\n""\t\t鍵盤按鍵【7】- 操作標(biāo)志符的低八位使用4位的連接模式\n""\t\t鍵盤按鍵【8】- 操作標(biāo)志符的低八位使用8位的連接模式\n\n"); }鼠標(biāo)消息onMouse回調(diào)
static void onMouse(int event, int x, int y, int, void*) {if (event != EVENT_LBUTTONDOWN)return;// 1、調(diào)用floodFill函數(shù)之前的參數(shù)準備部分Point seed = Point(x, y); // 鼠標(biāo)點擊獲取起始點位置int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference; //空范圍的漫水填充,此值設(shè)為0,否則設(shè)為全局的g_nLowDifferenceint UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference; //空范圍的漫水填充,此值設(shè)為0,否則設(shè)為全局的g_nUpDifference// 1.1、floodFill()函數(shù)第八個參數(shù)值:flags=低八位+中八位+高八位int flags = g_nConnectivity + (g_nNewMaskVal << 8) + (g_nFillMode == 1 ? FLOODFILL_FIXED_RANGE : 0); // FLOODFILL_FIXED_RANGE// 1.2、隨機生成bgr值int b = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值int g = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值int r = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值Rect ccomp;//定義重繪區(qū)域的最小邊界矩形區(qū)域// 1.3、在重繪區(qū)域像素的新值,若是彩色圖模式,取Scalar(b, g, r);若是灰度圖模式,取Scalar(r*0.299 + g*0.587 + b*0.114)Scalar newVal = g_bIsColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114);Mat dst = g_bIsColor ? g_dstImage : g_grayImage;//目標(biāo)圖的賦值// 2、正式調(diào)用floodFill函數(shù)threshold(g_maskImage, g_maskImage, 1, 128, THRESH_BINARY);// 帶掩碼輸出的 floodFill()int area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),Scalar(UpDifference, UpDifference, UpDifference), flags);// 3、關(guān)閉或顯示掩碼窗口if (g_bUseMask){imshow("mask", g_maskImage);} // else // { // // 不帶掩碼輸出的 floodFill() // area = floodFill(dst, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference), // Scalar(UpDifference, UpDifference, UpDifference), flags); // }imshow("效果圖", dst);cout << area << " 個像素被重繪\n"; }結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的OpenCV学习笔记(九): 漫水填充:floodFill()的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用pymc3可能遇到的问题及解决方法
- 下一篇: C++ delete只能用来释放new分