c/c++语言开发共享C++ Opencv imfill孔洞填充函数的实现思路与代码

目录函数实现的中心思想二值图此程序针对于二值图,寻找二值图中 像素值为0的连通域,将所有连通域的像素点分别保存下来,将符合条件的连通域的像素值 置为255;寻找连通域的关键针对填洞功能的实现,也就是0

目录

        函数实现的中心思想

        二值图

        此程序针对于二值图,寻找二值图中 像素值为0的连通域,将所有连通域的像素点分别保存下来,将符合条件的连通域的像素值 置为255;

        寻找连通域的关键

        针对填洞功能的实现,也就是0置为255过程,我们需要以四连通为基本点进行寻找。

        种子点的确定

        寻找种子点,其实就是寻找二值图中像素值为0的点,我们可以直接采取 遍历 二值图 中的像素,将第一个遇见的像素值为0的点确定为 第一个连通域的种子点。这时候,有一些朋友可能会疑惑,因为按照我的说法,在遍历 的过程中,遇见的第n个像素值为0的点 就是第n个连通域的种子点,进一步说,在整个遍历过程中,遇见像素值为0的像素点的个数,就是连通域的个数。
        是的!

        当然,如果要实现这一点,那我们就需要在各个连通域的寻找的过程中,将找到的点全部立即置为255,(此处不一定非得是255,只要不是0即可)这样在寻找结束后,我们再遍历二值图时,已经找到的连通域中的所有像素点的值均为255,当再次找到像素值为0 的像素点时,此像素点必是下一个待寻找的连通域的种子点

        连通域的寻找过程

        首先创建四连通的向量,vector<point> upp;用来存储上下前后四个点,创建vector<vector<vector<point>>> lenm;用来存储所有的连通域,至于为什么要创建三维point数组,大家可以先看看关于这个三维数组的注释,(下面的公式就是,程序中也有相应的注释),了解清楚每一维代表的意义,再结合一下程序,我感觉大家应该可以明白,再简要赘述一下,lenm.size()为连通域的个数。

        如图所示;函数为第i个连通域像素点个数的求和。

        C++ Opencv imfill孔洞填充函数的实现思路与代码

        条件设定

        在经过以上的寻找过程后,得到的结果必然是全白的图像,而我们只想要填充孔洞,所以我们需要去除不符合的连通域。所谓孔洞,其实就是周围被像素值为255的点包围起来的连通域,但是,有一些连通域,直接和图像的边界相连,而这并不是我们想要的, 至少不是我想要的,(如果大家有不同的需求,程序也是很容易改过去的)。所以,我需要一个标志位,当这个连通域中的像素点接触到边界后,给这个连通域一个标记。在下面的程序中,我用vector<vector<int>> flag;来存储标记点,其中flag[i]表示第i个连通域的标记点。在程序中,找到种子点后,首先将第i个连通域的flag[i][0] = 1;,如果在此连通域中出现边界点,再flag[i][0] = 0;(在程序中,此处貌似有一个小bug,我就先不改了[😏])

        最后赋值

        在寻找到的所有连通域中,flag[i][0] == 1; {其中 i 属于 [0,flag.size()) }的连通域为符合要求的连通域,因此将lenm[i];中的所有像素点赋值255即可。

        话不多说 直接上函数代码

        输入二值图;

        返回二值图;

          mat imfill(mat cop)  {  	mat fcop;  	cop.copyto(fcop);  	vector<point> upp;//定义四连通点集,有必要可以是八连通  	upp.push_back(point(-1, 0));  	upp.push_back(point(0, -1));  	upp.push_back(point(0, 1));  	upp.push_back(point(1, 0));  	//upp.push_back(point(1, 1));  	//upp.push_back(point(-1,-1));  	//upp.push_back(point(-1, 1));  	//upp.push_back(point(1, -1));    	vector<vector<vector<point>>> lenm;//三维point向量 lenm.size()是连通域的个数  	/*  	int impixel_sum = 0;  	for (int j = 0,j<lenm[i].size();j++)  	{  	    impixel_sum+= lenm[i][j].size();  	}  	//这段循环 表示第i个连通域中 像素点的个数。  	*/  	vector<vector<point>> numim;  	vector<point> ssinum;  	vector<vector<int>> flag;  	vector<int> ce;    	int nmss = 0;//连通域的个数;  	int nums = 0;//中间变量 用来存储 lenm.size();即 在程序运行过程中 nums始终等于 lenm[i][j][k] 中的j 的 值的大小;  	int s1 = 0;  	//标志位 ,每次区域生长后 符合条件的像素个数,当第i个连通域,在经过第j次生长后,s1=lenm[i][j].size(),  	//若s1==0,表示生长结束,不再有符合条件的点,第i连通域中的所有点都已经找到。    	for (int row = 0; row < fcop.rows; row++)  	{  		for (int col = 0; col < fcop.cols; col++)  		{  			if (fcop.at<uchar>(row, col) == 0)  			{  				ce.push_back(1);  				flag.push_back(ce);  				//vector<vector<point>> numim;  				//vector<point> ssinum;  				ssinum.push_back(point(col, row));  				numim.push_back(ssinum);  				fcop.at<uchar>(row, col) = 255;  				ssinum.clear();  				s1 = 1;  				while (s1 > 0)  				{  					//ce.push_back(1);  					//flag.push_back(ce);  					//vector<point> ssinum;  					for (int i = 0; i < numim[nums].size(); i++)  					{  						for (int j = 0; j < upp.size(); j++)  						{  							int x = numim[nums][i].x + upp[j].x;  							int y = numim[nums][i].y + upp[j].y;  							if (x >= 0 && y >= 0 && x < fcop.cols && y < fcop.rows)  							{  								if (fcop.at<uchar>(y, x) == 0)  								{  									ssinum.push_back(point(x, y));  									fcop.at<uchar>(y, x) = 255;  								}  							}    							if (x == 0 || y == 0 || x == fcop.cols - 1 || y == fcop.rows - 1)  							{  								flag[nmss][0] = 0;    							}  						}  					}  					//flag.push_back(ce);  					numim.push_back(ssinum);  					s1 = ssinum.size();  					nums++;  					ssinum.clear();  					/*ce.clear();*/  				}  				nums = 0;  				lenm.push_back(numim);  				numim.clear();  				nmss++;  				ce.clear();  			}    		}  	}  	//imshow("1",fcop);  	mat ffcop;  	cop.copyto(ffcop);  	//ffcop = mat::zeros(cop.size(),cop.type());  	for (int i = 0; i < flag.size(); i++)  	{  		if (flag[i][0] == 1)  		{  			for (int j = 0; j < lenm[i].size(); j++)  			{  				for (int k = 0; k < lenm[i][j].size(); k++)  				{  					int x = lenm[i][j][k].x;  					int y = lenm[i][j][k].y;  					ffcop.at<char>(y, x) = 255;  				}  			}  		}  	}  	return ffcop;  }  

        主函数代码

          #include<opencv2/opencv.hpp>  #include<iostream>    #include"imfill.h"    using namespace std;  using namespace cv;    mat src;  vector<vector<point>>  lunk;  vector<vec4i> level;    //rng rn;  int main()  {  	src = imread("5.jpg");  	//imshow("万丈高楼第一步",src);    	mat dst, gray, erzhi;  	blur(src, dst, size(3, 3), point(-1, -1));  	//imshow("均值滤波",dst);    	cvtcolor(dst, gray, color_bgr2gray);  	//imshow("灰度图",gray);    	canny(gray, erzhi, 100, 200, 3, false);  	//imshow("边缘检测",erzhi);    	mat holef;  	holef = imfill(erzhi);  	imshow("填洞", holef);  	  	waitkey(0);  	return 0;  }  

        代码框截图

        C++ Opencv imfill孔洞填充函数的实现思路与代码

        实例图片

        C++ Opencv imfill孔洞填充函数的实现思路与代码

        运行结果

        C++ Opencv imfill孔洞填充函数的实现思路与代码

        总结

        此程序会填充所有的孔洞,如果想只填充指定阈值范围内的孔洞,需要再多计算每个连通域像素的个数即可,因为所有数据都已经存了下来,所以计算会比较简单。

        到此这篇关于c++ opencv imfill孔洞填充函数的文章就介绍到这了,更多相关c++ opencv imfill孔洞填充函数内容请搜索<计算机技术网(www.ctvol.com)!!>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<计算机技术网(www.ctvol.com)!!>!

        需要了解更多c/c++开发分享C++ Opencv imfill孔洞填充函数的实现思路与代码,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!

        本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

        ctvol管理联系方式QQ:251552304

        本文章地址:https://www.ctvol.com/c-cdevelopment/835386.html

        (0)
        上一篇 2021年9月26日
        下一篇 2021年9月26日

        精彩推荐