Gaussina Blur 高斯模糊
高斯模糊的數學定義
高斯模糊是通過 高斯核(Gaussian Kernel) 對圖像進行卷積操作實現的. 二維高斯函數定義為
G ( x , y , σ ) = 1 2 π σ 2 e ? x 2 + y 2 2 σ 2 G(x, y, \sigma) = \frac{1}{2\pi \sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}} G(x,y,σ)=2πσ21?e?2σ2x2+y2?
其中:
- ( x , y ) (x, y) (x,y) 是像素點的坐標
- σ \sigma σ 是高斯核的標準差, 控制模糊程度 σ \sigma σ 越大, 圖像越模糊
高斯模糊計算的 Python 實現
以下是使用 OpenCV 計算不同尺度高斯模糊的代碼
import cv2
import numpy as np
import matplotlib.pyplot as plt# 讀取圖像
img = cv2.imread('00001.jpg', cv2.IMREAD_COLOR_RGB)# 定義高斯核的尺度(σ值)
sigma_values = [1.0, 1.6, 2.0, 2.5, 3.0] # 示例σ值# 對每個σ值進行高斯模糊
blurred_images = []
for sigma in sigma_values:# 高斯核大小(通常根據σ自動計算,如 ksize=(0,0))blurred = cv2.GaussianBlur(img, (0, 0), sigmaX=sigma, sigmaY=sigma)blurred_images.append(blurred)# 顯示結果
plt.figure(figsize=(15, 8))
# 原圖
plt.subplot(2, 3, 1)
plt.imshow(img)
plt.title('original')
plt.axis('off')
# 模糊處理過的圖
for i, (sigma, blurred) in enumerate(zip(sigma_values, blurred_images)):plt.subplot(2, 3, i+2)plt.imshow(blurred, cmap='gray')plt.title(f'σ={sigma}')plt.axis('off')
plt.tight_layout()
plt.show()
cv2.GaussianBlur(img, ksize, sigmaX)
ksize=(0,0)
時, OpenCV 會根據 σ \sigma σ 自動計算核大小, 通常為 6 σ + 1 6\sigma + 1 6σ+1sigmaX
和sigmaY
是高斯核在 X 和 Y 方向的標準差, 通常設為相同值
高斯核矩陣
在實際計算中, 高斯核需要離散化為一個二維矩陣. 例如, 當 σ = 1.0 \sigma = 1.0 σ=1.0 時, 一個 3×3 的高斯核可能如下
K = 1 16 [ 1 2 1 2 4 2 1 2 1 ] K = \frac{1}{16} \begin{bmatrix} 1 & 2 & 1 \\ 2 & 4 & 2 \\ 1 & 2 & 1 \\ \end{bmatrix} K=161? ?121?242?121? ?
手動計算高斯核的示例
import cv2
import numpy as np# 生成二維高斯核
def gaussian_kernel(size, sigma):kernel = np.zeros((size, size))# // 是整數除法運算符, 會將結果向下取整到最接近的整數center = size // 2for x in range(size):for y in range(size):dx, dy = x - center, y - centerkernel[x, y] = np.exp(-(dx**2 + dy**2) / (2 * sigma**2))kernel /= kernel.sum() # 歸一化return kernel# 生成 σ=1.5 的 5x5 高斯核
kernel = gaussian_kernel(5, 1.5)
print(kernel)
矩陣中各元素的數值構成了一個三維高斯曲面, 中心點最高, 呈鐘形向四周降低
SIFT(Scale-Invariant Feature Transform)算法
SIFT(Scale-Invariant Feature Transform)算法是一種用于圖像處理中的局部特征提取方法, 具有尺度、旋轉和光照不變性, 因為其結果穩定性和較高的精度在圖像匹配中廣泛應用. SIFT的缺點是計算復雜度較高, 在一些需要實時處理的場景被快速算法如SURF, ORB等替代. 在 COLMAP 中, 提取特征量和匹配基于的就是 SIFT 算法.
1. 尺度空間極值檢測(Scale-Space Extrema Detection)
目的: 在多尺度空間中尋找關鍵點(潛在的特征點)
- 構建高斯金字塔
- 對圖像進行不同尺度的高斯模糊(通過高斯卷積核 $ G(x,y,\sigma) $), 生成多組(Octave)圖像. 每組包含多層(Interval), 尺度按 $ k\sigma $ 遞增(如 $ \sigma, k\sigma, k^2\sigma $).
- 不同尺度的高斯模糊是通過對圖像應用不同標準差 σ \sigma σ 的高斯核進行卷積計算得到的
- 下一組的圖像由上一組降采樣(如尺寸減半)得到.
- 對圖像進行不同尺度的高斯模糊(通過高斯卷積核 $ G(x,y,\sigma) $), 生成多組(Octave)圖像. 每組包含多層(Interval), 尺度按 $ k\sigma $ 遞增(如 $ \sigma, k\sigma, k^2\sigma $).
- 構建高斯差分金字塔(DoG)
- 對同一組內相鄰尺度的高斯圖像相減, 得到 $ D(x,y,\sigma) = L(x,y,k\sigma) - L(x,y,\sigma) $
- DoG用于近似拉普拉斯算子(LoG), 效率更高.
- 檢測極值點
- 每個像素與同一層相鄰的8個像素及上下相鄰層的18個像素(共26個)比較, 判斷是否為局部極大/極小值.
2. 關鍵點定位(Keypoint Localization)
目的: 精確定位關鍵點, 去除低對比度或邊緣響應點
- 泰勒展開精確定位
- 通過泰勒展開擬合DoG函數, 找到極值點的亞像素級位置(偏移量 $ \hat{x} $)
- 若 $ |D(\hat{x})| $ 小于閾值(如0.03), 則視為低對比度點, 剔除
- 邊緣響應剔除
- 利用Hessian矩陣計算曲率, 剔除邊緣響應強的點(主曲率比值大的點)
- 若 $ \frac{\text{Tr}(H)^2}{\text{Det}(H)} > \frac{(r+1)^2}{r} $(通常 $ r=10 $), 則剔除
3. 方向分配(Orientation Assignment)
目的: 將關鍵點方向歸一化處理, 以實現旋轉不變性
- 計算梯度幅值和方向
- 在關鍵點所在高斯尺度圖像上, 計算鄰域窗口內像素的梯度:
m ( x , y ) = ( L ( x + 1 , y ) ? L ( x ? 1 , y ) ) 2 + ( L ( x , y + 1 ) ? L ( x , y ? 1 ) ) 2 m(x,y) = \sqrt{(L(x+1,y)-L(x-1,y))^2 + (L(x,y+1)-L(x,y-1))^2} m(x,y)=(L(x+1,y)?L(x?1,y))2+(L(x,y+1)?L(x,y?1))2?
θ ( x , y ) = tan ? ? 1 ( L ( x , y + 1 ) ? L ( x , y ? 1 ) L ( x + 1 , y ) ? L ( x ? 1 , y ) ) \theta(x,y) = \tan^{-1}\left( \frac{L(x,y+1)-L(x,y-1)}{L(x+1,y)-L(x-1,y)} \right) θ(x,y)=tan?1(L(x+1,y)?L(x?1,y)L(x,y+1)?L(x,y?1)?)
- 在關鍵點所在高斯尺度圖像上, 計算鄰域窗口內像素的梯度:
- 生成方向直方圖
- 將360°分為36柱(每柱10°), 加權統計梯度幅值(權重為高斯窗口和梯度幅值).
- 取主峰(最高峰值)和80%以上主峰的次峰作為關鍵點方向.
4. 關鍵點描述符(Descriptor Generation)
目的: 在方向歸一化處理后, 通過劃分子塊生成關鍵點的特征向量
- 旋轉坐標軸: 將鄰域窗口旋轉至關鍵點主方向.
- 劃分子區域: 將16×16的窗口分為4×4的子塊(共16塊).
- 計算子塊梯度直方圖:
- 每個子塊內計算8方向的梯度直方圖(共8維).
- 16個子塊 × 8方向 = 128維特征向量.
- 歸一化處理:
- 對特征向量歸一化, 減少光照影響, 并截斷大于0.2的值以增強魯棒性.
5. 關鍵點匹配
- 通過歐氏距離(如最近鄰算法)比較兩幅圖像的SIFT描述符
- 使用最近鄰距離比(NNDR, 如 $ \frac{d_1}{d_2} < 0.8 $)篩選匹配點, 提升匹配精度.
在Python代碼中通過OpenCV使用SIFT算法
提取關鍵點
import cv2
import matplotlib.pyplot as plt# 讀取圖像(轉為灰度圖)
img = cv2.imread('00001.jpg', cv2.IMREAD_GRAYSCALE)# 初始化 SIFT 檢測器
sift = cv2.SIFT_create()# 檢測關鍵點并計算描述符
keypoints, descriptors = sift.detectAndCompute(img, None)# 繪制關鍵點
img_with_keypoints = cv2.drawKeypoints(img, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
)# 顯示結果
plt.figure(figsize=(10, 6))
plt.imshow(img_with_keypoints, cmap='gray')
plt.title('SIFT Keypoints')
plt.axis('off')
plt.show()
雙圖關鍵點匹配
import cv2
import matplotlib.pyplot as plt# 讀取兩張圖像
img1 = cv2.imread('00001.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('00006.jpg', cv2.IMREAD_GRAYSCALE)# 初始化 SIFT
sift = cv2.SIFT_create()# 計算關鍵點和描述符
kp1, desc1 = sift.detectAndCompute(img1, None)
kp2, desc2 = sift.detectAndCompute(img2, None)# 使用 BFMatcher(Brute-Force 匹配器)
bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
matches = bf.match(desc1, desc2)# 按距離排序,取最優匹配
matches = sorted(matches, key=lambda x: x.distance)# 繪制前 50 個匹配點
matched_img = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS
)# 顯示匹配結果
plt.figure(figsize=(15, 8))
plt.imshow(matched_img, cmap='gray')
plt.title('SIFT Feature Matching')
plt.axis('off')
plt.show()