使用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 相关文章推荐
Python 过滤字符串的技巧,map与itertools.imap
Sep 06 Python
使用BeautifulSoup爬虫程序获取百度搜索结果的标题和url示例
Jan 19 Python
Python使用scrapy采集时伪装成HTTP/1.1的方法
Apr 08 Python
用实例解释Python中的继承和多态的概念
Apr 27 Python
Python通过matplotlib画双层饼图及环形图简单示例
Dec 15 Python
python3.6+opencv3.4实现鼠标交互查看图片像素
Feb 26 Python
python中使用PIL制作并验证图片验证码
Mar 15 Python
python 实现视频 图像帧提取
Dec 10 Python
Python3 集合set入门基础
Feb 10 Python
通过python连接Linux命令行代码实例
Feb 18 Python
在keras中对单一输入图像进行预测并返回预测结果操作
Jul 09 Python
浅谈python数据类型及其操作
May 25 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设计模式之代理模式的深入解析
2013/06/13 PHP
php保存二进制原始数据为图片的程序代码
2014/10/14 PHP
mysql_connect localhost和127.0.0.1的区别(网络层阐述)
2015/03/26 PHP
PHP实现加强版加密解密类实例
2015/07/29 PHP
浅谈PHP中的
2016/04/23 PHP
php+redis实现消息队列功能示例
2019/09/19 PHP
Mac下关于PHP环境和扩展的安装详解
2019/10/17 PHP
PHP中类与对象功能、用法实例解读
2020/03/27 PHP
jQuery源码分析-03构造jQuery对象-源码结构和核心函数
2011/11/14 Javascript
jquery无缝向上滚动实现代码
2013/03/29 Javascript
JS仿iGoogle自定义首页模块拖拽特效的方法
2015/02/13 Javascript
JavaScript父子窗体间的调用方法
2015/03/31 Javascript
jQuery1.9.1源码分析系列(十六)ajax之ajax框架
2015/12/04 Javascript
jQuery fadeOut 异步实例代码详解
2016/08/18 Javascript
在vue中添加Echarts图表的基本使用教程
2017/11/22 Javascript
Vue三层嵌套路由的示例代码
2018/05/05 Javascript
ES6 新增的创建数组的方法(小结)
2019/08/01 Javascript
解决使用layui对select append元素无效或者未及时更新的问题
2019/09/18 Javascript
[01:00:30]完美世界DOTA2联赛循环赛 Inki vs Matador BO2第二场 10.31
2020/11/02 DOTA
python正则表达式判断字符串是否是全部小写示例
2013/12/25 Python
python基础教程之类class定义使用方法
2014/02/20 Python
用于统计项目中代码总行数的Python脚本分享
2015/04/21 Python
python利用正则表达式提取字符串
2016/12/08 Python
python3实现点餐系统
2019/01/24 Python
python pygame实现滚动横版射击游戏城市之战
2019/11/25 Python
Python 矩阵转置的几种方法小结
2019/12/02 Python
python输出数学符号实例
2020/05/11 Python
python爬虫中url管理器去重操作实例
2020/11/30 Python
台湾全方位线上课程与职能学习平台:TibaMe
2019/12/04 全球购物
马德里运动鞋商店:Nigra Mercato
2020/02/16 全球购物
校庆活动策划方案
2014/06/05 职场文书
学校组织向国旗敬礼活动方案(中小学适用)
2014/09/27 职场文书
春季运动会开幕词
2015/01/28 职场文书
2015年办公室人员工作总结
2015/05/15 职场文书
文明礼仪主题班会
2015/08/13 职场文书
Python自动化工具之实现Excel转Markdown表格
2022/04/08 Python