漫水填充法

漫水填充法是一种用特定的颜色填充联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果的方法。漫水填充经常被用来标记或分离图像的一部分以便对其进行进一步处理或分析,也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或只处理掩码指定的像素点,操作的结果总是某个连续的区域。

漫水填充算法

基本思想

漫水填充算法是用来标记一片区域的:设置一个种子点,然后种子点附近的相似点都被填充同一种颜色。该算法应用性很广,比如目标识别,photoshop 的魔术棒功能等等,是填充类算法中应用最为广泛的一个算法。

OpenCV函数

1
2
3
4
5
6
7
8
9
10
void cvFloodFill (
IplImage * img,  // 输入图像
CvPoint seedPoint, // 种子点
CvScalar newVal,    // 像素点被染色的值
CvScalar loDiff = cvScalarAll(0), // 染色边界判定
CvScalar upDiff = cvScalarAll(0), // 染色边界判定
CvConnectedComp * comp = NULL, // 填充区域统计属性
int flags = 4, // 连通性,相关性等参数设置。
CvArr * mask = NULL // 掩码区域
);

参数特别说明:

  1. 掩码参数 mask 必须是一个单通道,8位,像素宽度高度均比原图像大两个像素。mask 图像的像素 (x+1, y+1) 与原图像 (x, y) 相对应。为 0 的位表示不进行处理。同时,掩码区也会返回填充结果。

  2. flags 参数提供更为强大的填充配置信息,详见相关资料

相应题目

有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。

给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。

为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。

最后返回经过上色渲染后的图像。

方法一:广度优先搜索

思路及算法

我们从给定的起点开始,进行广度优先搜索。每次搜索到一个方格时,如果其与初始位置的方格颜色相同,就将该方格加入队列,并将该方格的颜色更新,以防止重复入队。

注意:因为初始位置的颜色会被修改,所以我们需要保存初始位置的颜色,以便于之后的更新操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
vector<int> dx = {1,-1,0,0};
vector<int> dy = {0,0,1,-1};
public:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
int rows = image.size();
if(rows==0) return image;
int cols = image[0].size();
vector<vector<int>> flag(rows,vector<int>(cols,1));
int val = image[sr][sc];
queue<pair<int,int>> q;
q.push(make_pair(sr,sc));
flag[sr][sc]=0;
while(!q.empty()){
int sz = q.size();
while(sz--){
pair<int,int> loc = q.front();
q.pop();
int x = loc.first,y = loc.second;
image[x][y] = newColor;
for(int i = 0;i<4;i++){
int nx = x+dx[i],ny = y+dy[i];
if(nx>=0 && nx<rows && ny>=0 && ny<cols && flag[nx][ny]==1 && image[nx][ny]==val){
q.push(make_pair(nx,ny));
flag[nx][ny]=0;
}
}

}
}
return image;
}
};

方法二:深度优先搜索

思路及算法

我们从给定的起点开始,进行深度优先搜索。每次搜索到一个方格时,如果其与初始位置的方格颜色相同,就将该方格的颜色更新,以防止重复搜索;如果不相同,则进行回溯。

注意:因为初始位置的颜色会被修改,所以我们需要保存初始位置的颜色,以便于之后的更新操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
vector<int> dx = {1,-1,0,0};
vector<int> dy = {0,0,1,-1};
int rows,cols,currColor;
public:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
currColor = image[sr][sc];
if(newColor==currColor) return image;
rows = image.size(),cols = image[0].size();
vector<vector<int>> flag(rows,vector<int>(cols,1));
dfs(image,flag,sr,sc,newColor);
return image;
}
void dfs(vector<vector<int>>& image, vector<vector<int>>& flag,int row, int col, int newColor){
image[row][col] = newColor;
flag[row][col] = 0;
for(int i = 0;i<4;i++){
int nx = row+dx[i],ny = col+dy[i];
if(nx>=0 && nx<rows && ny>=0 && ny<cols && flag[nx][ny]==1 && image[nx][ny]==currColor){
dfs(image,flag,nx,ny,newColor);
}
}
}
};

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 guoben
  • PV: UV:

微信