数字图像处理(八)形态学处理之灰度级腐蚀、膨胀、开运算、闭运算、顶帽变换和底帽变换

本篇所有代码都是基于24位BMP图像

一. 灰度级腐蚀运算

灰度级腐蚀运算可以看成一种特殊的二维卷积运算,只不过用最小值运算代替了相关运算,用减法运算代替了相关运算的卷积操作。

灰度腐蚀运算时逐点进行的,计算该点局部范围内各点与结构元素对应点的灰度差,并选取差的最小值,作为该点的腐蚀结果。(先赋值255,再赋值差的最小值)

1.如果结构元素都是正的,则输出图像会比输入图像暗。

我们设结构元素3*3,且值都是0,看看代码

MFC中添加Menu,添加类向导

void CImageProcessingView::OnXtxHdfs()
{
	// TODO: 在此添加命令处理程序代码
	if (numPicture == 0)
	{
		AfxMessageBox("请输入一张图像", MB_OK, 0);
		return;
	}

	if (m_nBitCount != 24)
	{
		AfxMessageBox("输入图片不是24位", MB_OK, 0);
		return;
	}
	AfxMessageBox("灰度图像腐蚀!", MB_OK, 0);


	int num;//记录每一行需要填充的字节
	if (m_nWidth * 3 % 4 != 0)
	{
		num = 4 - m_nWidth * 3 % 4;
	}
	else
	{
		num = 0;
	}

	//打开临时的图片  
	FILE *fpo = fopen(BmpName, "rb");
	FILE *fpw = fopen(BmpNameLin, "wb+");
	fread(&bfh, sizeof(BITMAPFILEHEADER), 1, fpo);
	fread(&bih, sizeof(BITMAPINFOHEADER), 1, fpo);
	fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, fpw);
	fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, fpw);
	fread(m_pImage, m_nImage, 1, fpo);
	unsigned char *ImageSize;
	ImageSize = new unsigned char[m_nImage];
	int x, y, val,xx,yy,temp;
	for (y = 1; y < m_nHeight - 1; y++)
	{
		for (x = 1; x < m_nWidth - 1; x++)
			//由于使用3*3的结构元素,防止越界,不处理最左边和最右边的的像素
		{
			val = 255;
			for (int j = 0; j < 3; j++)
			{
				yy = y + j - 1;
				for (int i = 0; i < 3; i++)
				{
					xx = x + i - 1;
					if (m_pImage[(xx + yy*m_nWidth) * 3 + yy * num] < val)//因为结构元素都是0,所以原图像中各点与对应结构元素想减还是原图像本身,
																		  //找想减后差的最小值作为点(x,y)的灰度
					{
						val = m_pImage[(xx + yy*m_nWidth) * 3 + yy * num];
					}
				}
			}
			ImageSize[(x + y*m_nWidth) * 3 + y*num] = unsigned char(val);
			ImageSize[(x + y*m_nWidth) * 3 + y*num + 1] = unsigned char(val);
			ImageSize[(x + y*m_nWidth) * 3 + y*num + 2] = unsigned char(val);
		}
	}

	fwrite(ImageSize, m_nImage, 1, fpw);

	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level = 400;
	Invalidate();
}

看看结果


可以发现,黑的地方更黑了。

二. 灰度级膨胀运算

灰度级膨胀运算和腐蚀相反,是将原图像各点与对应结构元素中各相加,把相加后的最大值作为目标图像中当前点的灰度值

(先赋值0,再赋值最大值)

MFC中添加Menu,添加类向导,代码如下

void CImageProcessingView::OnXtxHdpz()
{
	// TODO: 在此添加命令处理程序代码
	if (numPicture == 0)
	{
		AfxMessageBox("请输入一张图像", MB_OK, 0);
		return;
	}

	if (m_nBitCount != 24)
	{
		AfxMessageBox("输入图片不是24位", MB_OK, 0);
		return;
	}
	AfxMessageBox("灰度图像膨胀!", MB_OK, 0);


	int num;//记录每一行需要填充的字节
	if (m_nWidth * 3 % 4 != 0)
	{
		num = 4 - m_nWidth * 3 % 4;
	}
	else
	{
		num = 0;
	}

	//打开临时的图片  
	FILE *fpo = fopen(BmpName, "rb");
	FILE *fpw = fopen(BmpNameLin, "wb+");
	fread(&bfh, sizeof(BITMAPFILEHEADER), 1, fpo);
	fread(&bih, sizeof(BITMAPINFOHEADER), 1, fpo);
	fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, fpw);
	fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, fpw);
	fread(m_pImage, m_nImage, 1, fpo);
	unsigned char *ImageSize;
	ImageSize = new unsigned char[m_nImage];
	int x, y, val, xx, yy, temp;
	for (y = 1; y < m_nHeight - 1; y++)
	{
		for (x = 1; x < m_nWidth - 1; x++)
			//由于使用3*3的结构元素,防止越界,不处理最左边和最右边的的像素
		{
			val = 0;
			for (int j = 0; j < 3; j++)
			{
				yy = y + j - 1;
				for (int i = 0; i < 3; i++)
				{
					xx = x + i - 1;
					if (m_pImage[(xx + yy*m_nWidth) * 3 + yy * num] > val)//因为结构元素都是0,所以原图像中各点与对应结构元素想加还是原图像本身,
																		  //找和的最大值作为点(x,y)的灰度
					{
						val = m_pImage[(xx + yy*m_nWidth) * 3 + yy * num];
					}
				}
			}
			ImageSize[(x + y*m_nWidth) * 3 + y*num] = unsigned char(val);
			ImageSize[(x + y*m_nWidth) * 3 + y*num + 1] = unsigned char(val);
			ImageSize[(x + y*m_nWidth) * 3 + y*num + 2] = unsigned char(val);
		}
	}

	fwrite(ImageSize, m_nImage, 1, fpw);

	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level = 400;
	Invalidate();
}

看看结果


可以看到,黑的变细了,白圈变大了。

三. 灰度开运算

先腐蚀,再膨胀。可以去除相对于结构元素较小的明亮细节,保持整体的灰度和较大的明亮区域不变

四. 灰度闭运算

先膨胀,再腐蚀。可以去除相对于结构元素较小的细节,保持整体的灰度和较大的暗区域不变

五. 顶帽变换和底帽运算

顶帽变换通俗的讲就是原图减去开运算(先腐蚀,后膨胀,去白变黑)后的结果。而底帽运算闭运算(先膨胀,再腐蚀,去黑变白)减去原图的结果


猜你喜欢

转载自blog.csdn.net/hjxu2016/article/details/80738290