您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“C++中Opencv的imfill孔洞填充函數怎么用”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“C++中Opencv的imfill孔洞填充函數怎么用”這篇文章吧。
此程序針對于二值圖,尋找二值圖中 像素值為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個連通域像素點個數的求和。
在經過以上的尋找過程后,得到的結果必然是全白的圖像,而我們只想要填充孔洞,所以我們需要去除不符合的連通域。所謂孔洞,其實就是周圍被像素值為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孔洞填充函數怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。