OpenCV-Python-圖像梯度


圖像梯度

我們知道一階導數可以用來求極值。把圖片想象成連續函數,因為邊緣部分的像素值與旁邊的像素明顯有區別,所以對圖片局部求極值,就可以得到整幅圖片的邊緣信息。不過圖片是二維的離散函數,導數就變成了差分,這個查分就變成了圖像梯度。

 

1. 垂直邊緣提取

濾波是應用卷積來實現的,卷積的關鍵就是卷積核。我們來考察下面這個卷積核:

這個核是用來提取圖片中的垂直邊緣的,怎么做到的呢?看下圖:

當前列左右兩側的元素進行差分,由於邊緣的值明顯小於(或大於)周邊像素,所以邊緣的差分結果會明顯不同,這樣就提取出垂直邊緣。同理,把上面的那個矩陣轉置一下,就是提取水平邊緣。這種差分操作就成為圖像的梯度計算:

import cv2
import numpy as np

img = cv2.imread('sudoku.jpg', 0)

# 自己進行垂直邊緣提取
kernel = np.array([[-1, 0, 1],
         [-2, 0, 2],
         [-1, 0, 1]], dtype=np.float32)

dst_v = cv2.filter2D(img, -1, kernel)

# 自己進行水平邊緣提取
dst_h = cv2.filter2D(img, -1, kernel.T)

# 橫向並排對比顯示
cv2.imshow('edge', np.hstack((img, dst_v, dst_h)))
cv2.waitKey(0)

 

2. Sobel算子

上面這種差分方法就叫Sobel算子,它先在垂直方向上計算梯度 Gx = k1 x src,再在水平方向計算梯度Gy = k2 x src,最后求出總梯度:

我們可以把前面的代碼用Sobel算子更簡單的實現:

sobelx = cv2.Sobel(img, -1, 1, 0, ksize=3) # 只計算x方向
sobely = cv2.Sobel(img, -1, 0, 1, ksize=3) # 只計算y方向
# 橫向並排對比顯示
cv2.imshow('edge', np.hstack((img, sobelx, sobely)))
cv2.waitKey(0)

還有其他算子,比如只利用領域間的原始差值來檢測邊緣的Prewitt算子

還有比Sobel更好用的Scharr算子

這些算法都是一階邊緣檢測的代表。

 

3. Laplacian算子

高數中用一階導數求極值,在這些極值的地方,二階導數為0,所以也可以求二階導計算梯度:

一維的一階和二階差分公式分別為:

提取前面的系數,那么一維的Laplacian的濾波核是:

 對於二維函數f(x,y),兩個方向的二階差分分別是:

 合在一起:

 

同樣提取前面的系數,那么二維的Laplacian濾波核就是:

 

這就是 Laplacian 算子的圖像卷積模板,有些資料在此基礎上考慮斜對角情況,將卷積核擴展為:

laplacian = cv2.Laplacian(img, -1)
# 橫向並排對比顯示
cv2.imshow('edge', np.hstack((img, laplacian)))
cv2.waitKey(0)

Laplacian算子是二階邊緣檢測的典型代表。

參考地址:http://ex2tron.wang/opencv-python-extra-image-gradients/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM