Opencv学习笔记七(梯度算子、锐化)

Sobel算子

卷积的作用除了实现图像模糊或者去噪,还可以寻找一张图像上所有梯度信息,这些梯度信息是图像的最原始特征数据,进一步处理之后就可以生成一些比较高级、抽象的特征用来表示一张图像实现基于图像特征的匹配,图像分类等应用。

Sobel算子是一种很经典的图像梯度提取算子,其本质是基于图像空间域卷积,背后的思想是图像一阶导数算子的理论支持。

OpenCV实现了基于Sobel算子提取图像梯度的API,表示与解释如下:

void cv::Sobel( 

InputArray src, // 输入图像 

OutputArray dst, // 输出结果 

int ddepth, // 图像深度CV_32F 当ddepth取值为-1时,表示输入图像和输出图像的深度相同,但最终的结果很不理想,这是因为Sobel算子的输出图像的所取值已经超过了0~255,如果仍已字节输出,会造成截断或溢出,造成信息丢失

int dx,// 1,X方向 一阶导数 

int dy, // 1,Y方向 一阶导数 

int ksize = 3, // 窗口大小 

double scale = 1, // 放缩比率,1 表示不变 

double delta = 0, // 对输出结果图像加上常量值 

int borderType = BORDER_DEFAULT ) 

Python: dst = cv.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType) 

Opencv学习笔记七(梯度算子、锐化)_第1张图片

图a为一张lenna的灰度图像,图b为在红色圆圈内像素的变化情况,图c为图b的求导

图像的像素之间存在着差值,梯度计算的就是相临像素之间的差异

x_grad=cv.Sobel(src,cv.CV_32F,1,0)
y_grad=cv.Sobel(src,cv.CV_32F,0,1)
x_grad=cv.convertScaleAbs(x_grad)
y_grad=cv.convertScaleAbs(y_grad)
dst=add(x_grad,y_grad,cv.CV_16S)
dst=cv.convertScaleAbs(dst)
cv.imshow("gradient",dst)

更多梯度算法

图像的一阶导数算子除了sobel算子之外,常见的还有robert算子与prewitt算子,它们也都是非常好的可以检测图像的梯度边缘信息,通过OpenCV中自定义滤波器,使用自定义创建的robert与prewitt算子就可以实现图像的rober与prewitt梯度边缘检测

OpenCV中的自定义算子滤波函数如下:

C++:
filter2D(
InputArray src,//输入
OutputArray dst,//输出
int ddepth,//图像深度
InputArray 	kernel,
Point anchor = Point(-1,-1),
double delta = 0,
int borderType = BORDER_DEFAULT 
)
Python:
dst	=cv.filter2D(src, ddepth, kernel, dst, anchor, delta, borderType)

Opencv学习笔记七(梯度算子、锐化)_第2张图片

上图为Robert算子和Prewitt算子的卷积窗口

Robert算子的梯度结果更浅,没有Prewitt算子那样对比强烈

robert_x=np.array([[1,0],[0,-1]],np.float32)
robert_y=np.array([[0,-1],[1,0]],np.float32)#Robert算子卷积窗口

prewitt_x=np.array([[-1,0,1],[-1,0,1],[-1,0,1]])
prewitt_y=np.array([[-1,-1,-1],[0,0,0],[1,1,1]])#Prewitt算子卷积窗口

robert_grad_x=cv.filter2D(src,cv.CV_16S,robert_x)
robert_grad_y=cv.filter2D(src,cv.CV_16S,robert_y)
robert_grad_x=cv.convertScaleAbs(robert_grad_x)
robert_grad_y=cv.convertScaleAbs(robert_grad_y)#自定义滤波器

prewitt_grad_x=cv.filter2D(src,cv.CV_16S,prewitt_x)
prewitt_grad_y=cv.filter2D(src,cv.CV_16S,prewitt_y)
prewitt_grad_x=cv.convertScaleAbs(prewitt_grad_x)
prewitt_grad_y=cv.convertScaleAbs(prewitt_grad_y)

拉普拉斯算子

图像的一阶导数算子可以得到图像梯度局部梯度相应值,二阶导数可以通过快速的图像像素值强度的变化来检测图像边缘,其检测图像边缘的原理跟图像的一阶导数有点类似,只是在二阶导数是求X、Y方向的二阶偏导数,对图像来说:
X方向的二阶偏导数就是 dx = f(x+1, y) + f(x-1, y) – 2 *f(x, y)
Y方向的二阶偏导数就是 dy = f(x, y+1) + f(x, y-1) – 2 *f(x, y)
对X方向与Y方向进行叠加最终就得到delta对应的二阶导数算子,看下面的图像最下面的部分就是对应的四邻域的二阶导数算子,我们可以进一步扩展增强为八邻域的算子。

OpenCV中Laplacian滤波函数就是二阶导数发现边缘的函数:

void cv::Laplacian(
InputArray src,
OutputArray dst,
int ddepth, // 深度默认是-1表示输入与输出图像相同
int ksize = 1,// 必须是奇数, 等于1是四邻域算子,大于1改用八邻域算子
double scale = 1,
double delta = 0, // 对输出图像加上常量值
int borderType = BORDER_DEFAULT 
)		
Python:
dst	= cv.Laplacian(src, ddepth, dst, ksize, scale, delta, borderType)

拉普拉斯算子是一种特别容易受到噪声干扰的边缘发现算子,所以经常对要处理的图像首先进行一个高斯模糊,然后再进行拉普拉斯算子的边缘提取,而且在一些场景中会把这两步合并成为一步,就是我们经常听说的LOG算子。

Opencv学习笔记七(梯度算子、锐化)_第3张图片

src=cv.GaussianBlur(image,(0,0),1)
dst=cv.Laplacian(src,cv.CV_32F,ksize=3,delta=127)
dst=cv.convertScaleAbs(dst)

图像锐化

图像卷积的主要有三功能分别是图像的模糊/去噪图像梯度/边缘发现图像锐化/增强,前面的两个功能我们以前通过相关知识点的分享加以了解,学习了相关API的使用。图像锐化的本质是图像拉普拉斯滤波加原图权重像素叠加的输出
-1 -1 -1
-1 C -1
-1 -1 -1
当C值大于8时候表示图像锐化、越接近8表示锐化效果越好
当C值等于8时候图像的高通滤波
当C值越大,图像锐化效果在减弱、中心像素的作用在提升

图片的像素细节部分提升

#sharpen_op=np.array([-1,-1,-1],[-1,9,-1],[-1,-1,-1])
sharpen_op=np.array([0,-1,0],[-1,5,-1],[0,-1,0])	#两种卷积和
sharpen_image=cv.filter2D(src,cv.CV_16S,sharpen_op)
sharpen_image=cv.convertScaleAbs(sharpen_image)

USM 锐化增强算法

图像卷积处理实现锐化有一种常用的算法叫做Unsharpen Mask方法,这种锐化的方法就是对原图像先做一个高斯模糊,然后用原来的图像减去一个系数乘以高斯模糊之后的图像,然后再把值Scale到0~255的RGB像素值范围之内。基于USM锐化的方法可以去除一些细小的干扰细节和噪声,比一般直接使用卷积锐化算子得到的图像锐化结果更加真实可信。
USM锐化公式表示如下:
(源图像– w*高斯模糊)/(1-w);其中w表示权重(0.1~0.9),默认为0.6
OpenCV中的代码实现步骤

  1. 高斯模糊
  2. 权重叠加
  3. 输出结果
blur_img=cv.GaussianBlur(src,(0,0),5)
usm = cv.addWeighted(src,1.5,blur_img,-0.5,0)#图像基于权重相加,最后一个数——伽马矫正

你可能感兴趣的:(Opencv学习笔记七(梯度算子、锐化))