使用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生成器以及应用实例解析
Feb 08 Python
Python利用heapq实现一个优先级队列的方法
Feb 03 Python
Python正则表达式匹配和提取IP地址
Jun 06 Python
wxpython实现按钮切换界面的方法
Nov 19 Python
详解python 破解网站反爬虫的两种简单方法
Feb 09 Python
python+requests接口压力测试500次,查看响应时间的实例
Apr 30 Python
pyecharts在数据可视化中的应用详解
Jun 08 Python
使用keras实现BiLSTM+CNN+CRF文字标记NER
Jun 29 Python
pytorch 实现在测试的时候启用dropout
May 27 Python
使用pycharm运行flask应用程序的详细教程
Jun 07 Python
OpenCV-Python实现怀旧滤镜与连环画滤镜
Jun 09 Python
Python编程中内置的NotImplemented类型的用法
Mar 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自动适应范围的分页代码
2008/08/05 PHP
PHP中两个float(浮点数)比较实例分析
2015/09/27 PHP
PHP支付系统设计与典型案例分享
2016/08/02 PHP
PHP实现的简单对称加密与解密方法实例小结
2017/08/28 PHP
PHP进阶学习之类的自动加载机制原理分析
2019/06/18 PHP
Laravel 简单实现Ajax滚动加载示例
2019/10/22 PHP
一组JS创建和操作表格的函数集合
2009/05/07 Javascript
json 实例详细说明教程
2009/10/31 Javascript
基于jquery的分页控件(C#)
2011/01/06 Javascript
javascript获取和判断浏览器窗口、屏幕、网页的高度、宽度等
2014/05/08 Javascript
用js格式化金额可设置保留的小数位数
2014/05/09 Javascript
jQuery中prevUntil()方法用法实例
2015/01/08 Javascript
JavaScript 学习笔记之数据类型
2015/01/14 Javascript
基于jquery实现左右按钮点击的图片切换效果
2021/01/27 Javascript
JSON在Javascript中的使用(eval和JSON.parse的区别)详细解析
2017/09/05 Javascript
vue中使用codemirror的实例详解
2018/11/01 Javascript
vue父子组件的通信方法(实例详解)
2019/11/10 Javascript
小程序新版订阅消息模板消息
2019/12/31 Javascript
JavaScript复制变量三种方法实例详解
2020/01/09 Javascript
在Python的Django框架的视图中使用Session的方法
2015/07/23 Python
python一键升级所有pip package的方法
2017/01/16 Python
win10安装python3.6的常见问题
2020/07/01 Python
测试驱动开发的主要步骤是什么
2014/12/10 面试题
学生学习总结的自我评价
2013/10/22 职场文书
小孩百日宴答谢词
2014/01/15 职场文书
高中生操行评语
2014/04/25 职场文书
师范生求职自荐信
2014/06/14 职场文书
咖啡店创业计划书
2014/08/15 职场文书
党员对照检查材料整改措施思想汇报
2014/09/26 职场文书
2014年中班下学期工作总结
2014/12/11 职场文书
写给老师的感谢信
2015/01/20 职场文书
2015年政府采购工作总结
2015/05/21 职场文书
学校就业保障协议书
2019/06/24 职场文书
基于CSS3画一个iPhone
2021/04/21 HTML / CSS
Nginx反向代理配置的全过程记录
2021/06/22 Servers
SQL Server使用T-SQL语句批处理
2022/05/20 SQL Server