《OpenCV3编程入门》学习笔记6 图像处理(五)漫水填充
6.5 漫水填充(floodFill)
6.5.1 漫水填充
1.定義:一種用特定的顏色填充連通區(qū)域,通過設(shè)置可連通像素的上下限及連通方式達(dá)到不同填充效果
2.基本思想:自動選中和種子點相連的區(qū)域(位于給定范圍(從LowDiff到UpDiff)或在原始seedPoint像素值范圍內(nèi)),將該區(qū)域所有相似點填充指定的相同顏色
3.作用:標(biāo)記或分離圖像一部分,從輸入圖像獲取掩碼區(qū)域
4.封裝函數(shù):floodFill()函數(shù)
5.函數(shù)原型(有2個版本,另一個版本無參數(shù)2):
int floodFill(InputOutputArray image, InputOutputArray mask, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4)
6.參數(shù)說明:
(1)輸入/輸出1通道或3通道,8位或浮點圖像
(2)操作掩模,8位單通道,長和寬都比原圖像大兩個像素點,漫水填充不會填充掩模mask的非零像素區(qū)域,如,邊緣檢測算子輸出做掩模可以防止填充邊緣、多次函數(shù)調(diào)用中使用同一個掩模可以保證填充區(qū)域不重疊。注意:掩模比須填充圖像大,輸入圖像(x,y)點對應(yīng)掩模(x+1,y+1)點
(3)算法起始點
(4)像素點被染色的值,即在重繪區(qū)域像素的新值
(5)可選參數(shù),用于設(shè)置floodFill函數(shù)將要重繪區(qū)域的最小邊界矩形區(qū)域,默認(rèn)0
(6)表示當(dāng)前觀察像素值與其附近鄰域像素值或待加入的種子像素值之間的亮度或顏色之負(fù)差(lower brightness/color difference)的最大值,默認(rèn)Scalar()
(7)表示當(dāng)前觀察像素值與其附近鄰域像素值或待加入的種子像素值之間的亮度或顏色之正差(lower brightness/color difference)的最大值,默認(rèn)Scalar()
(8)操作標(biāo)識符,包含三個部分(用”|”連接):
??1)0~7位用于控制算法連通性,取4(默認(rèn))表示填充算法只考慮當(dāng)前像素水平方向或垂直方向的相鄰點,取8表示還會包含對角線方向的臨近點
??2)16~23位可以為0或如下兩種選項標(biāo)識符的組合:FLOODFILL_RANGE表示會考慮當(dāng)前像素與種子像素的差,否則會考慮當(dāng)前像素與其相鄰像素的差;FLOODFILL_MASK_ONLY表示不會填充改變原始圖像(即忽略第3個參數(shù)newVal)而是去填充掩模圖像
??3)8~15位用于指定填充掩碼圖像的值(后8位標(biāo)識符為FLOODFILL_MASK_ONLY時),0表示掩模用1填充
Eg. 8鄰域,固定填充像素值范圍,填充掩模不填充原圖像,填充值為38:
Flags=8|FLOODFILL_MASK_ONLY|FLOODFILL_FIXED_RANGE|(38<<8)
6.5.2 漫水填充示例
1.漫水填充簡單示例
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{//載入原圖并顯示Mat srcImage = imread("love.jpg");imshow("【原始圖】", srcImage);//漫水填充Rect ccomp;floodFill(srcImage, Point(50, 300), Scalar(155, 255, 55), &ccomp, Scalar(20, 20, 20), Scalar(20, 20, 20));//顯示效果圖imshow("【效果圖】", srcImage);waitKey(0);return 0;
}
運行效果:
2.綜合示例
/*
效果:鼠標(biāo)對窗口多次點擊得到類似PS的魔棒效果鍵盤8個按鍵操作切換漫水填充模式
*/
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;//全局變量
Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage;//定義原始圖、目標(biāo)圖、灰度圖、掩模圖
int g_nFillMode = 1;//漫水填充模式(0為空范圍,1為固定填充像素值范圍)
int g_nLowDifference = 20;//負(fù)差最大值
int g_nUpDifference = 20;//正差最大值
int g_nConnectivity = 4;//表示floodFill函數(shù)標(biāo)識符低八位的連通值
int g_nNewMaskVal = 255;//新的重新繪制的像素值
int g_bIsColor = true;//是否為彩色圖的標(biāo)識符布爾值
bool g_bUseMask = false;//是否顯示掩模窗口的布爾值//---------------------------------【onMouse()函數(shù)】----------------------
// 描述:鼠標(biāo)消息onMouse回調(diào)函數(shù)
//------------------------------------------------------------------------
static void onMouse(int event, int x, int y, int, void*)
{//若鼠標(biāo)左鍵沒有按下,便返回if (event != EVENT_LBUTTONDOWN)return;//--------------------【<1>調(diào)用floodFill函數(shù)之前的參數(shù)準(zhǔn)備】-------------Point seed = Point(x, y);int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference;//空范圍的漫水填充設(shè)為0,否則設(shè)為全局的g_nLowDifferenceint UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference; //空范圍的漫水填充設(shè)為0,否則設(shè)為全局的g_nUpDifferenceint flags = g_nConnectivity + (g_nNewMaskVal << 8) + (g_nFillMode == 1 ? FLOODFILL_FIXED_RANGE : 0);//標(biāo)識符的0~7位為g_nConnectivity,8~15位為g_nNewMaskVal左移8位的值,16~23位為CV_FLOODFILL_FIXED+RANGE或0//隨機(jī)生成bgr值int b = (unsigned)theRNG() & 255;//隨機(jī)返回一個0~255之間的值int g = (unsigned)theRNG() & 255;//隨機(jī)返回一個0~255之間的值int r = (unsigned)theRNG() & 255;//隨機(jī)返回一個0~255之間的值//定義重繪區(qū)域的最小邊界矩形區(qū)域Rect ccomp;//重繪區(qū)域像素的新值,若是彩色圖模式,取Scalar(b,g,r);若是灰度圖模式,取Scalar(r*0.299+b*0.587+b*0.114)Scalar newVal = g_bIsColor ? Scalar(b, g, r) : Scalar(r*0.299 + g * 0.587 + b * 0.114);//目標(biāo)圖的賦值Mat dst = g_bIsColor ? g_dstImage : g_grayImage;int area;//---------------------【<2>正式調(diào)用floodFill函數(shù)】---------------------if (g_bUseMask){threshold(g_maskImage, g_maskImage, 1, 128, THRESH_BINARY);area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference), Scalar(UpDifference, UpDifference, UpDifference), flags);}else{area=floodFill(dst,seed,newVal,&ccomp, Scalar(LowDifference, LowDifference, LowDifference), Scalar(UpDifference, UpDifference, UpDifference), flags);}imshow("效果圖", dst);cout.width(7);cout <<area << " 個像素被重繪\n";
}
//---------------------------------【ShowHelpText()函數(shù)】----------------------
// 描述:鍵盤操作說明
//------------------------------------------------------------------------static void ShowHelpText()
{printf("--------------------------------------------------------------------\n");printf("請鼠標(biāo)點擊圖像觀察漫水填充效果~\n");printf("按鍵操作說明:\n");printf("\t\t鍵盤按鍵[ESC]-退出程序\n");printf("\t\t鍵盤按鍵[1]-切換彩色圖/灰度圖模式\n");printf("\t\t鍵盤按鍵[2]-顯示/隱藏掩模模式\n");printf("\t\t鍵盤按鍵[3]-恢復(fù)原始圖像\n");printf("\t\t鍵盤按鍵[4]-使用空范圍的漫水填充\n");printf("\t\t鍵盤按鍵[5]-使用新變、固定范圍的漫水填充\n");printf("\t\t鍵盤按鍵[6]-使用新變、浮動范圍的漫水填充\n");printf("\t\t鍵盤按鍵[7]-操作標(biāo)識符的低8位使用4的連接模式\n");printf("\t\t鍵盤按鍵[8]-操作標(biāo)識符的低8位使用8的連接模式\n");printf("--------------------------------------------------------------------\n");
}
int main()
{//鍵盤操作說明ShowHelpText();//載入原圖g_srcImage = imread("love.jpg");if (!g_srcImage.data){printf("載入原圖失敗~!\n");return false;}//復(fù)制原圖到目標(biāo)圖g_srcImage.copyTo(g_dstImage);cvtColor(g_dstImage, g_grayImage, COLOR_BGR2GRAY);//轉(zhuǎn)換三通道的g_srcImage到灰度圖g_maskImage.create(g_srcImage.rows + 2, g_srcImage.cols + 2, CV_8UC1);//利用g_srcImage尺寸初始化mask//創(chuàng)建效果圖窗口namedWindow("效果圖", WINDOW_AUTOSIZE);//創(chuàng)建TrackBarcreateTrackbar("負(fù)差最大值", "效果圖", &g_nLowDifference, 255, 0);createTrackbar("正差最大值", "效果圖", &g_nUpDifference, 255, 0);//鼠標(biāo)回調(diào)函數(shù)setMouseCallback("效果圖", onMouse, 0);//循環(huán)輪詢按鍵while (1){//先顯示效果圖imshow("效果圖", g_bIsColor ? g_dstImage : g_grayImage);//獲取鍵盤按鍵int c = waitKey(0);//判斷按鍵ESC是否按下,若按下便退出if ((c & 255) == 27){cout << "程序退出.......\n";break;}//根據(jù)按鍵不同,進(jìn)行各種操作switch ((char)c){//如果鍵盤1按下,效果圖在灰度圖,彩色圖之間互換case '1'://若原來為彩色,轉(zhuǎn)為灰度圖,并將掩模mask所有元素設(shè)為0if (g_bIsColor){cout << "按鍵“1”按下,切換彩色/灰度模式,當(dāng)前操作為【彩色模式】切換為【灰度模式】\n";cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);g_maskImage = Scalar::all(0);//將mask所有元素設(shè)為0g_bIsColor = false;//將標(biāo)識符設(shè)置為false,表示當(dāng)前圖像不為彩色,而是灰度}//若原來為灰度,將原來彩色圖g_srcImage再次復(fù)制給g_dstImage,并將掩模mask所有元素設(shè)為0else{cout << "按鍵“1”按下,切換彩色/灰度模式,當(dāng)前操作為【灰度模式】切換為【彩色模式】\n";g_srcImage.copyTo(g_dstImage);g_maskImage = Scalar::all(0);g_bIsColor = 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;//如果按鍵4被按下,使用空范圍的漫水填充case '4':cout << "按鍵“4”被按下,使用空范圍的漫水填充\n";g_nFillMode = 0;break;//如果按鍵5被按下,使用新變、固定范圍的漫水填充case '5':cout << "按鍵“5”被按下,使用新變、固定范圍的漫水填充\n";g_nFillMode = 1;break;//如果按鍵6被按下,使用新變、浮動范圍的漫水填充case '6':cout << "按鍵“6”被按下,使用新變、浮動范圍的漫水填充\n";g_nFillMode = 2;break;//如果按鍵7被按下,操作標(biāo)識符的低8位使用4的連接模式case '7':cout << "按鍵“7”被按下,操作標(biāo)識符的低8位使用4的連接模式\n";g_nConnectivity = 4;break;//如果按鍵8被按下,操作標(biāo)識符的低8位使用8的連接模式case '8':cout << "按鍵“8”被按下,操作標(biāo)識符的低8位使用8的連接模式\n";g_nConnectivity = 8;break;}}return 0;
}
運行效果:
總結(jié)
以上是生活随笔為你收集整理的《OpenCV3编程入门》学习笔记6 图像处理(五)漫水填充的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python学习笔记2 基本数据类型
- 下一篇: Python学习笔记3 流程控制、迭代器