千家信息网

C++中Opencv的imfill孔洞填充函数怎么用

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇文章主要为大家展示了"C++中Opencv的imfill孔洞填充函数怎么用",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C++中Opencv的imfi
千家信息网最后更新 2025年01月19日C++中Opencv的imfill孔洞填充函数怎么用

这篇文章主要为大家展示了"C++中Opencv的imfill孔洞填充函数怎么用",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C++中Opencv的imfill孔洞填充函数怎么用"这篇文章吧。

函数实现的中心思想

二值图

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

寻找连通域的关键

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

种子点的确定

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

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

连通域的寻找过程

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

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

条件设定

在经过以上的寻找过程后,得到的结果必然是全白的图像,而我们只想要填充孔洞,所以我们需要去除不符合的连通域。所谓孔洞,其实就是周围被像素值为255的点包围起来的连通域,但是,有一些连通域,直接和图像的边界相连,而这并不是我们想要的, 至少不是我想要的,(如果大家有不同的需求,程序也是很容易改过去的)。所以,我需要一个标志位,当这个连通域中的像素点接触到边界后,给这个连通域一个标记。在下面的程序中,我用vector> 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 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>> lenm;//三维point向量 lenm.size()是连通域的个数        /*        int impixel_sum = 0;        for (int j = 0,j> numim;        vector ssinum;        vector> Flag;        vector 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(row, col) == 0)                        {                                ce.push_back(1);                                Flag.push_back(ce);                                //vector> numim;                                //vector ssinum;                                ssinum.push_back(Point(col, row));                                numim.push_back(ssinum);                                fcop.at(row, col) = 255;                                ssinum.clear();                                s1 = 1;                                while (s1 > 0)                                {                                        //ce.push_back(1);                                        //Flag.push_back(ce);                                        //vector 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(Y, X) == 0)                                                                {                                                                        ssinum.push_back(Point(X, Y));                                                                        fcop.at(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(Y, X) = 255;                                }                        }                }        }        return ffcop;}

主函数代码

#include#include#include"imfill.h"using namespace std;using namespace cv;Mat src;vector>  lunk;vector 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孔洞填充函数怎么用"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

0