目录
1 概念
漫水填充法是根据像素灰度值之间的差值寻找相同区域以实现分割。我们可以将图像的灰度值理解成像素点的高度,这样一幅图像可以看成崎岖不平的地面或者山地,向地面上某一个低的地方倾倒一定量的水,水将掩盖低于某个高度的区域。漫水填充法利用的就是这样的原理,其式与注水相似,因此被形象地称为“漫水”。与向地面注水一致,漫水填充法也需要在图像选择一个注水”像素,该像素称为种子点,按照一定规则不断向外扩散,从而形成具有相似特征的独立区域,进而实现图像分割。
漫水填充法是一种基于种子点的图像处理算法,它从种子点开始向相邻的像素扩散,并将符合条件的像素标记为指定的颜色或值。漫水填充法常用于图像分割、背景去除、颜色替换等应用。
2 函数详解
OpenCV提供了cv::floodFill()函数来实现漫水填充。该函数接受输入图像、种子点位置、目标颜色、填充范围等参数,并输出填充后的图像。
以下是floodFill()函数的常见使用方式和参数说明:
void floodFill(InputOutputArray image, Point seedPoint, Scalar newVal,
Rect* rect = 0, Scalar loDiff = Scalar(), Scalar upDiff = Scalar(),
int flags = 4);
image:输入输出图像,可以是单通道或多通道的图像。
seedPoint:种子点,指定开始填充的点。
newVal:填充的新值,即要将区域内的像素设置为的值,可以是单个像素值或者一个Scalar对象。
rect(可选):输出参数,表示填充区域的最小外接矩形。如果不需要该信息,可以传入nullptr。
loDiff(可选):低灰度差异阈值,用于控制填充的相似性范围。如果当前像素与种子点之间的灰度差大于该阈值,则停止填充。
upDiff(可选):高灰度差异阈值,用于控制填充的相似性范围。如果当前像素与种子点之间的灰度差小于该阈值,则停止填充。
flags(可选):附加标志,用于控制填充的行为。常用的标志有:
4:只填充与种子点相连的4邻域像素(上下左右)。
8:填充与种子点相连的8邻域像素(上下左右及对角线)。
floodFill()函数会修改输入图像中的像素值,因此在进行填充操作前需要创建一个副本或者使用clone()函数复制原始图像。
3 原理
漫水填充法的数学原理涉及像素颜色比较和连通性判断。当当前像素与种子点的颜色满足条件时,将其标记为目标颜色,并继续向相邻像素扩散填充,直到不满足条件或达到填充范围的边界。
漫水填充法的一般步骤:
-
选择种子点:指定一个起始点作为种子点,可以是用户手动选择的点或者根据特定条件自动选择的点。
-
定义填充条件:确定填充的条件,通常是通过判断当前像素与种子点像素之间的相似性来确定是否进行填充。相似性判断可以基于像素值、灰度差异、颜色距离等。
-
开始填充:从种子点开始,按照填充条件逐渐向相邻的像素进行填充。可以使用递归或队列等数据结构来实现填充过程。
-
边界控制:在填充过程中,需要控制填充范围,避免填充超出目标区域。可以通过设定边界条件或者使用掩码(mask)来限制填充的范围。
4 用C++编写代码进行实现
下面是一个使用漫水填充法实现图像背景去除的示例代码:
#include <iostream>
#include <opencv2/opencv.hpp>
int main() {
// 加载图像
cv::Mat image = cv::imread("image.jpg", cv::IMREAD_COLOR);
// 复制原始图像作为填充结果
cv::Mat filledImage = image.clone();
// 定义填充参数
cv::Point seedPoint(100, 100); // 种子点
cv::Scalar fillColor(255, 0, 0); // 填充颜色
int loDiff = 3; // 低灰度差异阈值
int upDiff = 3; // 高灰度差异阈值
// 执行漫水填充
cv::floodFill(filledImage, seedPoint, fillColor, nullptr, cv::Scalar(loDiff, loDiff, loDiff), cv::Scalar(upDiff, upDiff, upDiff));
// 显示结果
cv::imshow("Original Image", image);
cv::imshow("Filled Image", filledImage);
cv::waitKey(0);
return 0;
}