1)形态学的基本思想是利用一种特殊的结构元来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别。
2)图像的形态学处理是对二值图像进行处理,所以在形态学处理前需要将图像二值化
3)结构元可以是任意形状,结构元有一个锚点,如下结构元,中间红色则为锚点
可以知道,二值图像就是由黑色和白色组成,那么膨胀简单来说就是将图像的白色部分变大。
膨胀的原理就是结构元在图像上滑动,当锚点对应的像素为白色时,那么结构元对应为1的元素点也变为白色。
举个栗子:
那么膨胀就是如下过程(深色像素为白色):
代码:
这里的结构元为3*3,值全为1
//全局二值化后再进行形态学处理
double f[9];
f[0] = 1;
f[1] = 1;
f[2] = 1;
f[3] = 1;
f[4] = 1;
f[5] = 1;
f[6] = 1;
f[7] = 1;
f[8] = 1;
double* new_data = new double[biHead1.biHeight * biHead1.biWidth]();
//膨胀就是图像中的白的变大
for (int i = 0; i < biHead1.biHeight-2; i++)
for (int j = 0; j < biHead1.biWidth-2; j++)
{
if (double_data[(i + 1) * biHead1.biWidth + j + 1] + f[4] == 256)
{
new_data[i * biHead1.biWidth + j] = 255;
new_data[i* biHead1.biWidth + j + 1] = 255;
new_data[i * biHead1.biWidth + j + 2] = 255;
new_data[(i + 1) * biHead1.biWidth + j ] = 255;
new_data[(i + 1) * biHead1.biWidth + j + 1] = 255;//锚点
new_data[(i + 1) * biHead1.biWidth + j + 2] = 255;
new_data[(i + 2) * biHead1.biWidth + j ] = 255;
new_data[(i + 2) * biHead1.biWidth + j + 1] = 255;
new_data[(i + 2) * biHead1.biWidth + j + 2] = 255;
}
}
//显示
for (int i = 0; i < biHead1.biHeight; i++)
for (int j = 0; j < biHead1.biWidth; j++)
{
dc.SetPixel(j / time, (biHead1.biHeight - i) / time, RGB(new_data[j + i * biHead1.biWidth], new_data[j + i * biHead1.biWidth], new_data[j + i * biHead1.biWidth]));
}
结果:
与膨胀同理,腐蚀简单来说就是将图像的白色部分变小。
腐蚀的原理就是结构元在图像上滑动,当结构元上所有对应的像素都为白色时,那么只保留锚点的白色,其余像素变黑。
举个栗子:
那么腐蚀就是如下过程(深色像素为白色):
代码:
//全局二值化后再进行形态学处理
double f[9];
f[0] = 0;
f[1] = 1;
f[2] = 0;
f[3] = 1;
f[4] = 1;
f[5] = 1;
f[6] = 0;
f[7] = 1;
f[8] = 0;
double* new_data = new double[biHead1.biHeight * biHead1.biWidth]();
//腐蚀,腐蚀就是原图中的白的变小
for (int i = 0; i < biHead1.biHeight-2; i++)
for (int j = 0; j < biHead1.biWidth-2; j++)
{
if ((double_data[i * biHead1.biWidth + j + 1] + f[1] == 256) &&(double_data[(i + 1) * biHead1.biWidth + j] + f[3] == 256) && (double_data[(i + 1) * biHead1.biWidth + j + 1] + f[4] == 256) && (double_data[(i + 1) * biHead1.biWidth + j + 2] + f[5] == 256)&& (double_data[(i + 2) * biHead1.biWidth + j + 1] + f[7] == 256))
{
new_data[(i + 1) * biHead1.biWidth + j + 1] = 255;//锚点
}
}
//显示
for (int i = 0; i < biHead1.biHeight; i++)
for (int j = 0; j < biHead1.biWidth; j++)
{
dc.SetPixel(j / time, (biHead1.biHeight - i) / time, RGB(new_data[j + i * biHead1.biWidth], new_data[j + i * biHead1.biWidth], new_data[j + i * biHead1.biWidth]));
}
结果:
开运算实质上是先腐蚀再膨胀,它一般会平滑物体的轮廓,断开较窄的狭颈并消除细的突出物。
举个栗子:
那么开运算就是如下过程(深色像素为白色):
代码:
double f[9];
f[0] = 0;
f[1] = 1;
f[2] = 0;
f[3] = 1;
f[4] = 1;
f[5] = 1;
f[6] = 0;
f[7] = 1;
f[8] = 0;
//先腐蚀再膨胀(开操作,一般会平滑物体的轮廓,断开较窄的狭颈并消除细的突出物。
//腐蚀就是图像中的白的变小
double* new_data2 = new double[biHead1.biHeight * biHead1.biWidth]();
for (int i = 0; i < biHead1.biHeight - 2; i++)
for (int j = 0; j < biHead1.biWidth - 2; j++)
{
if ((double_data[i * biHead1.biWidth + j + 1] + f[1] == 256) && (double_data[(i + 1) * biHead1.biWidth + j] + f[3] == 256) && (double_data[(i + 1) * biHead1.biWidth + j + 1] + f[4] == 256) && (double_data[(i + 1) * biHead1.biWidth + j + 2] + f[5] == 256) && (double_data[(i + 2) * biHead1.biWidth + j + 1] + f[7] == 256))
{
new_data2[(i + 1) * biHead1.biWidth + j + 1] = 255;//锚点
}
}
//膨胀就是图像中的白的变大
double* new_data = new double[biHead1.biHeight * biHead1.biWidth]();
for (int i = 0; i < biHead1.biHeight-2; i++)
for (int j = 0; j < biHead1.biWidth-2; j++)
{
if (new_data2[(i + 1) * biHead1.biWidth + j + 1] + f[4] == 256)
{
new_data[i * biHead1.biWidth + j] = 255;
new_data[i* biHead1.biWidth + j + 1] = 255;
new_data[i * biHead1.biWidth + j + 2] = 255;
new_data[(i + 1) * biHead1.biWidth + j ] = 255;
new_data[(i + 1) * biHead1.biWidth + j + 1] = 255;//锚点
new_data[(i + 1) * biHead1.biWidth + j + 2] = 255;
new_data[(i + 2) * biHead1.biWidth + j ] = 255;
new_data[(i + 2) * biHead1.biWidth + j + 1] = 255;
new_data[(i + 2) * biHead1.biWidth + j + 2] = 255;
}
}
//显示
for (int i = 0; i < biHead1.biHeight; i++)
for (int j = 0; j < biHead1.biWidth; j++)
{
dc.SetPixel(j / time, (biHead1.biHeight - i) / time, RGB(new_data[j + i * biHead1.biWidth], new_data[j + i * biHead1.biWidth], new_data[j + i * biHead1.biWidth]));
}
结果:
闭运算实质上是先膨胀再腐蚀,它也会平滑轮廓的一部分,但通常会弥合较窄的间断和细长的沟壑,消除小的孔洞,填补轮廓线中的断裂。
举个栗子:
那么闭运算就是如下过程(深色像素为白色):
代码:
double f[9];
f[0] = 0;
f[1] = 1;
f[2] = 0;
f[3] = 1;
f[4] = 1;
f[5] = 1;
f[6] = 0;
f[7] = 1;
f[8] = 0;
double* new_data = new double[biHead1.biHeight * biHead1.biWidth]();
//先膨胀再腐蚀(闭操作弥合较窄的间断和细长的沟壑,消除小的空洞,填补轮廓线的中的断裂。
//膨胀就是图像中的白的变大
for (int i = 0; i < biHead1.biHeight-2; i++)
for (int j = 0; j < biHead1.biWidth-2; j++)
{
if (double_data[(i + 1) * biHead1.biWidth + j + 1] + f[4] == 256)
{
new_data[i * biHead1.biWidth + j] = 255;
new_data[i* biHead1.biWidth + j + 1] = 255;
new_data[i * biHead1.biWidth + j + 2] = 255;
new_data[(i + 1) * biHead1.biWidth + j ] = 255;
new_data[(i + 1) * biHead1.biWidth + j + 1] = 255;//锚点
new_data[(i + 1) * biHead1.biWidth + j + 2] = 255;
new_data[(i + 2) * biHead1.biWidth + j ] = 255;
new_data[(i + 2) * biHead1.biWidth + j + 1] = 255;
new_data[(i + 2) * biHead1.biWidth + j + 2] = 255;
}
}
//腐蚀就是图像中的白的变小
double* new_data2 = new double[biHead1.biHeight * biHead1.biWidth]();
for (int i = 0; i < biHead1.biHeight - 2; i++)
for (int j = 0; j < biHead1.biWidth - 2; j++)
{
if ((new_data[i * biHead1.biWidth + j + 1] + f[1] == 256) && (new_data[(i + 1) * biHead1.biWidth + j] + f[3] == 256) && (new_data[(i + 1) * biHead1.biWidth + j + 1] + f[4] == 256) && (new_data[(i + 1) * biHead1.biWidth + j + 2] + f[5] == 256) && (new_data[(i + 2) * biHead1.biWidth + j + 1] + f[7] == 256))
{
new_data2[(i + 1) * biHead1.biWidth + j + 1] = 255;//锚点
}
}
//显示
for (int i = 0; i < biHead1.biHeight; i++)
for (int j = 0; j < biHead1.biWidth; j++)
{
dc.SetPixel(j / time, (biHead1.biHeight - i) / time, RGB(new_data2[j + i * biHead1.biWidth], new_data2[j + i * biHead1.biWidth], new_data2[j + i * biHead1.biWidth]));
}
结果: