图像锐化
图像锐化(image sharpening)是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空间域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。
图像锐化处理的目的是为了使图像的边缘、轮廓线以及图像的细节变得清晰,经过平滑的图像变得模糊的根本原因是因为图像受到了平均或积分运算,因此可以对其进行逆运算(如微分运算)就可以使图像变得清晰。微分运算是求信号的变化率,由傅立叶变换的微分性质可知,微分运算具有较强高频分量作用。从频率域来考虑,图像模糊的实质是因为其高频分量被衰减,因此可以用高通滤波器来使图像清晰。但要注意能够进行锐化处理的图像必须有较高的性噪比,否则锐化后图像性噪比反而更低,从而使得噪声增加的比信号还要多,因此一般是先去除或减轻噪声后再进行锐化处理。
原理:
图像平滑往往使图像中的边界、轮廓变得模糊,为了减少这类不利效果的影响,这就需要利用图像锐化技术,使图像的边缘变的清晰。
在图像的增强处理中除了去噪,对比度扩展外,有时候还需要加强图像中景物的边缘和轮廓。而边缘和轮廓常常位于图像中灰度突变的地方,因而可以直观地想到用灰度的差分对边缘和轮廓进行提取。
原理:利用图像的高频分量来实现的,将原图像的高频分量提取出来,再和原图像按一定规则叠加起来,最终得到的图像就是锐化后的图像。提取高频分量可以有如下两种方式:
-
1.直接使用高通滤波器来提取图像高频分量,如Sobel算子、Laplace算子、梯度Prewitt算子等。其中Sobel提取出来的边缘比较粗糙,Laplace提取出来的边缘更加细腻,因此也更加适合用于做锐化滤波器;
-
2.先使用低通滤波器对图像进行滤波处理,得到图像中的低频分量,再用原图像减去滤波得到的低频分量图像得到高频分量,最后将高频分量和原图像叠加得到锐化后的图像。这种方法也称为非锐化掩模(USM),我们常使用低通滤波器(高斯、双边)对图像进行滤波,这种方法的滤波器很好控制(包括大小和强弱),从而可以灵活控制高频分量的强弱。
USM锐化增强算法
数字图像处理中关于图像增强算法有两种常用的技术:非锐化掩蔽和高提升滤波:
g = f + k ⋅ m k > 0 k = { > 1 , 高 提 升 滤 波 = 1 , 非 锐 化 掩 蔽 < 1 , 不 强 调 非 锐 化 模 板 的 贡 献 g=f+k·m \ \ \ \ \ \ k>0 k= \begin{cases} >1, &高提升滤波 \\ =1, &非锐化掩蔽 \\ <1, &不强调非锐化模板的贡献 \end{cases} g=f+k⋅m k>0k=⎩⎪⎨⎪⎧>1,=1,<1,高提升滤波非锐化掩蔽不强调非锐化模板的贡献
其中g表示锐化后的图像,f表示原图像,k表示锐化系数,m为高频分量图像。
传统的锐化算法
通过获取高频分量然后与原图像叠加做锐化,其步骤:
- 首先使用低通滤波器平滑原图像得到低频分量图像:s = f(低通滤波);
- 原图像减去低频分量图像,产生的差值,高频分量图像称为模板:m = f - s
- 将模板图像乘以一个系数,加到原图像中,得到锐化后的图像:g = f + k × m
这种方法虽然效果很明显,但是容易出现噪声增强的现象,而且很容易在图像纹理的边缘处产生明亮的伪边缘。
改进的非锐化掩模(USM)
设置一个阈值,将原图像与滤波后得到的高频分量图像做差值,再与阈值比较,其步骤:
- 先对原图像src做高斯滤波得到滤波图像BlurImg,src(高斯模糊) -> BlurImg;
- 原图像src与滤波图像做差值,再与阈值Threshold比较,结果存放在掩模Mask中,Mask = abs( src - BlurImg ) < Threshold ? 1 : 0;
- 将src与高频分量图像按一定系数叠加,得到锐化图像,SharpenImg = src + k × ( src - BlurImg );
- 将src中Mask对应的非0部分复制到SharpenImg 中;
#define SharpenFactor 1 //锐化系数
#define SharpenThs 30 //锐化阈值
void ImproveUSM(Mat src, Mat BlurImg, int Threshold, float Factor)
{
Mat DiffMask, dst;
DiffMask = Mat::zeros(src.rows, src.cols, src.type());
if (src.channels() == 1) //灰度单通道
{
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
int Value_diff = abs(src.at<uchar>(i, j) - BlurImg.at<uchar>(i, j));
if (Value_diff < Threshold) //小于阈值说明非边缘,不需要锐化
DiffMask.at<uchar>(i, j) = 1;
else
DiffMask.at<uchar>(i, j) = 0;
}
}
}
else if (src.channels() == 3) //三通道BGR
{
int Value_diff[3] = { 0 };
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
for (int k = 0; k < 3; k++)
{
Value_diff[k] = abs(src.at<Vec3b>(i, j)[k] - BlurImg.at<Vec3b>(i, j)[k]);
if (Value_diff[k] < Threshold) //小于阈值说明非边缘,不需要锐化
DiffMask.at<Vec3b>(i, j)[k] = 1;
else
DiffMask.at<uchar>(i, j) = 0;
}
}
}
}
addWeighted(src, 1 + Factor, BlurImg, -Factor, 0, dst); //将两幅图按权重系数融合,dst = src + Factor(src - BlurImg)
src.copyTo(dst, DiffMask); //将src中DiffMask对应的非0部分复制到dst中
imshow("ImproveUSM", dst);
}
int main()
{
int Ths = SharpenThs;
float Fac = SharpenFactor;
Mat src = imread("D:/test/src.jpg");
imshow("src", src);
Mat blur_img, USMsharpen_img, sharpen_img, sharpen_kernel;
sharpen_kernel = (Mat_<float>(3, 3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
filter2D(src, sharpen_img, CV_32F, sharpen_kernel);
convertScaleAbs(sharpen_img, sharpen_img);
imshow("sharpen", sharpen_img);
GaussianBlur(src, blur_img, Size(9, 9), 0, 0);
addWeighted(src, 1 + Fac, blur_img, -Fac, 0, USMsharpen_img);
imshow("USMsharpen", USMsharpen_img);
//使用自己写的改进版本的USM锐化
ImproveUSM(src, blur_img, Ths, Fac);
waitKey(0);
return 0;
}