建議大家看看網絡視頻教程:http://www.opencvchina.com/thread-886-1-1.html
腐蝕與膨脹都是針對灰度圖的形態學操作,比如下面的一副16*16的灰度圖。
它每個像素對應的值為(每個像素值范圍都在0-255之間)為:
我們定義一個5*5的結構元素,該結構元素用5*5的矩陣表示,其中為1的單元,表示該單元在結構元素中有效,另外還定義一個錨點,坐標為(2,2),在單元格中用藍色表示。
腐蝕/膨脹的操作就是用結構元素的錨點位置對齊圖像的像素,然后從左上角的第一個像素滑動到右下角的最后一個像素。
在滑動到每個像素時,結構元素中為1的各個坐標格子會與相應的像素對齊。比如滑動到第一個像素時,如下圖所示:
此時,原圖像中對齊的格子,如下圖所示。
腐蝕操作就是取其中的最小值,代替原素像素值,即image(0,0)的像素值為min(0,1,2,16,32)=0,而膨脹操作則相反,是取最大值代替原像素,即image(0,0)=max(0,1,2,16,32)=32。
下面我們再看一個例子,當結構元素滑動到image(4,4 ) 位置時候,圖像的腐蝕膨脹操作:
此時,結構元素對齊的像素如下圖所示,對於腐蝕操作,此時image(4,4)應該等於min(36,52,66,67,68,69,70,84,100)=36,而膨脹操作,則是image(4,4)等於max(36,52,66,67,68,69,70,84,100)=100。
需要注意下面的一種情況:
結構元素如下圖所示,仍是5*5的十字形狀,但錨點位置在(3,3),此時當結構元素在圖像中滑動時候,會有一些特殊情況需要注意。
比如滑動到圖像的(0,0)位置時,結構元素中為1的單元格和圖像沒有交叉的格子,此時按我的理解,應該保持像素的值不變,但opencv中卻不是這樣,當腐蝕時,此時(0,0)位置像素值為255,當膨脹時,(0,0)位置像素值為0。
下面是我寫的簡單的腐蝕膨脹函數代碼:
cv::Mat gMophEx::Erode(cv::Mat& img, cv::Mat kernel, cv::Point anchor)
{
cv::Mat tmpImg;
img.copyTo(tmpImg);
int i, j, m, n;
uchar* p;
for(i=0; i<img.rows; i++)
{
p = tmpImg.ptr<uchar>(i);
for(j=0; j<img.cols; j++)
{
int min = 100000;
for(m = 0; m < kernel.rows; m++)
{
for(n=0; n <kernel.cols; n++)
{
if(kernel.data[m*kernel.cols+n]==1)
{
//printf("i=%d, j=%d, m=%d,n=%d,tt1=%d, tt2=%d, tt3=%d\n",i,j,m,n,j+n-anchor.y,i + m - anchor.x,(i + m - anchor.x)*img.cols + j+n-anchor.y);
if(j+n-anchor.x < 0 || j+n-anchor.y >=img.cols || i + m - anchor.x < 0 || i + m - anchor.x >= img.rows)
continue;
//printf("%d \n",img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]);
if(img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]<min)
min = img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y];
}
}
}
if (min < 256)
{
p[j] = min;
}
else if(min==100000)
{
p[j] = 255; //opencv結果是這樣,當腐蝕時候,當前像素找不到相應的點,賦予最大值
}
}
}
return tmpImg;
}
cv::Mat gMophEx::Dilate(cv::Mat& img, cv::Mat kernel, cv::Point anchor)
{
cv::Mat tmpImg;
img.copyTo(tmpImg);
int i, j, m, n;
uchar* p;
for(i=0; i<img.rows; i++)
{
p = tmpImg.ptr<uchar>(i);
for(j=0; j<img.cols; j++)
{
int max=-1;
for(m = 0; m < kernel.rows; m++)
{
for(n=0; n <kernel.cols; n++)
{
if(kernel.data[m*kernel.cols+n]==1)
{
//printf("i=%d, j=%d, m=%d,n=%d, tt=%d\n",i,j,m,n,(i + m - anchor.x)*img.cols + j+n-anchor.y);
if(j+n-anchor.y < 0 || j+n-anchor.y >=img.cols || i + m - anchor.x < 0 || i + m - anchor.x >= img.rows)
continue;
//printf("%d \n",img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]);
if(img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]>max)
max = img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y];
}
}
}
if (max >= 0)
{
p[j] = max;
}
else if(max == -1)
{
p[j] = 0;
}
//PrintMat(tmpImg);
}
}
return tmpImg;
}
膨脹操作后的像素值為:
程序代碼: 工程FirstOpenCV4