使用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处理python编码问题
Mar 13 Python
python设置检查点简单实现代码
Jul 01 Python
Python内置函数的用法实例教程
Sep 08 Python
Python实现高效求解素数代码实例
Jun 30 Python
解决Python传递中文参数的问题
Aug 04 Python
剖析Python的Twisted框架的核心特性
May 25 Python
PHP统计代码行数的小代码
Sep 19 Python
Python获取时间戳代码实例
Sep 24 Python
关于Python中定制类的比较运算实例
Dec 19 Python
Python多线程threading join和守护线程setDeamon原理详解
Mar 18 Python
python使用建议与技巧分享(一)
Aug 17 Python
python小型的音频操作库mp3Play
Apr 24 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
PHP session有效期session.gc_maxlifetime
2011/04/20 PHP
php管理nginx虚拟主机shell脚本实例
2014/11/19 PHP
又拍云异步上传实例教程详解
2016/04/19 PHP
PHP mysqli事务操作常用方法分析
2017/07/22 PHP
yii框架redis结合php实现秒杀效果(实例代码)
2017/10/26 PHP
Div Select挡住的解决办法
2008/08/07 Javascript
Javascript 代码也可以变得优美的实现方法
2009/06/22 Javascript
JavaScript动态改变HTML页面元素例如添加或删除
2014/08/10 Javascript
javascript使用switch case实现动态改变超级链接文字及地址
2014/12/16 Javascript
jQuery中children()方法用法实例
2015/01/07 Javascript
nodejs简单实现TCP服务器端和客户端的聊天功能示例
2018/01/04 NodeJs
Vue底层实现原理总结
2018/02/17 Javascript
使用Node搭建reactSSR服务端渲染架构
2018/08/30 Javascript
原生js实现随机点名
2020/07/05 Javascript
浅谈Vue开发人员的7个最好的VSCode扩展
2021/01/20 Vue.js
小程序实现列表倒计时功能
2021/01/29 Javascript
JS+CSS实现动态时钟
2021/02/19 Javascript
Pyhthon中使用compileall模块编译源文件为pyc文件
2015/04/28 Python
Python numpy实现数组合并实例(vstack,hstack)
2018/01/09 Python
ActiveMQ:使用Python访问ActiveMQ的方法
2019/01/30 Python
在Pandas中处理NaN值的方法
2019/06/25 Python
Python shutil模块用法实例分析
2019/10/02 Python
详解Python在使用JSON时需要注意的编码问题
2019/12/06 Python
Keras 快速解决OOM超内存的问题
2020/06/11 Python
微软中国官方旗舰店:销售Surface、Xbox One、笔记本电脑、Office
2018/07/23 全球购物
澳大利亚家具和家居用品购物网站:Zanui
2018/12/29 全球购物
前台文员个人求职信范文
2014/01/05 职场文书
网上蛋糕店创业计划书
2014/01/24 职场文书
培训主管岗位职责
2014/02/01 职场文书
业务员简历自我评价
2014/03/06 职场文书
党的群众路线教育实践活动领导班子整改措施
2014/10/28 职场文书
关于法制教育的宣传语
2015/07/13 职场文书
python生成随机数、随机字符、随机字符串
2021/04/06 Python
Java spring单点登录系统
2021/09/04 Java/Android
Docker官方工具docker-registry案例演示
2022/04/13 Servers
Java实现字符串转为驼峰格式的方法详解
2022/07/07 Java/Android