在Matlab下,使用imfill可以很容易地完成孔洞填充操作。下面文章主要介绍C Opencv imfill的孔洞填充函数的实现思路和代码,通过示例代码进行了非常详细的介绍。有需要的朋友可以参考一下。
目录
功能实现的中心思想二元图
寻找连通域的关键
种子点的确定
连通域的搜索过程
条件设置
最终任务
话不多说,直接上功能代码。主功能代码框截图。示例图片摘要
功能实现的中心思想
二元图
这个程序针对二值图,在二值图中找到像素值为0的连通域,分别保存所有连通域的像素,将合格连通域的像素值设置为255;
寻找连通域的关键
对于填洞功能的实现,也就是设置0到255的过程,我们需要以四个连通度为基点进行搜索。
种子点的确定
寻找种子点实际上就是在二值图中寻找像素值为0的点。我们可以直接遍历二值图中的像素,确定像素值为0的第一个点作为第一个连通域的种子点。这时候可能会有朋友疑惑,因为根据我的看法,在遍历的过程中,第n个值为0的像素就是第n个连通域的种子点。再者,在整个遍历过程中,像素值为0的像素个数就是连通域的个数。
是啊!
当然,如果要实现这一点,那么我们需要在搜索每个连通域的过程中,立即将所有找到的点设置为255(这里不一定是255,只要不是0就行)。所以当我们在搜索之后遍历二进制图时,已经找到的连通域中所有像素的值都是255。当再次找到像素值为0的像素时,这个像素一定是下一个要找到的像素。
连通域的搜索过程
首先,创建一个四连接向量,vectorPoint upp用于存储上、下、前、后四个点创建vectorvectorvectorPoint lenm它用于存储所有连接的域。至于为什么要创建一个三维点数组,可以先看看关于这个三维数组的注释(下面的公式是程序里有对应的注释),了解每个维度的含义。结合节目,我想你能看懂。简单重复一下,lenm.size()是连通域的个数。
如图所示;是函数第I个连通域的像素数之和。
条件设置
经过上面的搜索过程,结果一定是全白图像,我们只想填补空洞,所以需要去除不整合连通域。所谓的洞,其实就是由像素值为255的点围成的连通域。但是,有一些连通域是直接与图像的边界相连的,而这不是我们想要的,至少不是我想要的。(如果每个人的需求不一样,程序很容易改)。所以,我需要一个标志位来标记连通域,当连通域中的像素触及边界时。在下面的程序中,我使用vectorvectorint标志;以存储标记点,其中Flag[i]表示第I个连通域的标记点。程序中,找到种子点后,先设置第I个连通域的标志[I][0]=1;如果在这个连通域中存在边界点,那么Flag[I][0]=0;(程序里,这里好像有个小BUG,先不改了[])
最终任务
所有找到的连通域中的flag[I][0]==1;{其中I属于[0,Flag.size())}是满足条件的连通域,所以放len[I];中的所有像素都可以赋值为255。
话不多说,直接上功能代码。
输入二元图;
返回二元图;
垫填充(垫铜)
{
Mat fcop
COP . copy to(fcop);
向量点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));
向量向量向量点lenm//三维要点向量lenm.size()是连通域的个数
/*
int imp xel _ sum=0;
for (int j=0,jlenm[i]).size();j)
{
imp xel _ sum=lenm[I][j].size();
}
//这段循环表示第我个连通域中像素点的个数。
*/
向量向量点numim
向量点西努姆
向量向量标志;
向量ce;
int nmss=0;//连通域的个数;
int nums=0;//中间变量用来存储伦姆。size();即在程序运行过程中nums始终等于lenm[i][j][k]中的j的值的大小;
int S1=0;
//标志位,每次区域生长后符合条件的像素个数,当第我个连通域,在经过第j次生长后,s1=lenm[i][j].大小(),
//若s1==0,表示生长结束,不再有符合条件的点,第我连通域中的所有点都已经找到。
for(int row=0;行fcop.rows行)
{
for(int col=0;col fcop.colscol)
{
if (fcop.atuchar(row,col)==0)
{
ce。push _ back(1);
旗帜。push _ back(ce);
//vector向量点numim
//向量点SSI num
ssinum.push_back(Point(col,row));
努米姆。push _ back(ssinum);
fcop.atuchar(row,col)=255;
西努姆。clear();
S1=1;
当(s1 0)
{
//ce。push _ back(1);
//标志。push _ back(ce);
//向量点SSI num
for(int I=0;我努米姆[努姆斯].size();我)
{
for(int j=0;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.atuchar(Y,X)==0)
{
ssinum.push_back(Point(X,Y));
fcop.atuchar(Y,X)=255;
}
}
if(X==0 | | Y==0 | | X==fcop。cols-1 | | Y==fcop。第1行)
{
flag[nmss][0]=0;
}
}
}
//标志。push _ back(ce);
努米姆。push _ back(ssinum);
S1=SSI编号。size();
nums
西努姆。clear();
/* ce。clear();*/
}
nums=0;
伦姆。push _ back(numim);
努米姆。clear();
网络管理系统
ce。clear();
}
}
}
//imshow('1 ',fcop);
Mat ffcop
警察。复制到(ff COP);
//ffcop=Mat:zeros(cop.size()、cop。type());
for(int I=0;我举旗。size();我)
{
if (Flag[i][0]==1)
{
for(int j=0;伦姆[我]。size();j)
{
for(int k=0;k伦姆[i][j].size();k)
{
int X=lenm[i][j][k].x;
int Y=lenm[i][j][k].y;
ffcop.atchar(Y,X)=255;
}
}
}
}
返回ffcop
}
主函数代码
# includeopenv2/opencv。HPP
#includeiostream
#包含" imfill.h "
使用命名空间标准
使用名称空间cv;
Mat src
向量向量点
vectorVec4i级;
//RNG rn;
int main()
{
src=im read(' 5。jpg’);
//imshow('万丈高楼第一步,src);
夏令时,灰色,尔智;
blur(src,dst,Size(3,3),Point(-1,-1));
//imshow('均值滤波,dst);
cvtColor(dst,灰色,COLOR _ bgr 2灰色);
//imshow('灰度图,灰色);
Canny(灰色,尔志,100,200,3,假);
//imshow('边缘检测,尔志);
垫子holef
holef=imfill(二支);
imshow('填洞,holef);
等待键(0);
返回0;
}
代码框截图
实例图片
运行结果
总结
此程序会填充所有的孔洞,如果想只填充指定阈值范围内的孔洞,需要再多计算每个连通域像素的个数即可,因为所有数据都已经存了下来,所以计算会比较简单。
到此这篇关于C Opencv imfill孔洞填充函数的文章就介绍到这了,更多相关C Opencv imfill孔洞填充函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。