图像的腐蚀与膨胀
一、原理:
⑴ 图像形态学处理的概念膨胀和腐蚀这两种操作是形态学处理的基础,许多形态学算法都是以这两种运算为基础的。
定义结构元素B为:
1 | 1 |
1 | 0 |
(i-1,j+1) | (i,j+1) |
(i-1,j) | 所求此点(i,j) |
腐蚀处理的结果是使原来的二值图像减小一圈。
二、我再加一个轮廓提取,非常简单的方法:用的是9X9的模板;
(i-1,j+1) | (i,j+1) | (i+1,j+1) |
(i-1,j) | 所求此点(i,j) | (i+1,j) |
(i-1,j-1) | (i,j-1) | (i+1,j_1) |
#include
#include
using namespace cv;
using namespace std;
Mat srcImage, grayImage, binarygray, erosion, dilation, outline;
static void g_erosion(int, void*);
static void g_dilation(int, void*);
static void g_outline(int, void*);
static void ShowHelpText();
int main()
{
system("color 3f");
ShowHelpText();
srcImage = imread("D://vvoo//cell.jpg");
cvtColor(srcImage, grayImage, CV_RGB2GRAY);
int threshold;
cout << "input threshold: " << endl;
cin >> threshold;
//二值化
binarygray = Mat::zeros(grayImage.rows, grayImage.cols, grayImage.type());
{
for (int i = 0; i threshold)
{
binarygray.data[i*binarygray.step + j] = 255;
}
else
{
binarygray.data[i*binarygray.step + j] = 0;
}
}
}
}
//腐蚀
g_erosion(0, 0);
//膨胀
g_dilation(0, 0);
//轮廓提取
g_outline(0, 0);
imshow("原图", srcImage);
imshow("binarygray", binarygray);
waitKey(0);
return 0;
}
static void g_erosion(int, void*)
{
erosion = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type());
{
for (int i = 1; i < binarygray.rows; i++)
{
for (int j = 1; j < binarygray.cols; j++)
{
if (binarygray.data[(i - 1)*binarygray.step + j] + binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[i*binarygray.step + j + 1] == 0)
{
erosion.data[i*erosion.step + j] = 0;
}
else
{
erosion.data[i*erosion.step + j] = 255;
}
}
}
}
imshow("erosion_1", erosion);
}
static void g_dilation(int, void*)
{
dilation = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type());
for (int i = 1; i < binarygray.rows; i++)
{
for (int j = 1; j < binarygray.cols; j++)
{
if (binarygray.data[(i - 1)*binarygray.step + j] == 0 || binarygray.data[(i - 1)*binarygray.step + j - 1] == 0 || binarygray.data[i*binarygray.step + j + 1] == 0)
{
dilation.data[i*dilation.step + j] = 0;
}
else
{
dilation.data[i*dilation.step + j] = 255;
}
}
}
imshow("dilation_1", dilation);
}
static void g_outline(int, void*)
{
outline = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type());
for (int i = 1; i < binarygray.rows; i++)
{
for (int j = 1; j < binarygray.cols; j++)
{
if (binarygray.data[i*binarygray.step + j + 1] + binarygray.data[(i - 1)*binarygray.step + j]
+ binarygray.data[i*binarygray.step + j - 1] + binarygray.data[(i - 1)*binarygray.step + j - 1]
+ binarygray.data[(i + 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j]
+ binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[(i + 1)*binarygray.step + j + 1] == 2040)
{
outline.data[i*erosion.step + j] = 255;
}
if (binarygray.data[i*binarygray.step + j + 1] + binarygray.data[(i - 1)*binarygray.step + j]
+ binarygray.data[i*binarygray.step + j - 1] + binarygray.data[(i - 1)*binarygray.step + j - 1]
+ binarygray.data[(i + 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j]
+ binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[(i + 1)*binarygray.step + j + 1] == 0)
{
outline.data[i*erosion.step + j] = 255;
}
}
}
imshow("outline", outline);
}
static void ShowHelpText()
{
cout << "\n\n本程序涉及到:"<<"腐蚀(erosion)、膨胀(dilation)、轮廓提取(outline)。\n\n" << endl;
}
四、运行结果
五、调用Opencv的erode()函数和dilate()函数实现腐蚀和膨胀功能
1)erode函数,使用像素邻域内的局部极小运算符来腐蚀一张图片,从src输入,由dst输出。支持就地(in-place)操作。
看一下函数原型:
void erode(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor=Point(-1,-1),
int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue()
);
同样的,使用erode函数,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。
2)dilate函数原型
函数原型:
C++: void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() );
参数详解:
我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵。其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:
矩形: MORPH_RECT
而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。
3)代码实现
#include
#include
using namespace cv;
using namespace std;
#define WINDOWN_NAME_1 "原图"
#define WINDOWN_NAME_2 "腐蚀图"
#define WINDOWN_NAME_3 "膨胀图"
int main()
{
Mat srcImage = imread("D://vvoo//cell.jpg");
//获取自定义核
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
Mat out_erosion, out_dilate;
//进行膨胀操作
erode(srcImage, out_erosion, element);
dilate(srcImage, out_dilate, element);
imshow(WINDOWN_NAME_1, srcImage);
imshow(WINDOWN_NAME_2, out_erosion);
imshow(WINDOWN_NAME_3, out_dilate);
waitKey(0);
return 0;
}
4)运行结果
和自己写的比较下比较一下,差别比较大,主要是因为结构元素大小的关系,我的是2*2,Opencv是15*15的。
我也是初学者,欢迎纠正!
六、参考资料
1.system("color 3f");//输出窗口和字体颜色可变化,3代表窗口颜色(绿色),f代表窗口里字体颜色(白色)
全部颜色为:
2.图像腐蚀、膨胀、细化基本原理
3. 形态学图像处理(一): 膨胀与腐蚀