使用OpenCV去除面积较小的连通域


Posted in Python onJuly 05, 2020

这是后期补充的部分,和前期的代码不太一样

效果图

使用OpenCV去除面积较小的连通域

源代码

//测试
void CCutImageVS2013Dlg::OnBnClickedTestButton1()
{
	vector<vector<Point> > contours;  //轮廓数组
	vector<Point2d> centers;    //轮廓质心坐标 
	vector<vector<Point> >::iterator itr; //轮廓迭代器
	vector<Point2d>::iterator itrc;  //质心坐标迭代器
	vector<vector<Point> > con;   //当前轮廓

	double area;
	double minarea = 1000;
	double maxarea = 0;
	Moments mom;       // 轮廓矩
	Mat image, gray, edge, dst;
	image = imread("D:\\66.png");
	cvtColor(image, gray, COLOR_BGR2GRAY);
	Mat rgbImg(gray.size(), CV_8UC3); //创建三通道图
	blur(gray, edge, Size(3, 3));       //模糊去噪
	threshold(edge, edge, 200, 255, THRESH_BINARY_INV); //二值化处理,黑底白字
	//--------去除较小轮廓,并寻找最大轮廓--------------------------
	findContours(edge, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //寻找轮廓
	itr = contours.begin();    //使用迭代器去除噪声轮廓
	while (itr != contours.end())
	{
		area = contourArea(*itr);  //获得轮廓面积
		if (area<minarea)    //删除较小面积的轮廓 
		{
			itr = contours.erase(itr); //itr一旦erase,需要重新赋值
		}
		else
		{
			itr++;
		}
		if (area>maxarea)    //寻找最大轮廓
		{
			maxarea = area;
		}
	}
	dst = Mat::zeros(image.rows, image.cols, CV_8UC3);
	/*绘制连通区域轮廓,计算质心坐标*/
	Point2d center;
	itr = contours.begin();
	while (itr != contours.end())
	{
		area = contourArea(*itr);		
		con.push_back(*itr);   //获取当前轮廓
		if (area == maxarea)
		{
			vector<Rect> boundRect(1); //定义外接矩形集合
			boundRect[0] = boundingRect(Mat(*itr));
			cvtColor(gray, rgbImg, COLOR_GRAY2BGR);
			Rect select;
			select.x = boundRect[0].x;
			select.y = boundRect[0].y;
			select.width = boundRect[0].width;
			select.height = boundRect[0].height;
			rectangle(rgbImg, select, Scalar(0, 255, 0), 3, 2); //用矩形画矩形窗
			drawContours(dst, con, -1, Scalar(0, 0, 255), 2); //最大面积红色绘制
		}
		else
			drawContours(dst, con, -1, Scalar(255, 0, 0), 2); //其它面积蓝色绘制
		con.pop_back();
		//计算质心
		mom = moments(*itr);
		center.x = (int)(mom.m10 / mom.m00);
		center.y = (int)(mom.m01 / mom.m00);
		centers.push_back(center);
		itr++;
	}
	imshow("rgbImg", rgbImg);
	//imshow("gray", gray);
	//imshow("edge", edge);
	imshow("origin", image);
	imshow("connected_region", dst);
	waitKey(0);
	return;
}

前期做的,方法可能不太一样

一,先看效果图

原图

使用OpenCV去除面积较小的连通域

处理前后图

使用OpenCV去除面积较小的连通域

二,实现源代码

//=======函数实现=====================================================================
void RemoveSmallRegion(Mat &Src, Mat &Dst, int AreaLimit, int CheckMode, int NeihborMode)
{
	int RemoveCount = 0;
	//新建一幅标签图像初始化为0像素点,为了记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查 
	//初始化的图像全部为0,未检查 
	Mat PointLabel = Mat::zeros(Src.size(), CV_8UC1);
	if (CheckMode == 1)//去除小连通区域的白色点 
	{
		//cout << "去除小连通域.";
		for (int i = 0; i < Src.rows; i++)
		{
			for (int j = 0; j < Src.cols; j++)
			{
				if (Src.at<uchar>(i, j) < 10)
				{
					PointLabel.at<uchar>(i, j) = 3;//将背景黑色点标记为合格,像素为3 
				}
			}
		}
	}
	else//去除孔洞,黑色点像素 
	{
		//cout << "去除孔洞";
		for (int i = 0; i < Src.rows; i++)
		{
			for (int j = 0; j < Src.cols; j++)
			{
				if (Src.at<uchar>(i, j) > 10)
				{
					PointLabel.at<uchar>(i, j) = 3;//如果原图是白色区域,标记为合格,像素为3 
				}
			}
		}
	}
	vector<Point2i>NeihborPos;//将邻域压进容器 
	NeihborPos.push_back(Point2i(-1, 0));
	NeihborPos.push_back(Point2i(1, 0));
	NeihborPos.push_back(Point2i(0, -1));
	NeihborPos.push_back(Point2i(0, 1));
	if (NeihborMode == 1)
	{
		//cout << "Neighbor mode: 8邻域." << endl;
		NeihborPos.push_back(Point2i(-1, -1));
		NeihborPos.push_back(Point2i(-1, 1));
		NeihborPos.push_back(Point2i(1, -1));
		NeihborPos.push_back(Point2i(1, 1));
	}
	else int a = 0;//cout << "Neighbor mode: 4邻域." << endl;
	int NeihborCount = 4 + 4 * NeihborMode;
	int CurrX = 0, CurrY = 0;
	//开始检测 
	for (int i = 0; i < Src.rows; i++)
	{
		for (int j = 0; j < Src.cols; j++)
		{
			if (PointLabel.at<uchar>(i, j) == 0)//标签图像像素点为0,表示还未检查的不合格点 
			{ //开始检查 
				vector<Point2i>GrowBuffer;//记录检查像素点的个数 
				GrowBuffer.push_back(Point2i(j, i));
				PointLabel.at<uchar>(i, j) = 1;//标记为正在检查 
				int CheckResult = 0;
				for (int z = 0; z < GrowBuffer.size(); z++)
				{
					for (int q = 0; q < NeihborCount; q++)
					{
						CurrX = GrowBuffer.at(z).x + NeihborPos.at(q).x;
						CurrY = GrowBuffer.at(z).y + NeihborPos.at(q).y;
						if (CurrX >= 0 && CurrX<Src.cols&&CurrY >= 0 && CurrY<Src.rows) //防止越界 
						{
							if (PointLabel.at<uchar>(CurrY, CurrX) == 0)
							{
								GrowBuffer.push_back(Point2i(CurrX, CurrY)); //邻域点加入buffer 
								PointLabel.at<uchar>(CurrY, CurrX) = 1;   //更新邻域点的检查标签,避免重复检查 
							}
						}
					}
				}
				if (GrowBuffer.size()>AreaLimit) //判断结果(是否超出限定的大小),1为未超出,2为超出 
					CheckResult = 2;
				else
				{
					CheckResult = 1;
					RemoveCount++;//记录有多少区域被去除 
				}
				for (int z = 0; z < GrowBuffer.size(); z++)
				{
					CurrX = GrowBuffer.at(z).x;
					CurrY = GrowBuffer.at(z).y;
					PointLabel.at<uchar>(CurrY, CurrX) += CheckResult;//标记不合格的像素点,像素值为2 
				}
				//********结束该点处的检查********** 
			}
		}
	}
	CheckMode = 255 * (1 - CheckMode);
	//开始反转面积过小的区域 
	for (int i = 0; i < Src.rows; ++i)
	{
		for (int j = 0; j < Src.cols; ++j)
		{
			if (PointLabel.at<uchar>(i, j) == 2)
			{
				Dst.at<uchar>(i, j) = CheckMode;
			}
			else if (PointLabel.at<uchar>(i, j) == 3)
			{
				Dst.at<uchar>(i, j) = Src.at<uchar>(i, j);
			}
		}
	}
	//cout << RemoveCount << " objects removed." << endl;
}
//=======函数实现=====================================================================
//=======调用函数=====================================================================
	Mat img;
	img = imread("D:\\1_1.jpg", 0);//读取图片
	threshold(img, img, 128, 255, CV_THRESH_BINARY_INV);
	imshow("去除前", img);
	Mat img1;
	RemoveSmallRegion(img, img, 200, 0, 1);
	imshow("去除后", img);
	waitKey(0);
//=======调用函数=====================================================================

以上这篇使用OpenCV去除面积较小的连通域就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python数据结构之二叉树的遍历实例
Apr 29 Python
使用Python的Tornado框架实现一个一对一聊天的程序
Apr 25 Python
六个窍门助你提高Python运行效率
Jun 09 Python
详解Python的collections模块中的deque双端队列结构
Jul 07 Python
Python字典实现简单的三级菜单(实例讲解)
Jul 31 Python
python opencv读mp4视频的实例
Dec 07 Python
Python实现微信消息防撤回功能的实例代码
Apr 29 Python
Django model update的多种用法介绍
Mar 28 Python
Python定义一个函数的方法
Jun 15 Python
python实现将中文日期转换为数字日期
Jul 14 Python
安装并免费使用Pycharm专业版(学生/教师)
Sep 24 Python
基于python获取本地时间并转换时间戳和日期格式
Oct 27 Python
学python最电脑配置有要求么
Jul 05 #Python
浅谈OpenCV中的新函数connectedComponentsWithStats用法
Jul 05 #Python
python怎么对数字进行过滤
Jul 05 #Python
python主要用于哪些方向
Jul 05 #Python
python右对齐的实例方法
Jul 05 #Python
使用Python-OpenCV消除图像中孤立的小区域操作
Jul 05 #Python
python使用opencv resize图像不进行插值的操作
Jul 05 #Python
You might like
一个简单的MySQL数据浏览器
2006/10/09 PHP
php bootstrap实现简单登录
2016/03/08 PHP
Joomla开启SEF的方法
2016/05/04 PHP
ThinkPHP的SAE开发相关注意事项详解
2016/10/09 PHP
浅谈PHP实现大流量下抢购方案
2017/12/15 PHP
经典的带阴影的可拖动的浮动层
2006/06/26 Javascript
extJS中常用的4种Ajax异步提交方式
2014/03/07 Javascript
JavaScript模拟可展开、拖动与关闭的聊天窗口实例
2015/05/12 Javascript
JS实现的竖向折叠菜单代码
2015/10/21 Javascript
JavaScript实现简单获取当前网页网址的方法
2015/11/09 Javascript
BootStrap的弹出框(Popover)支持鼠标移到弹出层上弹窗层不隐藏的原因及解决办法
2016/04/03 Javascript
jquery实现图片上传前本地预览功能
2016/05/10 Javascript
基于jQuery的AJAX和JSON实现纯html数据模板
2016/08/09 Javascript
Javascript 闭包详解及实例代码
2016/11/30 Javascript
angularjs实现天气预报功能
2020/06/16 Javascript
Vue2.5 结合 Element UI 之 Table 和 Pagination 组件实现分页功能
2018/01/26 Javascript
Angular4 反向代理Details实践
2018/05/30 Javascript
Puppet的一些技巧
2018/09/17 Javascript
微信小程序实现点击卡片 翻转效果
2019/09/04 Javascript
vue实现编辑器键盘抬起时内容跟随光标距顶位置向上滚动效果
2020/05/28 Javascript
微信小程序实现电子签名功能
2020/07/29 Javascript
Python struct.unpack
2008/09/06 Python
使用Python进行稳定可靠的文件操作详解
2013/12/31 Python
numpy中以文本的方式存储以及读取数据方法
2018/06/04 Python
利用Pandas和Numpy按时间戳将数据以Groupby方式分组
2019/07/22 Python
Pytorch使用PIL和Numpy将单张图片转为Pytorch张量方式
2020/05/25 Python
Adobe Html5 Extension开发初体验图文教程
2017/11/14 HTML / CSS
军训考核自我鉴定
2014/02/13 职场文书
企业安全生产月活动总结
2014/07/05 职场文书
奉献家乡演讲稿
2014/09/13 职场文书
教师群众路线教育实践活动学习笔记
2014/11/05 职场文书
2015年话务员工作总结
2015/04/29 职场文书
python 实现mysql自动增删分区的方法
2021/04/01 Python
python实现MD5进行文件去重的示例代码
2021/07/09 Python
MySQL笔记 —SQL运算符
2022/01/18 MySQL
Redis高可用集群redis-cluster详解
2022/03/20 Redis