圖像處理進(jìn)階(一)——圖像的腐蝕膨脹
作者:Cabin_V
作為學(xué)習(xí)圖像處理的學(xué)生,需要不斷學(xué)習(xí)相關(guān)知識茸习,我在課余時間將一些分析總結(jié)和學(xué)習(xí)的筆記寫成博客來記錄自己的學(xué)習(xí)過程,也希望能與大家一起交流。
關(guān)于圖像處理入門和進(jìn)階分類問題倾鲫,我根據(jù)《數(shù)字圖像處理》這本書(本科期間上課使用)尤蒿,將出現(xiàn)的內(nèi)容劃分為入門郑气,其他常用的知識劃分為進(jìn)階。
轉(zhuǎn)載務(wù)必說明出處腰池!
圖像腐蝕與膨脹
OpenCV為進(jìn)行圖像的形態(tài)學(xué)變換提供了快捷尾组、方便的函數(shù)。最基本的形態(tài)學(xué)操作有兩種示弓,分別是:腐蝕(erode)與膨脹(dilate)讳侨。
區(qū)別
腐蝕和膨脹是對白色部分而言的。膨脹是對圖像中高亮的部分進(jìn)行膨脹避乏,處理后的圖片高亮區(qū)域擴(kuò)大爷耀;而腐蝕是對高亮部分進(jìn)行腐蝕,處理后的圖片高亮區(qū)域減少拍皮。
膨脹就是求局部最大值的操作歹叮。膨脹與膨脹操作就是將圖像與核進(jìn)行卷積。
作用
膨脹與腐蝕配合使用能實現(xiàn)各種各樣的功能铆帽,主要如下:
消除噪聲
分割出獨立的圖像元素贵试,在圖像中連接相鄰的元素
尋找圖像中明顯的極大值區(qū)域或極小值區(qū)域
求出圖像梯度
API說明
如果想進(jìn)一步了解各個參數(shù)對圖像最終結(jié)果的影響,可以跳到文章最下方代碼
我們先來看下簡單的圖像腐蝕膨脹的代碼
#include <opencv2/opencv.cpp>
using namespace cv;
int main()
{
Mat srcImage = imread("1.jpg");
imshow("原圖",srcImage);
//返回指定形狀和尺寸的結(jié)構(gòu)元素
Mat element = getStructuringElement(MORPH_CROSS,Size(3,3));
Mat eroImage, dilImage;
//圖像腐蝕
erode(srcImage, eroImage, element);
imshow("腐蝕", eroImage);
//圖像膨脹
dilate(srcImage, dilImage, element);
imshow("膨脹", dilImage);
waitKey(0);
return 0;
}
首先看一下程序運行結(jié)果
可以看到經(jīng)過原圖經(jīng)過腐蝕后蘑险,中間的白框不見了纵搁,而經(jīng)過膨脹處理,原圖中白框明顯變厚愧驱。
大家可以將代碼拷貝慰技,在自己的電腦運行一下,通過調(diào)整核大小形狀以及形態(tài)學(xué)操作组砚,觀察效果
注意吻商!圖片要放在.cpp文件相同路徑下!
以上程序分別用到了getStructuringElement()和erode()和dilate()函數(shù)糟红。
getStructuringElement()介紹
cv::Mat cv::getStructuringElement(int shape,Size ksize,Point anchor = cv::Point(-1,-1));
用法:可用于構(gòu)造一個特定大小和形狀的結(jié)構(gòu)元素艾帐,用于圖像形態(tài)學(xué)處理。
參數(shù)說明:
-
shape
:結(jié)構(gòu)元素的形狀(MorphShapes的其中一種)- MORPH_RECT——矩形
- MORPH_CROSS——交叉形
- MORPH_ELLIPSE——橢圓形
ksize
:結(jié)構(gòu)元素的大小anchor
:錨點盆偿,表示結(jié)構(gòu)元素中的一個點柒爸,默認(rèn)值Point(-1,-1)表示位于結(jié)構(gòu)元素中心,只有交錯形狀的(MORPH_CROSS)元素依賴錨點位置事扭,對于其它形狀的元素捎稚,錨點規(guī)定了形態(tài)學(xué)處理結(jié)果的偏移量。
erode()、dilate()介紹
void cv::erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor, int iterations,
int borderType, const Scalar& borderValue );
用法:實現(xiàn)圖像腐蝕功能的函數(shù)阳藻。
void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor, int iterations,
int borderType, const Scalar& borderValue );
用法:實現(xiàn)圖像膨脹功能的函數(shù)晰奖。
兩個函數(shù)的參數(shù)個數(shù)和名稱是一模一樣的,不同的只是函數(shù)功能腥泥,所以參數(shù)方面一起介紹匾南。
參數(shù)說明:一般只需使用前三個參數(shù),后四個參數(shù)都有默認(rèn)值蛔外。
src
:InputArray
類型蛆楞,輸入圖像,Mat類型的待處理圖像夹厌。圖像通道的數(shù)量可以是任意的豹爹,但圖像深度應(yīng)為CV_8U、CV_16U矛纹、CV_16S臂聋、CV_32F或CV_64F其中之一。dst
:OutputArray
類型或南,目標(biāo)圖像孩等,和輸入圖像有一樣的尺寸和類型。kerne
:InputArray
類型采够,形態(tài)學(xué)運算的內(nèi)核肄方。當(dāng)為NULL時,表示的是使用參考點位于中心3x3的核蹬癌。一般配合getStructuringElement()函數(shù)使用权她。anchor
:Point
類型,錨的位置逝薪。有默認(rèn)值(-1,-1)隅要,表示錨位于單位的中心。一般設(shè)置為默認(rèn)值董济。iteration
:int
類型步清,迭代使用erode()函數(shù)的次數(shù),默認(rèn)值為1感局。borderType
:int
類型,用于推斷圖像外部像素的某種邊界模式暂衡。默認(rèn)值為BORDER_DEFAULT询微。borderValue
:const Scalar&
類型,當(dāng)邊界為常數(shù)時的邊界值狂巢。默認(rèn)值為morphologyDefaultBorderValue()撑毛,一般設(shè)置為默認(rèn)值。
綜合代碼
這個程序在前面代碼基礎(chǔ)上加入了滑動條的功能
可以選擇“腐蝕/膨脹”、內(nèi)核形狀藻雌、內(nèi)核尺寸雌续。
運行界面如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
//全局變量聲明
Mat g_srcImage, g_dstImage;
//Trackbar接收的參數(shù)
int g_nTrackbarNumer = 0; //0-腐蝕,1-膨脹
int g_nStructElementShape = MORPH_RECT; //結(jié)構(gòu)元素的形狀 0-rect 1-cross 2-ellipse
int g_nStructElementSize = 0; //結(jié)構(gòu)元素的尺寸
//函數(shù)聲明
void Process();
void on_ElementShapeChange(int, void *);
void on_TrackbarNumChange(int, void *);
void on_ElementSizeChange(int, void *);
int main()
{
g_srcImage = imread("1.jpg");
if (!g_srcImage.data)
{
printf("error!\n");
return false;
}
namedWindow("Erode/Dilate");
imshow("Erode/Dilate",g_srcImage);
//創(chuàng)建滑動條
createTrackbar("Ero/Dil", "Erode/Dilate", &g_nTrackbarNumer, 1, on_TrackbarNumChange);
createTrackbar("shape", "Erode/Dilate", &g_nStructElementShape, 2, on_ElementShapeChange);
createTrackbar("size", "Erode/Dilate", &g_nStructElementSize, 11, on_ElementSizeChange);
//按q退出程序
if (waitKey(0) != 'q')
{
}
return 0;
}
void Process()
{
//根據(jù)g_nStructElementShape和g_nStructElementSize自定義核
Mat element = getStructuringElement(g_nStructElementShape, Size(2*g_nStructElementSize+1, 2*g_nStructElementSize+1), Point(g_nStructElementSize, g_nStructElementSize));
//選擇腐蝕或膨脹操作
if (g_nTrackbarNumer == 0)
{
erode(g_srcImage, g_dstImage, element);
}
else
{
dilate(g_srcImage, g_dstImage, element);
}
imshow("Erode/Dilate", g_dstImage);
}
//Trackbar-shape響應(yīng)函數(shù)
void on_ElementShapeChange(int, void *)
{
//g_nStructElementShape數(shù)值已改變
Process();
}
//Trackbar-erode/dilate響應(yīng)函數(shù)
void on_TrackbarNumChange(int, void *)
{
//g_nTrackbarNumer數(shù)值已改變
Process();
}
//Trackbar-size響應(yīng)函數(shù)
void on_ElementSizeChange(int, void *)
{
//g_nStructElementSize數(shù)值已改變
Process();
}
本篇文章對你們有用的話胯杭,點個贊再走~