个人博客:http://www.chenjianqu.com/
原文链接:http://www.chenjianqu.com/show-14.html
目录:
1.前言
2.锐化滤波
3.Robert算子
4.Sobel算子
5.Prewitt算子
6拉普拉斯算子
7.一阶微分算子和二阶微分算子的对比
前言
在上次的文章 空间域平滑滤波 中介绍了空间域滤波和平滑滤波的概念,本文将继续介绍空间域滤波的另一大类,空间域锐化滤波。
锐化滤波
与平滑滤波的积分运算或平均运算相反,锐化滤波对图像求导,或者说求差分。是将图像的低频部分减弱或去除,保留图像的高频部分,即图像的边缘信息。图像的边缘、轮廓一般位于灰度突变的地方,也就是图像的高频部分,通常用灰度差分提取边缘轮廓。
图像中边缘轮廓通常是任意方向的,因此我们的差分运算需要具有方向性。各向同性的边缘检测算子对任意方向的边缘轮廓都有相同的检测能力。
常见的锐化滤波的方法有通过一阶微分算子和二阶微分算子进行卷积运算。
一阶微分算子
在图像处理中,一阶微分是通过梯度算法来实现的。对于一幅图像用函数f(x,y)表示,定义在f(x,y)在点(x,y)处的梯度是一个矢量,定义为:
梯度的幅度G[f(x,y)]可以由以下公式算出:
梯度的 方向是函数f(x,y)最大变化率的方向上。
梯度的数值就是f(x,y)在其最大变化率方向上的单位距离所增加的量。对于数字图像而言,微分可用差分来近似。
Roberts算子
交叉一阶差分,得到Roberts算子:
即各个像素f(x,y),f(x+1,y+1),f(x+1,y),f(x,y+1)之间的位置关系为:
程序进行计算时只需要每个像素的都用模板进行卷积运算即可:
为避免出现负值,需要对运算结果求绝对值。
代码实现:
Mat ConvolutionOperationRobert(Mat &src)
{
//当kernel大小2x2时,以左上角为原点
Mat dst(src.rows, src.cols, src.type(), Scalar(0));
if (src.channels() == 1)
for (int i = 0; i < src.rows-1; i++)
for (int j = 0; j < src.cols-1; j++)
dst.at<uchar>(i, j) = abs(src.at<uchar>(i, j) - src.at<uchar>(i + 1, j + 1)) + abs(src.at<uchar>(i + 1, j) - src.at<uchar>(i, j + 1));
return dst;
}
运行结果:
Sobel算子
Sobel算子也是由一阶微分算子公式推导而来的。Roberts算子是基于2*2窗口计算近似梯度,而Sobel算子是基于3*3窗口计算近似梯度的,并且Sobel算子并不是各向同性的算子,它分为:
水平边缘检测Sobel算子gx
垂直边缘检测Sobel算子gy
Sobel算子的模板如下:
代码实现:
Mat ConvolutionOperationAbs(Mat &src, Mat &kernel1, Mat &kernel2)
{
Mat dst(src.rows, src.cols, src.type(), Scalar(0));
if (src.channels() == 1)
{
int rowsSub = int(kernel1.rows / 2);
int colsSub = int(kernel1.cols / 2);
for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++)
{
if (i <rowsSub || i >= src.rows - rowsSub-1 || j < colsSub || j >= src.cols - colsSub-1)
dst.at<uchar>(i, j) = src.at<uchar>(i, j);
else
{
float sum1 = 0;
float sum2 = 0;
for (int ki = 0; ki < kernel1.rows; ki++)
{
for (int kj = 0; kj < kernel1.cols; kj++)
{
int i_ = i + ki - rowsSub;
int j_ = j + kj - colsSub;
sum1 += src.at<uchar>(i_, j_)*kernel1.at<float>(ki, kj);
sum2 += src.at<uchar>(i_, j_)*kernel2.at<float>(ki, kj);
}
}
dst.at<uchar>(i, j) = abs(int(sum1))+abs(int(sum2));
}
}
}
}
return dst;
}
Kernel1和kernel2分别为水平检测算子和垂直检测算子,运行结果:
Prewitt算子
Prewitt是Sobel算子的无权重版本,模版如下:
Prewitt算子边缘检测和Sobel算子结果相似,但不如其细节丰富。
代码实现:
代码Sobel算子差不多,只是输入的kernel不同。
运行结果:
二阶微分算子
拉普拉斯微分算子
前面介绍的几个算子都是一阶微分算子,接下来我们介绍更高阶的微分算子:拉普拉斯微分算子。拉普拉斯算子是一个是n维欧几里德空间中的一个二阶微分算子,它的定义如下:
在x方向上
在y方向上
合起来就是
因此得到拉普拉斯算子的模板为:
代码实现:
Mat ConvolutionOperationAbs(Mat &src, Mat &kernel)
{
Mat dst(src.rows, src.cols, src.type(), Scalar(0));
if (src.channels() == 1)
{
int rowsSub = int(kernel.rows / 2);
int colsSub = int(kernel.cols / 2);
for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++)
{
if (i < rowsSub || i >= src.rows - rowsSub || j < colsSub || j >= src.cols - colsSub)
dst.at<uchar>(i, j) = src.at<uchar>(i, j);
else
{
float sum = 0;
for (int ki = 0; ki < kernel.rows; ki++)
{
for (int kj = 0; kj < kernel.cols; kj++)
{
int i_ = i + ki - rowsSub;
int j_ = j + kj - colsSub;
sum += src.at<uchar>(i_, j_)*kernel.at<float>(ki, kj);
}
}
dst.at<uchar>(i, j) = abs(int(sum));
}
}
}
}
return dst;
}
运行结果:
一阶微分算子和二阶微分算子对比
下面的第一个图是原函数曲线,第二张图片是一阶导数曲线,第三张图片为二阶导数曲线:
从上图可知,二阶导数增强域不是频率最高的部分(边缘),而有一定偏差,并且增强幅度并不如一阶导数。如果求绝对值,图像负y轴部分翻正,会产生双边缘。
Laplace算子做锐化滤波的特点
1.对噪声敏感
2.产生双边源
3.缓慢区域产生暗背景
图像锐化
上面介绍了各种算子进行滤波处理得到边缘图像,但是在图像处理中,我们有时候想要的是增强后的图像,这时只需要将锐化得到的图像与原图线性相加即可。下面给出各算子增强后的图像:
Robert算子:
Sobel算子:
Prewitt算子:
拉普拉斯算子:
参考文献
[1]CSDN博客:joaming. 图像增强-图像锐化.
https://blog.csdn.net/joaming/article/details/82149296 . 2018-08-28
[2]CSDN博客:我是郭俊辰. Matlab图像处理系列3———空间域锐化滤波器.
https://blog.csdn.net/u014030117/article/details/46383659. 2015-06-06