跳转至

图像梯度

图像梯度

图像梯度代表图像灰度值变化的速度,对于一副图像而言,其边缘部分两侧灰度值相差较大,梯度值大,所以对一副图像求梯度可以突出图像边缘的信息。由于像素值为离散值,所以其梯度其是就是差分运算,其本质上也就是一种空间滤波。

sobel算子

其掩膜结构为:

  • 水平梯度
G_x = \left[ \begin{matrix} -1 & 0 & 1 \newline -2 & 0 & 2 \newline -1 & 0 & 1 \end{matrix} \right]
  • 垂直梯度 $$ G_y = \left[ \begin{matrix} -1 & -2 & -1 \newline 0 & 0 & 0 \newline 1 & 2 & 1 \end{matrix} \right] $$

  • 合成

G=\sqrt{G_{x}^{2}+G_{y}^{2}}

opencv中提供了cv2.Sobel()来实现Sobel算子的运算:

dst=cv2.Sobel(src,ddepth,dx,dy,[,ksize[,scale[,delta[,borderType]]]])

参数说明: dst:目标输出图像 src:原始输入图像 ddepth:图像深度,默认值-1与原始图像相同深度,但注意原始图像一般为cv2.CV_8U,则由于求梯度的时候会出现负值的情况,其会将负值直接置为0,此时会丢失图像许多信息,所以要将其一般转化为更高位灰度去求梯度,再对结果求绝对值。ddepth一般取cv2.CV_64F。 dx:代表x方向上求导 dy:代表y方向上求导 ksize:掩模大小 scale:求导之后值的缩放因子,默认为1,即不会缩放 delta:表示偏置在目标图像上的值,用于调节亮度 borderType:边界处理类型

示例代码:

import cv2 as cv

img = cv.imread("img/brain.jpg",cv.IMREAD_GRAYSCALE)
cv.imshow("src",img)

# sobel算子  参数1:图像, 参数2:图像的深度 -1表示和原图相同, 参数3: x方向求导的阶数 参数4: y方向求导的阶数
x_sobel = cv.Sobel(img, cv.CV_32F, 1, 0)
# 将图像转成8位int
x_sobel = cv.convertScaleAbs(x_sobel)

cv.imshow("x sobel",x_sobel)


# sobel算子
y_sobel = cv.Sobel(img, cv.CV_16S, 0, 1)
# 将图像转成8位int
y_sobel = cv.convertScaleAbs(y_sobel)
cv.imshow("y_sobel",y_sobel)


# 将x,y方向的内容叠加起来
x_y_sobel = cv.addWeighted(x_sobel, 0.5, y_sobel, 0.5,0)
cv.imshow("x,y sobel",x_y_sobel)

cv.waitKey(0)
cv.destroyAllWindows()

scharr算子

其基本思想与sobel算子一样,只是两者所使用掩模的结构不一样,在运算中,其梯度近似的结果比sobel更精确,其算子如下:

  • 水平梯度
G_x = \left[ \begin{matrix} -3 & 0 & 3 \newline -10 & 0 & 10 \newline -3 & 0 & 3 \end{matrix} \right]
  • 垂直梯度
G_y = \left[ \begin{matrix} -3 & -10 & -3 \newline 0 & 0 & 0 \newline 3 & 10 & 3 \end{matrix} \right]

在opencv中提供的函数为cv2.Scharr():

dst=cv2.Scharr(src,ddepth,dx,dy,[,ksize[,scale[,delta[,borderType]]]])

laplace算子

其是对像素点求二阶导,即二阶差分,其对噪声点的锐化更加突出。 opencv提供的函数为cv2.Laplacian(),

dst=cv2.Laplacian(src,ddepth,[,ksize[,scale[,delta[,borderType]]]])

各参数意义与sobel一样,只是其求二阶导,无需指定对dx,与dy方向是否求导。

示例代码:

import cv2 as cv

img = cv.imread("img/grbq.jpg",cv.IMREAD_GRAYSCALE)
cv.imshow("src",img)

# 使用拉普拉斯算子
dst = cv.Laplacian(img,cv.CV_32F)
# 取绝对值,将数据转到uint8类型
dst = cv.convertScaleAbs(dst)

cv.imshow("dst",dst)

cv.waitKey(0)
cv.destroyAllWindows();