使用OpenCV获取图片连通域数量,并用不同颜色标记函


Posted in Python onJune 04, 2020

一,原图和效果图

使用OpenCV获取图片连通域数量,并用不同颜色标记函

二,代码

//#########################产生随机颜色#########################
cv::Scalar icvprGetRandomColor()
{
	uchar r = 255 * (rand() / (1.0 + RAND_MAX));
	uchar g = 255 * (rand() / (1.0 + RAND_MAX));
	uchar b = 255 * (rand() / (1.0 + RAND_MAX));
	return cv::Scalar(b, g, r);
}
//#########################产生随机颜色#########################

//########################种子填充法)#########################
void ConnectedCountBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg, int &iConnectedAreaCount)
{
  //拓宽1个像素的原因是:如果连通域在边缘,运行此函数会异常崩溃,所以需要在周围加一圈0值,确保连通域不在边上
	//==========图像周围拓宽1个像素============================================
	int top, bottom;      //【添加边界后的图像尺寸】
	int leftImage, rightImage;
	int borderType = BORDER_CONSTANT; //BORDER_REPLICATE
	//【初始化参数】
	top = (int)(1); bottom = (int)(1);
	leftImage = (int)(1); rightImage = (int)(1);
	Mat _binImg2, _binImg3;
	_binImg.copyTo(_binImg2);
		//初始化参数value
		Scalar value(0); //填充值
		//创建图像边界
		copyMakeBorder(_binImg2, _binImg3, top, bottom, leftImage, rightImage, borderType, value);

	//==========图像周围拓宽1个像素============================================

	// connected component analysis (4-component) 
	// use seed filling algorithm 
	// 1. begin with a foreground pixel and push its foreground neighbors into a stack; 
	// 2. pop the top pixel on the stack and label it with the same label until the stack is empty 
	//  
	// foreground pixel: _binImg(x,y) = 1 
	// background pixel: _binImg(x,y) = 0 

	if (_binImg3.empty() ||
		_binImg3.type() != CV_8UC1)
	{
		return;
	}

	_lableImg.release();
	_binImg3.convertTo(_lableImg, CV_32SC1);
	int icount = 0;
	int label = 1; // start by 2 

	int rows = _binImg3.rows - 1;
	int cols = _binImg3.cols - 1;
	for (int i = 1; i < rows - 1; i++)
	{
		int* data = _lableImg.ptr<int>(i);  //取一行数据
		for (int j = 1; j < cols - 1; j++)
		{
			if (data[j] == 1)  //像素不为0
			{
				std::stack<std::pair<int, int>> neighborPixels;   //新建一个栈
				neighborPixels.push(std::pair<int, int>(i, j));   // 像素坐标: <i,j> ,以该像素为起点,寻找连通域 
				++label; // 开始一个新标签,各连通域区别的标志
				while (!neighborPixels.empty())
				{
					// 获取堆栈中的顶部像素并使用相同的标签对其进行标记
					std::pair<int, int> curPixel = neighborPixels.top();
					int curX = curPixel.first;
					int curY = curPixel.second;
					_lableImg.at<int>(curX, curY) = label; //对图像对应位置的点进行标记

					// 弹出顶部像素  (顶部像素出栈)
					neighborPixels.pop();

						// 加入8邻域点
						if (_lableImg.at<int>(curX, curY - 1) == 1)
						{// 左点 
							neighborPixels.push(std::pair<int, int>(curX, curY - 1)); //左边点入栈
						}

						if (_lableImg.at<int>(curX, curY + 1) == 1)
						{// 右点 
							neighborPixels.push(std::pair<int, int>(curX, curY + 1)); //右边点入栈
						}

						if (_lableImg.at<int>(curX - 1, curY) == 1)
						{// 上点 
							neighborPixels.push(std::pair<int, int>(curX - 1, curY)); //上边点入栈
						}

						if (_lableImg.at<int>(curX + 1, curY) == 1)
						{// 下点 
							neighborPixels.push(std::pair<int, int>(curX + 1, curY)); //下边点入栈
						}
						//===============补充到8连通域======================================================
						if (_lableImg.at<int>(curX - 1, curY - 1) == 1)
						{// 左上点 
							neighborPixels.push(std::pair<int, int>(curX - 1, curY - 1)); //左上点入栈
						}

						if (_lableImg.at<int>(curX - 1, curY + 1) == 1)
						{// 右上点 
							neighborPixels.push(std::pair<int, int>(curX - 1, curY + 1)); //右上点入栈
						}

						if (_lableImg.at<int>(curX + 1, curY - 1) == 1)
						{// 左下点 
							neighborPixels.push(std::pair<int, int>(curX + 1, curY - 1)); //左下点入栈
						}

						if (_lableImg.at<int>(curX + 1, curY + 1) == 1)
						{// 右下点 
							neighborPixels.push(std::pair<int, int>(curX + 1, curY + 1)); //右下点入栈
						}
					//===============补充到8连通域======================================================
				}
			}
		}
	}
	iConnectedAreaCount = label - 1; //因为label从2开始计数的
	int a = 0;
}
###########################################################
//#############添加颜色#####################################
Mat PaintColor(Mat src, int iConnectedAreaCount)
{
	int rows = src.rows;
	int cols = src.cols;

	//cv::Scalar(b, g, r);
	std::map<int, cv::Scalar> colors;
	for (int n = 1; n <= iConnectedAreaCount + 1; n++)
	{
		colors[n] = icvprGetRandomColor(); //根据不同标志位产生随机颜色

		cv::Scalar color = colors[n];
		int a = color[0];
		int b = color[1];
		int c = color[2];
		int d = 0;
	}

	Mat dst2(rows, cols, CV_8UC3);
	dst2 = cv::Scalar::all(0);
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			int value = src.at<int>(i, j);
			if (value>1)
			{
				cv::Scalar color = colors[value];
				int a = color[0];
				int b = color[1];
				int c = color[2];
				dst2.at<Vec3b>(i, j)[0] = color[0];
				dst2.at<Vec3b>(i, j)[1] = color[1];
				dst2.at<Vec3b>(i, j)[2] = color[2];
			}
		}
	}
	return dst2;
}
//#############添加颜色##################################

//########调用##########################################
  Mat binImage = cv::imread("D:\\sxl\\处理图片\\testImages\\22.jpg", 0);
	threshold(binImage, binImage, 50, 1, CV_THRESH_BINARY_INV);

	// 连通域标记 
	Mat labelImg;
	int iConnectedAreaCount = 0; //连通域个数
	ConnectedCountBySeedFill(binImage, labelImg, iConnectedAreaCount);//针对黑底白字
	int a=iConnectedAreaCount;
	
	// 显示结果
	Mat dstColor2=PaintColor(labelImg,iConnectedAreaCount);
	imshow("colorImg", dstColor2);

	Mat grayImg;
	labelImg *= 10;
	labelImg.convertTo(grayImg, CV_8UC1);
	imshow("labelImg", grayImg);

	waitKey(0);
//########调用##########################################

补充知识:Opencv快速获取连通域

对于ndarray数据中的连通域查找,opencv提供了接口,非常方便。

import cv2
import numpy as np

img = np.array([
  [0, 255, 255, 0, 0, 0, 255, 255,],
  [0, 0, 255, 0, 255, 255, 255, 0],
  [0, 0, 0, 0, 255, 255, 0, 255],
  [255, 255, 0, 0, 0, 0, 0, 0],
  [255, 255, 0, 0, 0, 0, 0, 0],
  [255, 255, 0, 0, 0, 0, 0, 0]
], dtype=np.uint8)

num, labels = cv2.connectedComponents(img)
labels_dict = {i:[] for i in range(1, num+1)}
height, width = img.shape
for h in range(height):
  for w in range(width):
    if labels[h][w] in labels_dict:
      labels_dict[labels[h][w]].append([h,w])

cv2.connectedComponents()函数返回查找到的连通域个数和对应的label。

上面代码返回连通域个数为4(包含值为0区域,可通过lables过滤), labels结果如图所示:

使用OpenCV获取图片连通域数量,并用不同颜色标记函

以上这篇使用OpenCV获取图片连通域数量,并用不同颜色标记函就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Django中redis的使用方法(包括安装、配置、启动)
Feb 21 Python
django反向解析和正向解析的方式
Jun 05 Python
Python多线程编程之多线程加锁操作示例
Sep 06 Python
OpenCV3.0+Python3.6实现特定颜色的物体追踪
Jul 23 Python
PyTorch的Optimizer训练工具的实现
Aug 18 Python
树莓派极简安装OpenCv的方法步骤
Oct 10 Python
Python matplotlib修改默认字体的操作
Mar 05 Python
python如何爬取网页中的文字
Jul 28 Python
python Gabor滤波器讲解
Oct 26 Python
BeautifulSoup获取指定class样式的div的实现
Dec 07 Python
Python 打印自己设计的字体的实例讲解
Jan 04 Python
详解Go语言运用广度优先搜索走迷宫
Jun 23 Python
Python urllib2运行过程原理解析
Jun 04 #Python
Python如何生成xml文件
Jun 04 #Python
基于python代码批量处理图片resize
Jun 04 #Python
Python脚本如何在bilibili中查找弹幕发送者
Jun 04 #Python
Python爬虫谷歌Chrome F12抓包过程原理解析
Jun 04 #Python
python实现按键精灵找色点击功能教程,使用pywin32和Pillow库
Jun 04 #Python
解决python图像处理图像赋值后变为白色的问题
Jun 04 #Python
You might like
PHP 网络开发详解之远程文件包含漏洞
2010/04/25 PHP
PHP的异常处理类Exception的使用及说明
2012/06/13 PHP
php打开远程文件的方法和风险及解决方法
2013/11/12 PHP
php实现的漂亮分页方法
2014/04/17 PHP
php常用数学函数汇总
2014/11/21 PHP
php无序树实现方法
2015/07/28 PHP
Yii针对添加行的增删改查操作示例
2016/10/18 PHP
Laravel5.5+ 使用API Resources快速输出自定义JSON方法详解
2020/04/06 PHP
js focus不起作用的解决方法(主要是因为dom元素是否加载完成)
2010/11/05 Javascript
JavaScript编程中容易出BUG的几点小知识
2015/01/31 Javascript
JavaScript函数作用域链分析
2015/02/13 Javascript
javascript的正则匹配方法学习
2016/02/24 Javascript
JavaScript数组去重的两种方法推荐
2016/04/05 Javascript
JavaScript函数柯里化详解
2016/04/29 Javascript
js实现文本上下来回滚动
2017/02/03 Javascript
详解angularjs popup-table 弹出框表格指令
2017/09/20 Javascript
iview通过Dropdown(下拉菜单)实现的右键菜单
2018/10/26 Javascript
javascript实现对话框功能警告(alert 消息对话框)确认(confirm 消息对话框)
2019/05/07 Javascript
微信小程序实现单个卡片左滑显示按钮并防止上下滑动干扰功能
2019/12/06 Javascript
vantUI 获得piker选中值的自定义ID操作
2020/11/04 Javascript
Python使用reportlab将目录下所有的文本文件打印成pdf的方法
2015/05/20 Python
python写日志封装类实例
2015/06/28 Python
对Python w和w+权限的区别详解
2019/01/23 Python
Python基于模块Paramiko实现SSHv2协议
2020/04/28 Python
python 安装移动复制第三方库操作
2020/07/13 Python
python实现从ftp上下载文件的实例方法
2020/07/19 Python
Perricone MD裴礼康美国官网:抗衰老护肤品
2016/09/26 全球购物
Bealls Florida百货商店:生活服饰、家居装饰和鞋子
2018/02/23 全球购物
Otticanet美国:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/03/10 全球购物
简述网络文件系统NFS,并说明其作用
2016/10/19 面试题
黄河的主人教学反思
2014/02/07 职场文书
《地震中的父与子》教学反思
2014/04/10 职场文书
小学班主任经验交流材料
2014/12/16 职场文书
婚宴邀请函
2015/01/30 职场文书
如何书写民事调解协议书?
2019/06/25 职场文书
AngularJS实现多级下拉框
2022/03/25 Javascript