漫水填充
视频讲解如下:
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
本章节给大家讲讲如何使用漫水填充功能FloodFill。当前代码主体还是使用毛星云的demo,C#和Python都是在C++版本的基础上转换过来的,三个版本的效果基本一致。
准备的原图如下:

运行效果如下:

C#版本代码
C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。
如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。
OpenCv3版本的SetMouseCallback操作请参考:/Course?id=4743192000049
using OpenCvSharp;
using System;
namespace demo
{
internal class Program
{
//定义原始图、目标图、灰度图、掩模图
static Mat g_srcImage = new Mat();
static Mat g_dstImage = new Mat();
static Mat g_grayImage = new Mat();
static Mat g_maskImage = new Mat();
//漫水填充的模式
static int g_nFillMode = 1;
//负差最大值、正差最大值
static int g_nLowDifference = 20, g_nUpDifference = 20;
//表示floodFill函数标识符低八位的连通值
static int g_nConnectivity = 4;
//是否为彩色图的标识符布尔值
static bool g_bIsColor = true;
//是否显示掩膜窗口的布尔值
static bool g_bUseMask = false;
//新的重新绘制的像素值
static int g_nNewMaskVal = 255;
static Random g_rng = new Random();
static void ShowHelpText()
{
//输出一些帮助信息
Console.WriteLine("\n\n\t欢迎来到漫水填充示例程序~");
Console.WriteLine("\n\n\t本示例根据鼠标选取的点搜索图像中与之颜色相近的点,并用不同颜色标注。");
Console.WriteLine("\n\n\t按键操作说明:");
Console.WriteLine("\t\t鼠标点击图中区域- 进行漫水填充操作");
Console.WriteLine("\t\t键盘按键【ESC】- 退出程序");
Console.WriteLine("\t\t键盘按键【1】- 切换彩色图/灰度图模式");
Console.WriteLine("\t\t键盘按键【2】- 显示/隐藏掩膜窗口");
Console.WriteLine("\t\t键盘按键【3】- 恢复原始图像");
Console.WriteLine("\t\t键盘按键【4】- 使用空范围的漫水填充");
Console.WriteLine("\t\t键盘按键【5】- 使用渐变、固定范围的漫水填充");
Console.WriteLine("\t\t键盘按键【6】- 使用渐变、浮动范围的漫水填充");
Console.WriteLine("\t\t键盘按键【7】- 操作标志符的低八位使用4位的连接模式");
Console.WriteLine("\t\t键盘按键【8】- 操作标志符的低八位使用8位的连接模式\n");
}
//-------------------【onMouse( )函数】---------------------
// 描述:鼠标消息onMouse回调函数
//----------------------------------------------------------
static void onMouse(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userData)
{
// 若鼠标左键没有按下,便返回
if (@event != MouseEventTypes.LButtonDown)
return;
//-------------------【<1>调用floodFill函数之前的参数准备部分】---------------
Point seed = new Point(x, y);
//空范围的漫水填充,此值设为0,否则设为全局的g_nLowDifference
int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference;
//空范围的漫水填充,此值设为0,否则设为全局的g_nUpDifference
int UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;
//标识符的0~7位为g_nConnectivity,8~15位为g_nNewMaskVal左移8位的值,16~23位为CV_FLOODFILL_FIXED_RANGE或者0。
int mflags = (int)(g_nConnectivity + (g_nNewMaskVal << 8) + (g_nFillMode == 1 ? FloodFillFlags.FixedRange : 0));
//随机生成bgr值
int b = g_rng.Next(255);//随机返回一个0~255之间的值
int g = g_rng.Next(255);//随机返回一个0~255之间的值
int r = g_rng.Next(255);//随机返回一个0~255之间的值
//定义重绘区域的最小边界矩形区域
Rect ccomp = new Rect();
// 在重绘区域像素的新值,若是彩色图模式,取Scalar(b, g, r);
// 若是灰度图模式,取Scalar(r*0.299 + g*0.587 + b*0.114)
Scalar newVal = g_bIsColor ? new Scalar(b, g, r) : new 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)
{
Cv2.Threshold(g_maskImage, g_maskImage, 1, 128, ThresholdTypes.Binary);
area = Cv2.FloodFill(dst, g_maskImage, seed, newVal, out ccomp,
new Scalar(LowDifference, LowDifference, LowDifference),
new Scalar(UpDifference, UpDifference, UpDifference), (FloodFillFlags)mflags);
Cv2.ImShow("mask", g_maskImage);
}
else
{
area = Cv2.FloodFill(dst, seed, newVal, out ccomp,
new Scalar(LowDifference, LowDifference, LowDifference),
new Scalar(UpDifference, UpDifference, UpDifference), (FloodFillFlags)mflags);
}
Cv2.ImShow("效果图", dst);
Console.WriteLine($"{area} 个像素被重绘");
Cv2.WaitKey(10);
}
//-----------------【main( )函数】--------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//----------------------------------------------------------
static void Main(string[] args)
{
//载入原图
g_srcImage = Cv2.ImRead("../../../images/girl3.jpg");
// 缩放原图
//resize(g_srcImage, g_srcImage, Size(g_srcImage.cols * 0.5, g_srcImage.rows * 0.5));
//显示帮助文字
ShowHelpText();
//拷贝源图到目标图
g_srcImage.CopyTo(g_dstImage);
//转换三通道的image0到灰度图
Cv2.CvtColor(g_srcImage, g_grayImage, ColorConversionCodes.BGR2GRAY);
//利用image0的尺寸来初始化掩膜mask
g_maskImage.Create(g_srcImage.Rows + 2, g_srcImage.Cols + 2, MatType.CV_8UC1);
Cv2.NamedWindow("效果图", WindowFlags.AutoSize);
//创建Trackbar
Cv2.CreateTrackbar("负差最大值", "效果图", ref g_nLowDifference, 255);
Cv2.CreateTrackbar("正差最大值", "效果图", ref g_nUpDifference, 255);
//鼠标回调函数
Cv2.SetMouseCallback("效果图", new MouseCallback(onMouse));
//循环轮询按键
while (true)
{
//先显示效果图
Cv2.ImShow("效果图", g_bIsColor ? g_dstImage : g_grayImage);
//获取键盘按键
int c = Cv2.WaitKey(0);
//判断ESC是否按下,若按下便退出
if ((c & 255) == 27)
{
Console.WriteLine("程序退出...........");
break;
}
//根据按键的不同,进行各种操作
switch ((char)c)
{
//如果键盘“1”被按下,效果图在在灰度图,彩色图之间互换
case '1':
if (g_bIsColor) //若原来为彩色,转为灰度图,并且将掩膜mask所有元素设置为0
{
Console.WriteLine("键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】");
Cv2.CvtColor(g_srcImage, g_grayImage, ColorConversionCodes.BGR2GRAY);
g_maskImage = g_maskImage.SetTo(new Scalar(0, 0, 0));//将mask所有元素设置为0
g_bIsColor = false; //将标识符置为false,表示当前图像不为彩色,而是灰度
}
//若原来为灰度图,便将原来的彩图image0再次拷贝给image,并且将掩膜mask所有元素设置为0
else
{
Console.WriteLine("键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】\n");
g_srcImage.CopyTo(g_dstImage);
g_maskImage = g_maskImage.SetTo(new Scalar(0, 0, 0));//将mask所有元素设置为0
g_bIsColor = true;//将标识符置为true,表示当前图像模式为彩色
}
break;
//如果键盘按键“2”被按下,显示/隐藏掩膜窗口
case '2':
if (g_bUseMask)
{
Cv2.DestroyWindow("mask");
g_bUseMask = false;
}
else
{
Cv2.NamedWindow("mask", WindowFlags.AutoSize);
g_maskImage = g_maskImage.SetTo(new Scalar(0, 0, 0));//将mask所有元素设置为0
Cv2.ImShow("mask", g_maskImage);
g_bUseMask = true;
}
break;
//如果键盘按键“3”被按下,恢复原始图像
case '3':
Console.WriteLine("按键“3”被按下,恢复原始图像");
g_srcImage.CopyTo(g_dstImage);
Cv2.CvtColor(g_srcImage, g_grayImage, ColorConversionCodes.BGR2GRAY);
g_maskImage = g_maskImage.SetTo(new Scalar(0, 0, 0));
break;
//如果键盘按键“4”被按下,使用空范围的漫水填充
case '4':
Console.WriteLine("按键“4”被按下,使用空范围的漫水填充");
g_nFillMode = 0;
break;
//如果键盘按键“5”被按下,使用渐变、固定范围的漫水填充
case '5':
Console.WriteLine("按键“5”被按下,使用渐变、固定范围的漫水填充");
g_nFillMode = 1;
break;
//如果键盘按键“6”被按下,使用渐变、浮动范围的漫水填充
case '6':
Console.WriteLine("按键“6”被按下,使用渐变、浮动范围的漫水填充");
g_nFillMode = 2;
break;
//如果键盘按键“7”被按下,操作标志符的低八位使用4位的连接模式
case '7':
Console.WriteLine("按键“7”被按下,操作标志符的低八位使用4位的连接模式");
g_nConnectivity = 4;
break;
//如果键盘按键“8”被按下,操作标志符的低八位使用8位的连接模式
case '8':
Console.WriteLine("按键“8”被按下,操作标志符的低八位使用8位的连接模式");
g_nConnectivity = 8;
break;
default: break;
}
}
}
}
}
C++版本代码
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/core/utils/logger.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;
//表示floodFill函数标识符低八位的连通值
int g_nConnectivity = 4;
//是否为彩色图的标识符布尔值
bool g_bIsColor = true;
//是否显示掩膜窗口的布尔值
bool g_bUseMask = false;
//新的重新绘制的像素值
int g_nNewMaskVal = 255;
static void ShowHelpText()
{
//输出一些帮助信息
printf("\n\n\t欢迎来到漫水填充示例程序~");
printf("\n\n\t本示例根据鼠标选取的点搜索图像中与之颜色相近的点,并用不同颜色标注。");
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\n");
}
//-------------------【onMouse( )函数】---------------------
// 描述:鼠标消息onMouse回调函数
//----------------------------------------------------------
static void onMouse(int event, int x, int y, int, void*)
{
// 若鼠标左键没有按下,便返回
// opencv3:CV_EVENT_LBUTTONDOWN
// opencv4:EVENT_LBUTTONDOWN
if (event != EVENT_LBUTTONDOWN)
return;
//-------------------【<1>调用floodFill函数之前的参数准备部分】---------------
Point seed = Point(x, y);
//空范围的漫水填充,此值设为0,否则设为全局的g_nLowDifference
int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference;
//空范围的漫水填充,此值设为0,否则设为全局的g_nUpDifference
int UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;
//标识符的0~7位为g_nConnectivity,8~15位为g_nNewMaskVal左移8位的值,16~23位为CV_FLOODFILL_FIXED_RANGE或者0。
// opencv3:CV_FLOODFILL_FIXED_RANGE
// opencv4:FLOODFILL_FIXED_RANGE
int flags = g_nConnectivity + (g_nNewMaskVal << 8) + (g_nFillMode == 1 ? 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(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;
int area;
//--------------------【<2>正式调用floodFill函数】-----------------------------
if (g_bUseMask)
{
// opencv3:CV_THRESH_BINARY
// opencv4:THRESH_BINARY
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);
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)
{
// 关闭opencv日志
cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_SILENT);
//改变console字体颜色
system("color 2F");
//载入原图
g_srcImage = imread("../images/girl3.jpg");
// 缩放原图
//resize(g_srcImage, g_srcImage, Size(g_srcImage.cols * 0.5, g_srcImage.rows * 0.5));
if (!g_srcImage.data) { printf("Oh,no,读取图片image0错误~! \n"); return false; }
//显示帮助文字
ShowHelpText();
//拷贝源图到目标图
g_srcImage.copyTo(g_dstImage);
//转换三通道的image0到灰度图
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
//利用image0的尺寸来初始化掩膜mask
g_maskImage.create(g_srcImage.rows + 2, g_srcImage.cols + 2, CV_8UC1);
// opencv3:CV_WINDOW_AUTOSIZE
// opencv4:WINDOW_AUTOSIZE
namedWindow("效果图", 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", WINDOW_AUTOSIZE);
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;
default:break;
}
}
return 0;
}
Python版本代码
import cv2
import numpy as np
import yaml
import time
import random
g_maskImage = np.zeros((0,0), np.uint8)
g_dstImage = np.zeros((0,0), np.uint8)
# 漫水填充的模式
g_nFillMode = 1
# 负差最大值、正差最大值
g_nLowDifference = 20
g_nUpDifference = 20
# 表示floodFill函数标识符低八位的连通值
g_nConnectivity = 4
# 是否为彩色图的标识符布尔值
g_bIsColor = True
# 是否显示掩膜窗口的布尔值
g_bUseMask = False
# 新的重新绘制的像素值
g_nNewMaskVal = 255
def ShowHelpText():
#输出一些帮助信息
print("\n\n\t欢迎来到漫水填充示例程序~");
print("\n\n\t本示例根据鼠标选取的点搜索图像中与之颜色相近的点,并用不同颜色标注。");
print("\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\n");
#创建回调函数
def onMouse(event,x,y,flags,param):
global g_maskImage, g_dstImage
if event != cv2.EVENT_LBUTTONDOWN:
return
#-------------------【<1>调用floodFill函数之前的参数准备部分】---------------
seed = (x, y)
#空范围的漫水填充,此值设为0,否则设为全局的g_nLowDifference
LowDifference = 0 if g_nFillMode == 0 else g_nLowDifference
#空范围的漫水填充,此值设为0,否则设为全局的g_nUpDifference
UpDifference = 0 if g_nFillMode == 0 else g_nUpDifference
#标识符的0~7位为g_nConnectivity,8~15位为g_nNewMaskVal左移8位的值,16~23位为CV_FLOODFILL_FIXED_RANGE或者0。
m = cv2.FLOODFILL_FIXED_RANGE if g_nFillMode == 1 else 0
mflags = g_nConnectivity + (g_nNewMaskVal << 8) + m
#随机生成bgr值
b = random.randint(0,255) #随机返回一个0~255之间的值
g = random.randint(0,255) #随机返回一个0~255之间的值
r = random.randint(0,255) #随机返回一个0~255之间的值
# 在重绘区域像素的新值,若是彩色图模式,取Scalar(b, g, r);
# 若是灰度图模式,取Scalar(r*0.299 + g*0.587 + b*0.114)
newVal = (b, g, r) if g_bIsColor == True else (r * 0.299 + g * 0.587 + b * 0.114)
#目标图的赋值
dst = g_dstImage if g_bIsColor == True else g_grayImage
#--------------------【<2>正式调用floodFill函数】-----------------------------
ret,g_maskImage = cv2.threshold(g_maskImage,1,128,cv2.THRESH_BINARY)
area = cv2.floodFill(dst, g_maskImage, seed, newVal,
(LowDifference, LowDifference, LowDifference),
(UpDifference, UpDifference, UpDifference), mflags)
if g_bUseMask == True:
cv2.imshow('mask',g_maskImage)
cv2.imshow('image',dst)
print("(%d) 个像素被重绘" %(area[0]))
# 负差最大值
def nLowDifference(x):
global g_nLowDifference
g_nLowDifference = x
# 正差最大值
def nUpDifference(x):
global g_nUpDifference
g_nUpDifference = x
# 载入原图
g_srcImage=cv2.imread('../images/girl3.jpg')
# 显示帮助文字
ShowHelpText()
# 利用image0的尺寸来初始化掩膜mask
rows,cols,channels = g_srcImage.shape
# 拷贝源图到目标图
g_dstImage = np.zeros((rows,cols,3),np.uint8)
np.copyto(g_dstImage, g_srcImage)
# 转换三通道的image0到灰度图
g_grayImage=cv2.cvtColor(g_srcImage, cv2.COLOR_BGR2GRAY)
# 不知道是不是版本问题,CreateImage和CreateMat在我这里都用不了
#g_maskImage = cv2.CreateImage((rows + 2, cols + 2), cv2.IPL_DEPTH_8U, 1)
#g_maskImage = cv2.CreateMat(rows + 2, cols + 2, cv2.CV_8UC1)
g_maskImage = np.zeros((rows + 2, cols + 2), np.uint8)
# 创建窗口
cv2.namedWindow('image')
# 显示原图
cv2.imshow('image',g_srcImage)
cv2.setMouseCallback('image',onMouse)
cv2.createTrackbar('nLow', 'image', 0, 255, nLowDifference)
cv2.createTrackbar('nUp', 'image', 0, 255, nUpDifference)
cv2.setTrackbarPos('nLow', 'image', 15)
cv2.setTrackbarPos('nUp', 'image', 15)
while (True):
# 先显示效果图
img = g_dstImage if g_bIsColor == True else g_grayImage
cv2.imshow('image',img)
c = cv2.waitKey(0)
# 判断ESC是否按下,若按下便退出
if c == 27 :
print("程序退出...........")
break
# 如果键盘“1”被按下,效果图在在灰度图,彩色图之间互换
if c == 49 :
if g_bIsColor == True: #若原来为彩色,转为灰度图,并且将掩膜mask所有元素设置为0
print("键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】.")
g_grayImage=cv2.cvtColor(g_srcImage, cv2.COLOR_BGR2GRAY)
#将mask所有元素设置为0
g_maskImage = np.zeros((rows + 2, cols + 2), np.uint8)
#将标识符置为false,表示当前图像不为彩色,而是灰度
g_bIsColor = False
else: #若原来为灰度图,便将原来的彩图image0再次拷贝给image,并且将掩膜mask所有元素设置为0
print("键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】")
np.copyto(g_dstImage, g_srcImage)
g_maskImage = np.zeros((rows + 2, cols + 2), np.uint8)
g_bIsColor = True #将标识符置为true,表示当前图像模式为彩色
# 如果键盘按键“2”被按下,显示/隐藏掩膜窗口
if c == 50 :
if g_bUseMask:
cv2.destroyWindow("mask")
g_bUseMask = False
else:
cv2.namedWindow("mask", 0)
g_maskImage = np.zeros((rows + 2, cols + 2), np.uint8)
cv2.imshow("mask", g_maskImage)
g_bUseMask = True;
# 如果键盘按键“3”被按下,恢复原始图像
if c == 51 :
print("按键“3”被按下,恢复原始图像")
np.copyto(g_dstImage, g_srcImage)
g_grayImage=cv2.cvtColor(g_srcImage, cv2.COLOR_BGR2GRAY)
g_maskImage = np.zeros((rows + 2, cols + 2), np.uint8)
# 如果键盘按键“4”被按下,使用空范围的漫水填充
if c == 52 :
print("按键“4”被按下,使用空范围的漫水填充")
g_nFillMode = 0
# 如果键盘按键“5”被按下,使用渐变、固定范围的漫水填充
if c == 53 :
print("按键“5”被按下,使用渐变、固定范围的漫水填充")
g_nFillMode = 1
# 如果键盘按键“6”被按下,使用渐变、浮动范围的漫水填充
if c == 54 :
print("按键“6”被按下,使用渐变、浮动范围的漫水填充")
g_nFillMode = 2
# 如果键盘按键“7”被按下,操作标志符的低八位使用4位的连接模式
if c == 55 :
print("按键“7”被按下,操作标志符的低八位使用4位的连接模式")
g_nConnectivity = 4
# 如果键盘按键“8”被按下,操作标志符的低八位使用8位的连接模式
if c == 56 :
print("按键“8”被按下,操作标志符的低八位使用8位的连接模式")
g_nConnectivity = 8
cv2.destroyAllWindows()