OpenCV實現(xiàn)圖像腐蝕
圖像的腐蝕過程與圖像的卷積操作類似,都需要模板矩陣來控制運算的結(jié)果,在圖像的腐蝕和膨脹中這個模板矩陣被稱為結(jié)構(gòu)元素。與圖像卷積相同,結(jié)構(gòu)元素可以任意指定圖像的中心點,并且結(jié)構(gòu)元素的尺寸和具體內(nèi)容都可以根據(jù)需求自己定義。定義結(jié)構(gòu)元素之后,將結(jié)構(gòu)元素的中心點依次放到圖像中每一個非0元素處,如果此時結(jié)構(gòu)元素內(nèi)所有的元素所覆蓋的圖像像素值均不為0,則保留結(jié)構(gòu)元素中心點對應(yīng)的圖像像素,否則將刪除結(jié)構(gòu)元素中心點對應(yīng)的像素。圖像的腐蝕過程示意圖如圖6-12所示,圖6-12中左側(cè)為待腐蝕的原圖像,中間為結(jié)構(gòu)元素,首先將結(jié)構(gòu)元素的中心與原圖像中的A像素重合,此時結(jié)構(gòu)元素中心點的左側(cè)和上方元素所覆蓋的圖像像素值均為0,因此需要將原圖像中的A像素刪除;當把結(jié)構(gòu)元素的中心點與B像素重合時,此時結(jié)構(gòu)元素中所有的元素所覆蓋的圖像像素值均為1,因此保留原圖像中的B像素。將結(jié)構(gòu)元素中心點依次與原圖像中的每個像素重合,判斷每一個像素點是否保留或者刪除,最終原圖像腐蝕的結(jié)果如圖中右側(cè)圖像所示。
圖像腐蝕可以用“Θ”表示,其數(shù)學表示形式如式(6.4)所示,通過公式可以發(fā)現(xiàn),其實對圖像A的腐蝕運算就是尋找圖像中能夠?qū)⒔Y(jié)構(gòu)元素B全部包含的像素點。
生成常用的矩形結(jié)構(gòu)元素、十字結(jié)構(gòu)元素和橢圓結(jié)構(gòu):
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
- shape:結(jié)構(gòu)元素的種類,可以選擇的參數(shù)及含義在表6-5中給出。
- ksize:結(jié)構(gòu)元素的尺寸大小
- anchor:中心點的位置,默認參數(shù)為結(jié)構(gòu)元素的幾何中心點。
該函數(shù)用于生成圖像形態(tài)學操作中常用的矩形結(jié)構(gòu)元素、十字結(jié)構(gòu)元素和橢圓結(jié)構(gòu)元素。函數(shù)第一個參數(shù)為生成結(jié)構(gòu)元素的種類,可以選擇的參數(shù)及含義在表給出,函數(shù)第二個參數(shù)是結(jié)構(gòu)元素的尺寸大小,能夠影響到圖像腐蝕的效果,一般情況下,結(jié)構(gòu)元素的種類相同時,結(jié)構(gòu)元素的尺寸越大腐蝕效果越明顯。函數(shù)的最后一個參數(shù)是結(jié)構(gòu)元素的中心點,只有十字結(jié)構(gòu)元素的中心點位置會影響圖像腐蝕后的輪廓形狀,其他種類的結(jié)構(gòu)元素的中心點位置只影響形態(tài)學操作結(jié)果的平移量。
腐蝕函數(shù)
void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
- src:輸入的待腐蝕圖像,圖像的通道數(shù)可以是任意的,但是圖像的數(shù)據(jù)類型必須是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。
- dst:腐蝕后的輸出圖像,與輸入圖像src具有相同的尺寸和數(shù)據(jù)類型。
- kernel:用于腐蝕操作的結(jié)構(gòu)元素,可以自己定義,也可以用getStructuringElement()函數(shù)生成。
- anchor:中心點在結(jié)構(gòu)元素中的位置,默認參數(shù)為結(jié)構(gòu)元素的幾何中心點
- iterations:腐蝕的次數(shù),默認值為1。
- borderType:像素外推法選擇標志,取值范圍在表3-5中給出。默認參數(shù)為BORDER_DEFAULT,表示不包含邊界值倒序填充。
- borderValue:使用邊界不變外推法時的邊界值。
該函數(shù)根據(jù)結(jié)構(gòu)元素對輸入圖像進行腐蝕,在腐蝕多通道圖像時每個通道獨立進行腐蝕運算。
函數(shù)的第一個參數(shù)為待腐蝕的圖像,圖像通道數(shù)可以是任意的,但是圖像的數(shù)據(jù)類型必須是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。
函數(shù)第二個參數(shù)為腐蝕后的輸出圖像,與輸入圖像具有相同的尺寸和數(shù)據(jù)類型。
函數(shù)第三個和第四個參數(shù)都是與結(jié)構(gòu)元素相關(guān)的參數(shù),第三個參數(shù)為結(jié)構(gòu)元素,第四個參數(shù)為結(jié)構(gòu)元素的中心位置,第四個參數(shù)的默認值為Point(-1,-1),表示結(jié)構(gòu)元素的幾何中心處為結(jié)構(gòu)元素的中心點。
函數(shù)第五個參數(shù)是使用結(jié)構(gòu)元素腐蝕的次數(shù),腐蝕次數(shù)越多效果越明顯,參數(shù)默認值為1,表示只腐蝕1次。
函數(shù)第六個參數(shù)是圖像像素外推法的選擇標志,
第七個參數(shù)為使用邊界不變外推法時的邊界值,這兩個參數(shù)對圖像中主要部分的腐蝕操作沒有影響,因此在多數(shù)情況下使用默認值即可。
需要注意的是該函數(shù)的腐蝕過程只針對圖像中的非0像素,因此如果圖像是以0像素為背景,那么腐蝕操作后會看到圖像中的內(nèi)容變得更瘦更?。蝗绻麍D像是以255像素為背景,那么腐蝕操作后會看到圖像中的內(nèi)容變得更粗更大。
簡單示例
// // Created by smallflyfly on 2021/6/18. // #include "opencv2/opencv.hpp" #include <iostream> using namespace std; using namespace cv; void drawResult(Mat im, int num, Mat stats, Mat centroids, const string& name) { for (int i = 1; i < num; ++i) { int x = centroids.at<double>(i, 0); int y = centroids.at<double>(i, 1); cout << x << " " << y << endl; circle(im, Point(x, y), 2, Scalar(0, 0, 255), -1); int xmin = stats.at<int>(i, CC_STAT_LEFT); int ymin = stats.at<int>(i, CC_STAT_TOP); int w = stats.at<int>(i, CC_STAT_WIDTH); int h = stats.at<int>(i, CC_STAT_HEIGHT); Rect rect(xmin, ymin, w, h); rectangle(im, rect, Scalar(255, 255, 255), 2); putText(im, to_string(i), Point(x+5, y), FONT_HERSHEY_SCRIPT_SIMPLEX, 0.3, Scalar(0, 0, 255), 1); } imshow(name, im); } int main() { Mat src = ( Mat_<uchar>(6, 6) << 0, 0, 0, 0, 255, 0, 0, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 0 ); resize(src, src, Size(0, 0), 50, 50, INTER_NEAREST); Mat m1, m2; m1 = getStructuringElement(0, Size(3, 3)); m2 = getStructuringElement(1, Size(3, 3)); Mat erodeM1, erodeM2; erode(src, erodeM1, m1, Point(-1, -1), 10); erode(src, erodeM2, m2, Point(-1, -1), 10); imshow("src", src); imshow("erodeM1", erodeM1); imshow("erodeM2", erodeM2); Mat xbim = imread("xiaobai.jpg"); Mat xbM1, xbM2; erode(xbim, xbM1, m1, Point(-1, -1), 2); erode(xbim, xbM2, m2, Point(-1, -1), 2); imshow("xb", xbim); imshow("xbM1", xbM1); imshow("xbM2", xbM2); Mat im = imread("rice.jfif"); Mat im1 = im.clone(); Mat im2 = im.clone(); Mat im3 = im.clone(); Mat gray; cvtColor(im, gray, CV_BGR2GRAY); Mat riceBin; threshold(gray, riceBin, 125, 255, THRESH_BINARY); Mat out, stats, centroids; int count1 = connectedComponentsWithStats(riceBin, out, stats, centroids, 8, CV_16U); drawResult(im1, count1, stats, centroids, "no erode"); Mat erodeIm1, erodeIm2; erode(riceBin, erodeIm1, m1, Point(-1, -1), 5); erode(riceBin, erodeIm2, m2, Point(-1, -1), 5); int count2 = connectedComponentsWithStats(erodeIm1, out, stats, centroids, 8, CV_16U); drawResult(erodeIm1, count2, stats, centroids, "erode1"); int count3 = connectedComponentsWithStats(erodeIm2, out, stats, centroids, 8, CV_16U); drawResult(erodeIm2, count3, stats, centroids, "erode2"); waitKey(0); destroyAllWindows(); }
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。