C++——bmp图像的平滑、锐化(拉普拉斯+sobel+prewitt+Roberts Cross operator)

本文实现了RGB三通道图像及灰度图像的平滑、锐化处理。在开始之前,我们先对平滑及锐化的概念进行一个简单的了解:

1、平滑

       图像平滑是指受传感器和大气等因素的影响,遥感图像上会出现某些亮度变化过大的区域,或出现一些亮点(也称噪声)。这种为了抑制噪声,使图像亮度趋于平缓的处理方法就是图像平滑。图像平滑实际上是低通滤波,平滑过程会导致图像边缘模糊化。

常用的平滑处理方法有三种:
(1) Box模板去噪平滑处理,也就是均一化处理。
                     Box模板是{1,1,1,1,1,1,1,1,1}
(2) 高斯模板去噪平滑处理,就是在Box模板的基础上加入了加权系数,考虑了距离某点位置越近影响越大的因素。相比Box模板,较为清晰一些。
                     高斯模板是{1,2,1,2,4,2,1,2,1}

(3) 中值滤波去噪平滑处理,就是将该点左右邻近的两个点的rgb值与该点自身进行比较,选择其中最中间的值赋给该点。

2、锐化

       图像锐化(image sharpening)是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强

常用的锐化模板是拉普拉斯(Laplacian)算子:


代码如下:

#include <cstring>
#include <windows.h>
#include"readbmp.h"
#include"savebmp.h"

int Template1[3][3] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };//平滑模板  均一化处理
int Template2[3][3] = { 1, 2, 1, 2, 4, 2, 1, 2, 1 };//高斯平模板  
int Template3[3][3] = { 0, -1, 0, -1, 4, -1, 0, -1, 0 };//laplace锐化模板,4邻域  
int Template4[3][3] = { -1, -1, -1, -1, 8, -1, -1, -1, -1 };//laplace锐化模板,8邻域  
int sobelx[3][3] = { -1,-2,-1,0,0,0,1,2,1};//sobelx
int sobely[3][3] = { -1,0,1,-2,0,2,-1,0,1};//sobel  
int coefficient1 = 9;
int coefficient2 = 16;
int coefficient3 = 1;

void img_smooth_sharpen(int Template[][3], int coefficient)
{
	char readPath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\11.bmp";
	readBmp(readPath);

	unsigned char *imagedatasmooth;
	unsigned char *imagedata;
	imagedata = pBmpBuf;


	//平滑算子也是通过模板进行处理的,所以可以把平滑处理和锐化处理通过一个函数实现  

	//分配新像素素组的空间  
	int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
	imagedatasmooth = new unsigned char[lineByte * bmpHeight];
	//进行模板操作  
	for (int i = 0; i < bmpHeight; i++)
		for (int j = 0; j < bmpWidth; j++) 
			for (int k = 0; k < 3; k++)
			{
				if (i == 0 || j == 0 || i == bmpHeight - 1 || j == bmpWidth - 1)
					*(imagedatasmooth + i*bmpWidth*3 + j*3+k) = *(imagedata + i*bmpWidth*3 + j*3+k);
				else 
				{
					int sum = 0;
					for (int m = i - 1; m < i + 2; m++)
						for (int n = j - 1; n < j + 2; n++)
						{
						
							sum += (*(imagedata + m*bmpWidth * 3 + n * 3 + k))*Template[n - j + 1][m - i + 1] / coefficient;

						}//8位BMP中一个像素值,对应调色板中索引号为该像素值的项所存放的RGB色彩  
							//所以像素值范围为0~255,像素值小于0就取0,大于255就取255  
							
							sum = (sum > 0) ? sum : 0;
							sum = (sum >255) ? 255 : sum;

							*(imagedatasmooth + i*bmpWidth * 3 + j * 3 + k) = sum;
					
				}
			}
		



	char writePath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\11s1.bmp";
	saveBmp(writePath, imagedatasmooth, bmpWidth, bmpHeight, biBitCount, pColorTable);
	printf("平滑操作完成,请查看bmp文件。\n\n");
}

void imggray_smooth_sharpen(int Template[][3], int coefficient)
{
	char readPath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\11.bmp";
	readBmp(readPath);

	unsigned char *imagedatasmooth;
	unsigned char *imagedata;
	imagedata = pBmpBuf;


	//平滑算子也是通过模板进行处理的,所以可以把平滑处理和锐化处理通过一个函数实现  

	//分配新像素素组的空间  
	int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
	imagedatasmooth = new unsigned char[lineByte * bmpHeight];
	//进行模板操作  
	for (int i = 0; i < bmpHeight; i++)
		for (int j = 0; j < bmpWidth; j++)
			
				if (i == 0 || j == 0 || i == bmpHeight - 1 || j == bmpWidth - 1)
					*(imagedatasmooth + i*bmpWidth  + j  ) = *(imagedata + i*bmpWidth  + j );
				else
				{
					int sum = 0;
					for (int m = i - 1; m < i + 2; m++)
						for (int n = j - 1; n < j + 2; n++)
						{

							sum += (*(imagedata + m*bmpWidth  + n  ))*Template[n - j + 1][m - i + 1] / coefficient;

						}//8位BMP中一个像素值,对应调色板中索引号为该像素值的项所存放的RGB色彩  
					//所以像素值范围为0~255,像素值小于0就取0,大于255就取255  

					sum = (sum > 0) ? sum : 0;
					sum = (sum >255) ? 255 : sum;

					*(imagedatasmooth + i*bmpWidth + j ) = sum;

				}
			

	char writePath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\11s1.bmp";
	saveBmp(writePath, imagedatasmooth, bmpWidth, bmpHeight, biBitCount, pColorTable);
	printf("平滑操作完成,请查看bmp文件。\n\n");
}

其中,img_smooth_sharpen( )对应的是RGB图的平滑及锐化处理,imggray_smooth_sharpen( )对应的是灰度图的平滑及锐化处理。

3、sobel算子

       索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。

Sobel卷积因子为:


       该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:


图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:


通常,为了提高效率 使用不开平方的近似值:


梯度计算方法如下:


       Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。

代码如下:

void imggray_sobel_sharpen(int Templatex[][3], int Templatey[][3], int coefficient)
{
	char readPath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\gray.bmp";
	readBmp(readPath);

	unsigned char *imagedatasobel;
	unsigned char *imagedatasobelx;
	unsigned char *imagedatasobely;
	unsigned char *imagedata;
	imagedata = pBmpBuf;


	//平滑算子也是通过模板进行处理的,所以可以把平滑处理和锐化处理通过一个函数实现  

	//分配新像素素组的空间  
	int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
	imagedatasobel = new unsigned char[lineByte * bmpHeight];
	imagedatasobelx = new unsigned char[lineByte * bmpHeight];
	imagedatasobely = new unsigned char[lineByte * bmpHeight];
	//进行模板操作  
	for (int i = 0; i < bmpHeight; i++)
		for (int j = 0; j < bmpWidth; j++)

			if (i == 0 || j == 0 || i == bmpHeight - 1 || j == bmpWidth - 1)
			{
				*(imagedatasobelx + i*bmpWidth + j) = *(imagedata + i*bmpWidth + j);
				*(imagedatasobely + i*bmpWidth + j) = *(imagedata + i*bmpWidth + j);
			}
			else
			{
				int sumx = 0;
				int sumy = 0;
				for (int m = i - 1; m < i + 2; m++)
					for (int n = j - 1; n < j + 2; n++)
					{

						sumx += (*(imagedata + m*bmpWidth + n))*Templatex[n - j + 1][m - i + 1] / coefficient;
						sumy += (*(imagedata + m*bmpWidth + n))*Templatey[n - j + 1][m - i + 1] / coefficient;

					}//8位BMP中一个像素值,对应调色板中索引号为该像素值的项所存放的RGB色彩  
				//所以像素值范围为0~255,像素值小于0就取0,大于255就取255  

				sumx = (sumx > 0) ? sumx : 0;
				sumx = (sumx >255) ? 255 : sumx;

				*(imagedatasobelx + i*bmpWidth + j) = sumx;//sobelx

				sumy = (sumy > 0) ? sumy : 0;
				sumy = (sumy >255) ? 255 : sumy;

				*(imagedatasobely + i*bmpWidth + j) = sumy;//sobely

				*(imagedatasobel + i*bmpWidth + j) =abs( *(imagedatasobelx + i*bmpWidth + j)) + abs(*(imagedatasobely + i*bmpWidth + j));


			}


	char writePath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\11s1.bmp";
	saveBmp(writePath, imagedatasobel, bmpWidth, bmpHeight, biBitCount, pColorTable);
	printf("平滑操作完成,请查看bmp文件。\n\n");
}

4、普利维特算子(Prewitt operate)

卷积因子如下:


计算 和sobel差不多;

Prewitt算子利用像素点上下、左右邻点灰度差,在边缘处达到极值检测边缘。对噪声具有平滑作用,定位精度不够高。

5、罗伯茨交叉边缘检测(Roberts Cross operator)

卷积因子如下:


灰度公式:


近似公式:


灰度方向计算公式为:


       Roberts算子采用对角线方向相邻两像素之差近似梯度幅值检测边缘。检测水平和垂直边缘的效果好于斜向边缘,定位精度高,对噪声敏感。

这三种检测算子,本文仅用sobel进行了实验,若要实验其他算子,需适当修改程序。

猜你喜欢

转载自blog.csdn.net/wanty_chen/article/details/80336986