二值图像连通域搜索BFS

1、BFS计算连通域个数



// https://blog.csdn.net/weixin_41788963/article/details/104470487


//【算法笔记】基于广度优先搜索(BFS)求解图像连通域


//简介
//广度优先搜索,是以广度作为第一关键词,当碰到岔口时,首先访问这个岔口能直接到达的所有结点,然后这些结点被访问的顺序,依次继续访问其可以到达的所有结点,直到所有结点都被访问,或者满足终止条件;
//
//算法较为理想的实现方式是使用队列,将前面的元素不断弹出,在搜索过程中,将下一层的元素不断地补在后面,直到队列为空,或是满足条件,完成搜索;
//
//完成demo后,发现本方法适用于求取图像中的连通域个数、大小、排序等,因此作为扩展,在此记录求解连通域的用法;
//————————————————
//版权声明:本文为CSDN博主「Henry爱学习」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
//原文链接:https://blog.csdn.net/weixin_41788963/article/details/104470487

//模板

//void BFS(int s){
//	queue<int> q;
//	q.push(s);
//	while(!q.empty()){
//		取出队首元素top;
//		访问队首元素top;
//		将队首元素出队;
//		将top的下一层结点中,未曾入队的全部入队;
//	}
//}


//对于上述模板的说明如下:
//
//1.定义队列 q,并将起点 s 入队;
//2.定义 while 循环,循环条件是 q 非空;
//3.在 while 循环中,先取出队首的元素 top,然后访问 top,访问结束后令 top 出队;
//4.将 top下一层结点中未曾入队的结点全部入队,如果需要记录层号,此时层号加一,同时设置上述结点已经入过队;
//5.返回步骤 2,直到队列为空或满足其他终止条件;


//Demo
//给出一个 m×n 的矩阵,矩阵中的元素为0或1(与二值图像等效),定义位置 (x,y) 与其上下左右四个位置 (x-1, y), (x+1, y), (x, y-1), (x, y+1) 
//是相邻的。由相邻的点连成的区域就叫连通域,求给定矩阵中连通域的个数,给出 6×7 的矩阵示例如下,首行输入尺寸,随后输入矩阵的值:


//6 7
//0 1 1 1 0 0 1
//0 0 1 0 0 0 0
//0 0 0 0 1 0 0
//0 0 0 1 1 1 0
//1 1 1 0 1 0 0
//1 1 1 1 0 0 0


//输出为连通域的个数:
//
//4


//问题分析
//1.枚举每一个位置的元素,如果为 0,跳过;如果为 1,则使用 BFS 查询邻近的 4 个元素(保证不出界,且不重复访问), 判断其是否为 1,循环往复,知道一个连通域内的 1 全部访问;
//2.为了防止走“回头路”,防止重复访问同一个 1,设置一个 bool 型的数组 inq(意为in queue) 来记录每个 1 是否在 BFS 中已经入过队;
//3.设置两个数组来表示 4 个方向,用 for 循环省略了 4 个 if;


//int row[4] = {0, 0, 1, -1};
//int col[4] = {1, -1, 0, 0};
//for(int i=0;i<4;i++){
//	new_x = x + row[i]; //x, y 分别是当前位置的行和列
//	new_y = y + col[i];
//	...
//}


//代码
 
#include <stdio.h> 
#include <queue>
using namespace std;
const int maxn = 30; //假设矩阵最大的尺寸是 30×30

// 定义Node 变量来记录(x,y) 坐标

struct Node{
	int x, y;
}; 

int matrix[maxn][maxn]; //定义输入矩阵
int m, n; //定义矩阵的行和列
bool inq[maxn] [maxn] = {false}; //定义查询矩阵 

int row[4] = {1, -1, 0, 0};
int col[4] = {0, 0, 1, -1}; // 定义访问上下左右四个方向的变量
queue<Node> a; // 定义记录搜索过程的队列

// 定义判断函数,判断某点是否值为1,没有超出尺寸,且没有被访问过
bool judge(int x, int y) {
	if(x<0 || x>=m || y<0 || y>=n) return false;
	if(matrix[x][y]==0 || inq[x][y]==true) return false;
	return true;
}


void BFS(int x, int y){
	Node p, temp; // 定义p为当前位置, temp为临近的四个位置
	p.x = x;
	p.y = y;
	a.push(p); //访问并入队
	inq[x] [y]=true; //更新访问状态
	while(!a.empty()){
		p = a.front(); // 令P访问a的队首作为当前节点
		a.pop(); //弹出a的队首
		//访问临近节点,符合条件的入队,直到队列a为空
		for(int i=0; i<4; i++) {
			int new_x = p.x + row[i];
			int new_y = p.y + col[i];
			if(judge(new_x, new_y)==true){
				temp.x = new_x;
				temp.y = new_y;
				a.push(temp);
				inq[new_x][new_y] = true;
			}
		}
	}
}


int main(){
	printf("Please input the row and column:\n");
	// 矩阵维度
	 
	//	scanf("%d%d", &m, &n);
	m = 6;
	n = 7; 
	printf("Please input matrix:\n");
	// 输入矩阵
	 int mat[42]={
	 0, 1, 1, 1, 0, 0, 1,
	 0, 0, 1, 0, 0, 0, 0,
	 0, 0, 0, 0, 1, 0, 0,
	 0, 0, 0, 1, 1, 1, 0,
	 1, 1, 1, 0, 1, 0, 0,
	 1, 1, 1, 1, 0, 0, 0,};
	for(int i=0; i<m; i++){
		for(int j=0; j<n; j++){
//			scanf("%d", &matrix[i][j]);
			matrix[i][j] = mat[i*n+j];
		}
	}
	
		for(int i=0; i<m; i++){
		for(int j=0; j<n; j++){
			printf("%d", matrix[i][j]);
		}
		printf("\n");
    }
	
	//ans 记录连通域个数
	int ans=0;
	for(int i=0; i<m; i++) {
		for(int j=0; j<n; j++){
			//符合条件的点进入BFS
			if(matrix[i][j]==1 && inq[i][j]==false) {
				ans++;
				BFS(i,j);
			}
		}
	}
	
	printf("%d\n", ans);
	getchar();
	return 0;
	
}

 

参考:【算法笔记】基于广度优先搜索(BFS)求解图像连通域

2、 BFS标记连通域


//代码
 
#include <stdio.h> 
#include <queue>
using namespace std;
const int maxn = 30; //假设矩阵最大的尺寸是 30×30
int ans=0;
// 定义Node 变量来记录(x,y) 坐标

struct Node{
	int x, y;
}; 

int matrix[maxn][maxn]; //定义输入矩阵
int m, n; //定义矩阵的行和列
//bool inq[maxn] [maxn] = {false}; //定义查询矩阵 
int inq[maxn] [maxn] = {0}; //定义查询矩阵 
int row[4] = {1, -1, 0, 0};
int col[4] = {0, 0, 1, -1}; // 定义访问上下左右四个方向的变量
queue<Node> a; // 定义记录搜索过程的队列

// 定义判断函数,判断某点是否值为1,没有超出尺寸,且没有被访问过
bool judge(int x, int y) {
	if(x<0 || x>=m || y<0 || y>=n) return false;
	if(matrix[x][y]==0 || inq[x][y]>0) return false;
	return true;
}


void BFS(int x, int y){
	Node p, temp; // 定义p为当前位置, temp为临近的四个位置
	p.x = x;
	p.y = y;
	a.push(p); //访问并入队
	inq[x] [y]=ans; //更新访问状态
	while(!a.empty()){
		p = a.front(); // 令P访问a的队首作为当前节点
		a.pop(); //弹出a的队首
		//访问临近节点,符合条件的入队,直到队列a为空
		for(int i=0; i<4; i++) {
			int new_x = p.x + row[i];
			int new_y = p.y + col[i];
			if(judge(new_x, new_y)==true){
				temp.x = new_x;
				temp.y = new_y;
				a.push(temp);
				inq[new_x][new_y] = ans;
			}
		}
	}
}


int main(){
	printf("Please input the row and column:\n");
	// 矩阵维度
	 
	//	scanf("%d%d", &m, &n);
	m = 6;
	n = 7; 
	printf("rows: %d\n", m);
	printf("cols: %d\n", n);
	printf("Please input matrix:\n");
	// 输入矩阵
	 int mat[42]={
	 0, 1, 1, 1, 0, 0, 1,
	 0, 0, 1, 0, 0, 0, 0,
	 0, 0, 0, 0, 1, 0, 0,
	 0, 0, 0, 1, 1, 1, 0,
	 1, 1, 1, 0, 1, 0, 0,
	 1, 1, 1, 1, 0, 0, 0,};
	for(int i=0; i<m; i++){
		for(int j=0; j<n; j++){
//			scanf("%d", &matrix[i][j]);
			matrix[i][j] = mat[i*n+j];
		}
	}
	
	for(int i=0; i<m; i++){
		for(int j=0; j<n; j++){
			printf("%d", matrix[i][j]);
			}
		printf("\n");
	}
	
	//ans 记录连通域个数

	for(int i=0; i<m; i++) {
		for(int j=0; j<n; j++){
			//符合条件的点进入BFS
			if(matrix[i][j]==1 && inq[i][j]==0) {
				ans++;
				BFS(i,j);
			}
		}
	}
	
	printf("connection regions: %d\n", ans);
	printf("labeled matrix:\n");	
	for(int i=0; i<m; i++){
		for(int j=0; j<n; j++){
			printf("%d", inq[i][j]);
		}
		printf("\n");
	}
	getchar();
	return 0;
	
}

输出结果:

Please input the row and column:
rows: 6
cols: 7
Please input matrix:
0111001
0010000
0000100
0001110
1110100
1111000
connection regions: 4
labeled matrix:
0111002
0010000
0000300
0003330
4440300
4444000

 

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落花逐流水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值