本文实现了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
#include
#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进行了实验,若要实验其他算子,需适当修改程序。