Opencv3從頭開始(九)漫水填充

Opencv3從頭開始(九)漫水填充

參考淺墨文章

漫水填充法是一種用特定的顏色填充聯通區域,通過設置可連通像素的上下限以及連通方式來達到不同的填充效果的方法。漫水填充經常被用來標記或分離圖像的一部分以便對其進行進一步處理或分析,也可以用來從輸入圖像獲取掩碼區域,掩碼會加速處理過程,或只處理掩碼指定的像素點,操作的結果總是某個連續的區域。

在這裏插入圖片描述
在這裏插入圖片描述

/*
-----------------------------------------------------------------------------------------
漫水填充
-----------------------------------------------------------------------------------------
*/

//-----------------------------------【頭文件包含部分】---------------------------------------  
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
 
//-----------------------------------【命名空間聲明部分】---------------------------------------  
using namespace cv;
using namespace std;
 
 
//-----------------------------------【全局變量聲明部分】--------------------------------------  
Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage;//定義原始圖、目標圖、灰度圖、掩模圖
int g_nFillMode = 1;//漫水填充的模式
int g_nLowDifference = 20, g_nUpDifference = 20;//負差最大值、正差最大值
int g_nConnectivity = 4;//表示floodFill函數標識符低八位的連通值
int g_bIsColor = true;//是否爲彩色圖的標識符布爾值
bool g_bUseMask = false;//是否顯示掩膜窗口的布爾值
int g_nNewMaskVal = 255;//新的重新繪製的像素值
 
 
//-----------------------------------【ShowHelpText( )函數】----------------------------------  
//      描述:輸出一些幫助信息  
//----------------------------------------------------------------------------------------------  
static void ShowHelpText()  
{  
	//輸出一些幫助信息  
	printf("\n\n\n\t歡迎來到漫水填充示例程序~\n\n");  
	printf( "\n\n\t按鍵操作說明: \n\n"  
		"\t\t鼠標點擊圖中區域- 進行漫水填充操作\n"  
		"\t\t鍵盤按鍵【ESC】- 退出程序\n"  
		"\t\t鍵盤按鍵【1】-  切換彩色圖/灰度圖模式\n"  
		"\t\t鍵盤按鍵【2】- 顯示/隱藏掩膜窗口\n"  
		"\t\t鍵盤按鍵【3】- 恢復原始圖像\n"  
		"\t\t鍵盤按鍵【4】- 使用空範圍的漫水填充\n"  
		"\t\t鍵盤按鍵【5】- 使用漸變、固定範圍的漫水填充\n"  
		"\t\t鍵盤按鍵【6】- 使用漸變、浮動範圍的漫水填充\n"  
		"\t\t鍵盤按鍵【7】- 操作標誌符的低八位使用4位的連接模式\n"  
		"\t\t鍵盤按鍵【8】- 操作標誌符的低八位使用8位的連接模式\n"  
		);  
}  
 
 
//-----------------------------------【onMouse( )函數】--------------------------------------  
//      描述:鼠標消息onMouse回調函數
//---------------------------------------------------------------------------------------------
static void onMouse( int event, int x, int y, int, void* )
{
	// 若鼠標左鍵沒有按下,便返回
	if( event != CV_EVENT_LBUTTONDOWN )
		return;
 
	//-------------------【<1>調用floodFill函數之前的參數準備部分】---------------
	Point seed = Point(x,y);
	int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference;//空範圍的漫水填充,此值設爲0,否則設爲全局的g_nLowDifference
	int UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;//空範圍的漫水填充,此值設爲0,否則設爲全局的g_nUpDifference
	int flags = g_nConnectivity + (g_nNewMaskVal << 8) +
		(g_nFillMode == 1 ? CV_FLOODFILL_FIXED_RANGE : 0);//標識符的0~7位爲g_nConnectivity,8~15位爲g_nNewMaskVal左移8位的值,16~23位爲CV_FLOODFILL_FIXED_RANGE或者0。
 
	//隨機生成bgr值
	int b = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值
	int g = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值
	int r = (unsigned)theRNG() & 255;//隨機返回一個0~255之間的值
	Rect ccomp;//定義重繪區域的最小邊界矩形區域
 
	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)
 
	Mat dst = g_bIsColor ? g_dstImage : g_grayImage;//目標圖的賦值
	int area;
 
	//--------------------【<2>正式調用floodFill函數】-----------------------------
	if( g_bUseMask )
	{
		threshold(g_maskImage, g_maskImage, 1, 128, CV_THRESH_BINARY);
		area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
			Scalar(UpDifference, UpDifference, UpDifference), flags);
		imshow( "mask", g_maskImage );
	}
	else
	{
		area = floodFill(dst, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
			Scalar(UpDifference, UpDifference, UpDifference), flags);
	}
 
	imshow("效果圖", dst);
	cout << area << " 個像素被重繪\n";
}
 
 
//-----------------------------------【main( )函數】--------------------------------------------  
//      描述:控制檯應用程序的入口函數,我們的程序從這裏開始  
//-----------------------------------------------------------------------------------------------  
int main( int argc, char** argv )
{
	//改變console字體顏色  
	system("color 2F");    
 
	//載入原圖
	g_srcImage = imread("倉老師.jpg", 1);
 
    if( !g_srcImage.data ) { printf("Oh,no,讀取圖片image0錯誤~! \n"); return false; }  
 
	//顯示幫助文字
	ShowHelpText();
 
	g_srcImage.copyTo(g_dstImage);//拷貝源圖到目標圖
	cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);//轉換三通道的image0到灰度圖
	g_maskImage.create(g_srcImage.rows+2, g_srcImage.cols+2, CV_8UC1);//利用image0的尺寸來初始化掩膜mask
 
	namedWindow( "效果圖",CV_WINDOW_AUTOSIZE );
 
	//創建Trackbar
	createTrackbar( "負差最大值", "效果圖", &g_nLowDifference, 255, 0 );
	createTrackbar( "正差最大值" ,"效果圖", &g_nUpDifference, 255, 0 );
 
	//鼠標回調函數
	setMouseCallback( "效果圖", onMouse, 0 );
 
	//循環輪詢按鍵
	while(1)
	{
		//先顯示效果圖
		imshow("效果圖", g_bIsColor ? g_dstImage : g_grayImage);
 
		//獲取鍵盤按鍵
		int c = waitKey(0);
		//判斷ESC是否按下,若按下便退出
		if( (c & 255) == 27 )
		{
			cout << "程序退出...........\n";
			break;
		}
 
		//根據按鍵的不同,進行各種操作
		switch( (char)c )
		{
		//如果鍵盤“1”被按下,效果圖在在灰度圖,彩色圖之間互換
		case '1':
			if( g_bIsColor )//若原來爲彩色,轉爲灰度圖,並且將掩膜mask所有元素設置爲0
			{
				cout << "鍵盤“1”被按下,切換彩色/灰度模式,當前操作爲將【彩色模式】切換爲【灰度模式】\n";
				cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
				g_maskImage = Scalar::all(0);	//將mask所有元素設置爲0
				g_bIsColor = false;	//將標識符置爲false,表示當前圖像不爲彩色,而是灰度
			}
			else//若原來爲灰度圖,便將原來的彩圖image0再次拷貝給image,並且將掩膜mask所有元素設置爲0
			{
				cout << "鍵盤“1”被按下,切換彩色/灰度模式,當前操作爲將【彩色模式】切換爲【灰度模式】\n";
				g_srcImage.copyTo(g_dstImage);
				g_maskImage = Scalar::all(0);
				g_bIsColor = true;//將標識符置爲true,表示當前圖像模式爲彩色
			}
			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”被按下,恢復原始圖像
		case '3':
			cout << "按鍵“3”被按下,恢復原始圖像\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”被按下,操作標誌符的低八位使用4位的連接模式
		case '7':
			cout << "按鍵“7”被按下,操作標誌符的低八位使用4位的連接模式\n";
			g_nConnectivity = 4;
			break;
		//如果鍵盤按鍵“8”被按下,操作標誌符的低八位使用8位的連接模式
		case '8':
			cout << "按鍵“8”被按下,操作標誌符的低八位使用8位的連接模式\n";
			g_nConnectivity = 8;
			break;
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章