21、opencv影象形態學變換

在計算機視覺的早期階段,大量的形態學操作被開發出來。大多數是為特定目的或其他目的而開發的,其中一些在過去幾年中發現更廣泛的用途。實質上,所有的形態學操作都基於兩個基本操作。下面將從這些開始,然後繼續進行更復雜的操作,每個操作通常都是用簡單的先例來定義的。

1、 膨脹和腐蝕

基本的形態學操作稱為膨脹和侵蝕,它們出現在各種各樣的影象處理中,例如去燥,分割單個元素以及連通影象中的不同元素。基於這兩個基本操作的更復雜的形態學操作也可以用於查詢影象中峰值或空洞,並且定義特定形式的影象梯度。

膨脹是一些影象與核心的卷積,其中任何給定的畫素被核心覆蓋的所有畫素值的區域性最大值替換。這是一個非線性操作的例子,大多數情況下,核心是一個方形核心,或者有時是一個圓形,其中心位置為錨點。膨脹的效果是在影象中填充。

腐蝕是相反的操作。腐蝕運算元的作用等同於計算核區域內的區域性最小值。影象形態學通常在閾值操作產生的二值影象上完成。然而,因為膨脹只是一個最大的運算元,腐蝕只是一個最小的運算元,所以形態學也可以用在灰度影象上。

一般而言,膨脹擴大了一個明亮的區域,腐蝕減少了這樣一個明亮的區域。而且,膨脹會傾向於填充凹陷而腐蝕將趨於移除突起。當然,確切的結果將取決於核心,但只要核心既是凸的又是滿的,其操作結果就與上面所述類似。

在OpenCV中,使用dilate ()和 erode ()函式來實現這些操作:

void cv::erode(

cv::InputArray src,

cv::OutputArray dst,

cv::InputArray element,

cv::Point anchor = cv::Point(-1,-1),

int iterations = 1,

int borderType = cv::BORDER_CONSTANT

const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue()

);

void cv::dilate(

cv::InputArray src,

cv::OutputArray dst,

cv::InputArray element,

cv::Point anchor = cv::Point(-1,-1),

int iterations = 1,

int borderType = cv::BORDER_CONSTANT

const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue()

);

erode()和dilate()都支援源影象和目標影象是相同的影象。第三個引數是核心,可以向其傳遞未初始化的陣列Mat(),它會預設使用一個3×3核心,並在其中心定位錨。第四個引數是迭代次數。如果未設定,預設值1。borderType引數是邊界型別,borderValue是borderType設定為BORDER_CONSTANT時將用於邊緣外畫素的值。

腐蝕操作通常用於消除影象中的“散斑”噪聲。“散斑”被腐蝕,而包含視覺重要內容的較大區域則不受影響。通常使用膨脹操作來試圖找出連通的分量。膨脹效用的產生是因為在很多情況下,由於噪音,陰影或其他類似的影響,大的區域可能會被分解成多個分量。小的膨脹會將這些分量融合成一個整體。

當OpenCV處理erode()函式時,在錨點處對齊時,某個點p的值被設定為核心覆蓋的所有點的最小值; 對於dilate()運算,除了考慮max而不是min之外,其他都是相同的。可以用公式表示如下。

21、opencv影象形態學變換

2、 形態學函式

當使用二值影象時,基本的腐蝕和膨脹操作通常就足夠了。但是,當使用灰度圖或彩色影象時,許多其他操作通常都會有所幫助。幾個更有用的操作可以透過morphologyEx()函式來處理。

void cv::morphologyEx(

cv::InputArray src,

cv::OutputArray dst,

int op,

cv::InputArray element,

cv::Point anchor = cv::Point(-1,-1),

int iterations = 1,

int borderType = cv::BORDER_DEFAULT

const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue()

);

除了用dilate()和erode()函式看到的引數之外, morphologyEx()還有一個新的非常重要的引數。這個名為op的新引數是要完成的具體操作。表1列出了該引數的可能值。

21、opencv影象形態學變換

MOP_OPEN

開運算

MOP_CLOSE

閉運算

MOP_GRADIENT

形態學梯度

MOP_TOPHAT

頂帽運算

MOP_BLACKHAT

黑帽運算

3 、開運算和閉運算

開運算和閉運算,實際上是腐蝕和膨脹操作的簡單組合。在開運算的情況下,先腐蝕然後膨脹。開運算通常用於對布林影象中的區域進行計數。例如,如果在顯微鏡載玻片上設定閾值的細胞影象,可能會在計數區域之前使用開運算來分離彼此相鄰的細胞。

閉運算是先膨脹然後腐蝕。閉運算用於大多數更復雜的連線區域演算法,以減少不需要部分的或噪聲。通常首先執行腐蝕或閉運算操作以消除純粹由噪聲引起的元素,然後使用開運算操作來連線附近的大區域。儘管使用開運算或閉運算的最終結果與使用腐蝕或膨脹類似,但這些新操作傾向於更精確地保留連線區域的面積。

當用於非二值影象時,閉運算的最顯著效果是消除值低於其鄰域的孤立值,而開運算的效果是消除高於其鄰域的孤立值。

4、 形態學梯度

對於形態梯度。 可以從一個公式開始,然後找出它的含義可能更容易:

21、opencv影象形態學變換

正如上面公式中看到的那樣,從膨脹的影象中減去腐蝕影象的效果是留下原始影象中物件邊緣的表示。

使用灰度影象,該操作告訴我們影象亮度變化的速度。這就是為什麼叫“形態學梯度”。當想要分割明亮區域的周長時,通常會使用形態學梯度。由於從區域的膨脹中減去了腐蝕,留下了完整的周邊邊緣,因此可以找到區域的完整週長。

5、 頂帽和黑帽

頂帽(Top Hat)和黑帽(Black Hat)運算子用於分割比其鄰域值更亮或更暗的值。當分割顯示亮度變化的物件的某些部分僅與其所連線的物件相關時,可以使用這些操作。這兩個操作都是按照更原始的運算子來定義的,公式如下所示:

21、opencv影象形態學變換

頂帽操作從原圖中減去原圖的膨脹圖。因此,從原圖中減去開運算的結果應該顯示比原圖的周圍區域更小的區域;相反,黑帽運算子揭示了區域比周圍的更暗。

6、 自定義核心

到目前為止,所考慮的核心始終是方形的,並且是3×3。如果使用者需要比這更通用的核心,OpenCV允許使用者建立自己的核心。在形態學的情況下,核心通常被稱為結構化元素。

使用者可以建立自己喜歡的形狀,並將它用作dilate(), erode()或morphologyEx()等函式中的結構元素,這通常很必要。這就是getStructuringElement()的用途。

cv::Mat cv::getStructuringElement(

int shape,

cv::Size ksize,

cv::Point anchor = cv::Point(-1,-1)

);

第一個引數shape用於控制哪個基本形狀將用於建立元素,而ksize和anchor分別指定元素的大小和錨點的位置。如果anchor保留其預設值,則getStructuringElement()將表示該錨點應該自動放置在核心中心。getStructuringElement()的形狀主要有MORPH_RECT、MORPH_ELLIPSE、MORPH_CROSS三種。如果需要更復雜的結構元素,可以將任何Mat作為結構元素傳遞給形態學運算。例1演示了部分形態學操作,其它的操作都是類似。

例1 形態學操作示意

#include #include using namespace std;using namespace cv;int main(int argc, char** argv){    Mat srcImg = imread(“E:/形態學。png”, 0);    namedWindow(“原始影象”, 0);    imshow(“原始影象”, srcImg);    //二值化    Mat thresholdImg;    threshold(srcImg, thresholdImg, 100, 255, 0);    //膨脹    Mat dilateImg;    Mat kernel = Mat::ones(3, 3, CV_8UC1);    dilate(thresholdImg, dilateImg, kernel);    namedWindow(“膨脹”, 0);    imshow(“膨脹”, dilateImg);    //腐蝕    Mat erodeImg;    erode(thresholdImg, erodeImg, kernel);    namedWindow(“腐蝕”, 0);    imshow(“腐蝕”, erodeImg);    //開運算    morphologyEx(thresholdImg, openImg, MorphTypes::MORPH_OPEN, horizontalStructure);    namedWindow(“開運算”, 0);    imshow(“開運算”, openImg);     //閉運算    Mat closeImg;    morphologyEx(thresholdImg, closeImg, MorphTypes::MORPH_CLOSE, horizontalStructure);    namedWindow(“閉運算”, 0);    imshow(“閉運算”, closeImg);     Mat verticalStructure = getStructuringElement(MORPH_RECT, Size(1, 5));    morphologyEx(thresholdImg, openImg, MorphTypes::MORPH_OPEN, verticalStructure);    namedWindow(“開運算2”, 0);    imshow(“開運算2”, openImg);     waitKey(0);    return 0;}

21、opencv影象形態學變換