原理:
腐蚀膨胀算法的基本原理很简单,与图像卷积的方法类似,给定一个窗口或者是一个特定形状的卷积核,卷积核中的值全部为1。
处理前,先将图像二值化。
如果是腐蚀操作,那么在进行卷积的操作过程当中,让卷积核与卷积核所覆盖的的图像区域的取“与”运算操作(如果图像像素值不为空就当成1处理)。如果卷积核中的所有值都是1,那么就将卷积核的锚点设置成1。
以上为腐蚀运算。
同样,在膨胀运算的过程中使用“与”运算,如果卷积核当中有一个值是1,那么就将锚点设置成1。
“卷积核”的形状及大小,在opencv程序当中可以使用getStructElement函数来获取,有三种,分别是矩形、椭圆以及十字形状。
可以在OpenCV源码当中看到其中的实现过程。
山寨代码:
下面程序只使用了矩形的卷积操作,卷积核大小3×3
void Binary(const Mat &src,Mat &dst,int threshold)
{
CV_Assert(src.channels() == 1);
dst.create(Size(src.cols, src.rows), src.type());
uchar *ps = src.data;
uchar *pd = dst.data;
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
if (ps[(row*src.cols) + col]>threshold)
pd[(row*src.cols) + col] = 255;
else
pd[(row*src.cols) + col] = 0;
}
}
}
void MyErosion(const Mat &src, Mat &dst)//仅使用矩形element
{
int kernel[3][3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
kernel[i][j] = 1;
}
CV_Assert(src.channels() == 1);
dst.create(Size(src.cols, src.rows), src.type());
uchar *ps = src.data;
uchar *pd = dst.data;
for (int row = 1; row < src.rows-1; row++)
{
for (int col = 1; col < src.cols-1; col++)
{
int cnt = 0;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (kernel[(1 + i) * 3 + j + 1] &&
ps[(row + i)*src.cols + col + j] > 0
)
{
cnt++;
}
}
}
if (cnt == 9)
pd[(row*src.cols) + col] = 255;
else
pd[(row*src.cols) + col] = 0;
}
}
for (int col = 0; col < src.cols; col++)
{
pd[col] = ps[col];
pd[(src.rows - 1)*src.cols + col] = ps[(src.rows - 1)*src.cols + col];
}
for (int row = 0; row < src.rows; row++)//列
{
pd[row*src.cols] = ps[row*src.cols];
pd[row*src.cols + src.cols - 1] = ps[row*src.cols + src.cols - 1];
}
}
void MyDilate(const Mat &src, Mat &dst)
{
int kernel[3][3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
kernel[i][j] = 1;
}
CV_Assert(src.channels() == 1);
dst.create(Size(src.cols, src.rows), src.type());
uchar *ps = src.data;
uchar *pd = dst.data;
for (int row = 1; row < src.rows - 1; row++)
{
for (int col = 1; col < src.cols - 1; col++)
{
int cnt = 0;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (kernel[(1 + i) * 3 + j + 1] &&
ps[(row + i)*src.cols + col + j] > 0
)
{
cnt++;
}
}
}
if (cnt > 0)
pd[(row*src.cols) + col] = 255;
else
pd[(row*src.cols) + col] = 0;
}
}
for (int col = 0; col < src.cols; col++)
{
pd[col] = ps[col];
pd[(src.rows - 1)*src.cols + col] = ps[(src.rows - 1)*src.cols + col];
}
for (int row = 0; row < src.rows; row++)//列
{
pd[row*src.cols] = ps[row*src.cols];
pd[row*src.cols + src.cols - 1] = ps[row*src.cols + src.cols - 1];
}
}
int main()
{
ios::sync_with_stdio(false);
Mat src = imread("src.jpg",0),gary;
Mat dst,tmp;
Binary(src, dst, 100);
MyDilate(dst, tmp);
imshow("src", src);
imshow("tmp", tmp);
imshow("dst", dst);
waitKey();
system("pause");
return 0;
}
先读入一个灰度图,使用Binary函数二值化,然后可以调用腐蚀或者膨胀算法来实现形态学运算。
结果如下
原图是一张漂亮的东德牧羊犬
腐蚀
膨胀