opencv(5)形態學操作

圖像形態學一般用於閾值化後的二值圖像,其實也可以用於灰度圖像的處理,這篇文章主要對灰度中的應用做分析。

1.膨脹與腐蝕

函數
void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );//腐蝕函數
void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );//膨脹函數

函數解釋可以參考:opencv論壇,關於裏面的結構IplConvKernel可以參考:http://blog.csdn.net/babbxazzg/article/details/5976177

腐蝕操作要計算核區域內像素的最小值。膨脹操作要計算核區域內的像素最大值。具體的函數表達:

1

如果在二值圖像中進行表達,那麼就是按核進行擴展,在二值圖像中,膨脹可以填充小的凹陷,鏈接一些相近的部件,腐蝕可以去除一些小的斑點。

2.IplConvKernel結構

結構
typedef struct _IplConvKernel
{
    int  nCols;
    int  nRows;
    int  anchorX;
    int  anchorY;
    int *values;
    int  nShiftR;
}

IplConvKernel;
在這裏,對其中的變量定義做一簡單的描述:
nCols,nRows:結構元素的行寬與列高;
anchorX,anchorY:結構元素原點(錨點)的位置座標,水平,垂直;
nShiftR:用於表示結構元素的形狀類型,有如下幾個值:
#define  CV_SHAPE_RECT      0
#define  CV_SHAPE_CROSS     1
#define  CV_SHAPE_ELLIPSE   2
#define  CV_SHAPE_CUSTOM    100
分別表示矩形,十字,橢圓和自定義。
values:當nShiftR爲自定義時,value是指向結構元素數據的指針,如果結構元素的大小定義爲8*6,那麼values爲48長的int數組,值爲0或1。

操作函數:

結構IplConvKernel* cvCreateStructuringElementEx( int cols, int rows, int anchor_x, int anchor_y,
int shape, int* values=NULL );//創建
void cvReleaseStructuringElement( IplConvKernel** element );//釋放

以前做過一個點識別的程序,就是用這個實現的,代碼圖片如下:

形態學灰度操作實例
#include "stdafx.h"
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include "math.h"

int _tmain(int argc, _TCHAR* argv[])
{
	cvNamedWindow("src");
	cvNamedWindow("dst");
	cvNamedWindow("thresh");

	IplImage *img=cvLoadImage("2.bmp");
	IplImage *img2 = cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,1);
	IplImage *img3 = cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,1);
	cvCvtColor(img,img2,CV_BGR2GRAY);
	cvShowImage("src",img2);

	IplConvKernel* t = cvCreateStructuringElementEx(11, 11, 6,6,CV_SHAPE_ELLIPSE);

	cvDilate(img2,img3,t);

	cvReleaseStructuringElement( &t );

	cvSaveImage("dst.jpg",img3);

	cvShowImage("dst",img3);

	cvThreshold(img3,img2,60,255,CV_THRESH_BINARY);

	cvShowImage("thresh",img2);

	cvWaitKey();
	cvDestroyWindow("thresh");
	cvDestroyWindow("dst");
	cvDestroyWindow("src");
	return 0;
}

操作的圖片:
                原圖                                       形態學操作後                          閾值

上面雖然不是一個很好的例子,但是在一定程度上說明形態學灰度的效果。

3. cvMorphologyEx

opencv中實現開運算、閉運算、形態梯度、tophat,baackhat的函數是cvMorphologyEx();具體使用方法:

cvMorphologyEx
void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp,
IplConvKernel* element, int operation, int iterations=1 );
src
輸入圖像.
dst
輸出圖像.
temp
臨時圖像,某些情況下需要
element
結構元素
operation
形態操作的類型:
CV_MOP_OPEN - 開運算
CV_MOP_CLOSE - 閉運算
CV_MOP_GRADIENT - 形態梯度
CV_MOP_TOPHAT - "頂帽"
CV_MOP_BLACKHAT - "黑帽"
iterations
膨脹和腐蝕次數.
函數 cvMorphologyEx 在膨脹和腐蝕基本操作的基礎上,完成一些高級的形態變換:

開運算
dst=open(src,element)=dilate(erode(src,element),element)
閉運算
dst=close(src,element)=erode(dilate(src,element),element)
形態梯度
dst=morph_grad(src,element)=dilate(src,element)-erode(src,element)
"頂帽"
dst=tophat(src,element)=src-open(src,element)
"黑帽"
dst=blackhat(src,element)=close(src,element)-src
臨時圖像 temp 在形態梯度以及對“頂帽”和“黑帽”操作時的 in-place 模式下需要。

有人說,這個函數使用非對稱結構的時候會造成偏移,其實即使使用opencv其他函數實現也會造成偏移,原理使其然,並不阻礙我們使用。

需要說明的是,最後一個參數,例如閉運算,iterations=2的時候,並不是說分別執行2次閉運算,也就是dilate—>erode-->dilate—>erode,實際的情況是dilate—>dilate-->erode—>erode。

(1)開運算,必運算

開運算是先腐蝕,再膨脹,用來消除小物體、在纖細點處分離物體、平滑較大物體的邊界的同時並不明顯改變其面積。

閉運算是先膨脹,在腐蝕,用來填充物體內細小空洞、連接鄰近物體、平滑其邊界的同時並不明顯改變其面積。

就用《learning opencv》上的圖說明吧:

3 4

                                      開運算                                                                                                    閉運算

下圖爲例,演示通過開運算和閉運算消除噪聲,突出需要的物體,原圖以及經過二值化以後的圖像如下:

12 src

可以看到二值畫以後的圖像中,區域邊緣有很多毛刺,雖然濾波也可以消除,但是不是很乾淨,想我採用的形態學操作辦法,代碼:

形態學操作例子
	cvNamedWindow("src");
	cvNamedWindow("dst");


	IplImage *img=cvLoadImage("12.bmp");
	IplImage *img2 = cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,1);
	IplImage *img3 = cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,1);
	cvCvtColor(img,img2,CV_BGR2GRAY);
	cvThreshold(img2,img2,60,255,CV_THRESH_BINARY);
	cvShowImage("src",img2);
	cvSaveImage("src.jpg",img2);

	IplConvKernel* t = cvCreateStructuringElementEx(7, 7, 4,4,CV_SHAPE_ELLIPSE);
	IplConvKernel* t2 = cvCreateStructuringElementEx(5, 5, 3,3,CV_SHAPE_ELLIPSE);


	cvMorphologyEx(img2,img3,NULL,t2,CV_MOP_OPEN);
	cvMorphologyEx(img3,img3,NULL,t2,CV_MOP_OPEN);

	cvMorphologyEx(img3,img3,NULL,t,CV_MOP_CLOSE);
	cvMorphologyEx(img3,img3,NULL,t,CV_MOP_CLOSE);

	cvReleaseStructuringElement( &t );
	cvReleaseStructuringElement( &t2 );
	cvSaveImage("dst.jpg",img3);

	cvShowImage("dst",img3);

	cvWaitKey();

	cvDestroyWindow("dst");
	cvDestroyWindow("src");
	return 0;

即先進性2次開運算,擴大邊緣的噪聲,在使用閉運算,連接邊緣的毛刺,開運算和閉運算的結果如下:

open   dst

經過開運算,閉運算後,邊緣平滑很多,這並不是一個很好的例子,手邊剛好有這麼一張圖片,就一次來說明問題而已

 

 轉自:http://www.cnblogs.com/zsb517/archive/2012/06/08/2541193.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章