找回密码
 立即注册
首页 业界区 业界 图像处理中的 Gaussina Blur 和 SIFT 算法

图像处理中的 Gaussina Blur 和 SIFT 算法

乐敬 2025-6-2 22:51:57
Gaussina Blur 高斯模糊

高斯模糊的数学定义

高斯模糊是通过 高斯核(Gaussian Kernel) 对图像进行卷积操作实现的. 二维高斯函数定义为

\[G(x, y, \sigma) = \frac{1}{2\pi \sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}}\]
其中:

  • \((x, y)\) 是像素点的坐标
  • \(\sigma\) 是高斯核的标准差, 控制模糊程度\(\sigma\) 越大, 图像越模糊
计算高斯核的 Python 实现

在实际计算中, 高斯核需要离散化为一个二维矩阵. 例如, 当 \(\sigma = 1.0\) 时, 一个 3×3 的高斯核结构如下

\[K = \frac{1}{16}\begin{bmatrix}1 & 2 & 1 \\2 & 4 & 2 \\1 & 2 & 1 \\\end{bmatrix}\]
矩阵中各元素的数值构成了一个三维高斯曲面, 中心点最高, 呈钟形向四周降低
计算离散化高斯核的 Python 代码
  1. import cv2
  2. import numpy as np
  3. # 生成二维高斯核
  4. def gaussian_kernel(size, sigma):
  5.     kernel = np.zeros((size, size))
  6.     # "//" 是整数除法运算符, 会将结果向下取整到最接近的整数
  7.     center = size // 2
  8.     for x in range(size):
  9.         for y in range(size):
  10.             dx, dy = x - center, y - center
  11.             kernel[x, y] = np.exp(-(dx**2 + dy**2) / (2 * sigma**2))
  12.     kernel /= kernel.sum()  # 归一化
  13.     return kernel
  14. # 生成 σ=1.5 的 5x5 高斯核
  15. kernel = gaussian_kernel(5, 1.5)
  16. print(kernel)
复制代码
使用  OpenCV 处理高斯模糊

在实际使用中, 可以直接用 OpenCV 的 GaussianBlur() 函数. 以下是使用 OpenCV 计算不同尺度高斯模糊的代码
  1. import cv2
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. # 读取图像
  5. img = cv2.imread('00001.jpg', cv2.IMREAD_COLOR_RGB)
  6. # 定义高斯核的尺度(σ值)
  7. sigma_values = [1.0, 1.6, 2.0, 2.5, 3.0]  # 示例σ值
  8. # 对每个σ值进行高斯模糊
  9. blurred_images = []
  10. for sigma in sigma_values:
  11.     # 高斯核大小(通常根据σ自动计算,如 ksize=(0,0))
  12.     blurred = cv2.GaussianBlur(img, (0, 0), sigmaX=sigma, sigmaY=sigma)
  13.     blurred_images.append(blurred)
  14. # 显示结果
  15. plt.figure(figsize=(15, 8))
  16. # 原图
  17. plt.subplot(2, 3, 1)
  18. plt.imshow(img)
  19. plt.title('original')
  20. plt.axis('off')
  21. # 模糊处理过的图
  22. for i, (sigma, blurred) in enumerate(zip(sigma_values, blurred_images)):
  23.     plt.subplot(2, 3, i+2)
  24.     plt.imshow(blurred, cmap='gray')
  25.     plt.title(f'σ={sigma}')
  26.     plt.axis('off')
  27. plt.tight_layout()
  28. plt.show()
复制代码

  • cv2.GaussianBlur(img, ksize, sigmaX)

    • ksize=(0,0) 时, OpenCV 会根据 \(\sigma\) 自动计算核大小, 通常为 \(6\sigma + 1\)
    • sigmaX 和 sigmaY 是高斯核在 X 和 Y 方向的标准差, 通常设为相同值

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\) 的高斯核进行卷积计算得到的

    • 下一组的图像由上一组降采样(如尺寸减半)得到.

  • 构建高斯差分金字塔(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) = \sqrt{(L(x+1,y)-L(x-1,y))^2 + (L(x,y+1)-L(x,y-1))^2}\]

      \[\theta(x,y) = \tan^{-1}\left( \frac{L(x,y+1)-L(x,y-1)}{L(x+1,y)-L(x-1,y)} \right)\]

  • 生成方向直方图

    • 将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算法

提取关键点
  1. import cv2
  2. import matplotlib.pyplot as plt
  3. # 读取图像(转为灰度图)
  4. img = cv2.imread('00001.jpg', cv2.IMREAD_GRAYSCALE)
  5. # 初始化 SIFT 检测器
  6. sift = cv2.SIFT_create()
  7. # 检测关键点并计算描述符
  8. keypoints, descriptors = sift.detectAndCompute(img, None)
  9. # 绘制关键点
  10. img_with_keypoints = cv2.drawKeypoints(
  11.     img,
  12.     keypoints,
  13.     None,
  14.     flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
  15. )
  16. # 显示结果
  17. plt.figure(figsize=(10, 6))
  18. plt.imshow(img_with_keypoints, cmap='gray')
  19. plt.title('SIFT Keypoints')
  20. plt.axis('off')
  21. plt.show()
复制代码
双图关键点匹配
  1. import cv2
  2. import matplotlib.pyplot as plt
  3. # 读取两张图像
  4. img1 = cv2.imread('00001.jpg', cv2.IMREAD_GRAYSCALE)
  5. img2 = cv2.imread('00006.jpg', cv2.IMREAD_GRAYSCALE)
  6. # 初始化 SIFT
  7. sift = cv2.SIFT_create()
  8. # 计算关键点和描述符
  9. kp1, desc1 = sift.detectAndCompute(img1, None)
  10. kp2, desc2 = sift.detectAndCompute(img2, None)
  11. # 使用 BFMatcher(Brute-Force 匹配器)
  12. bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
  13. matches = bf.match(desc1, desc2)
  14. # 按距离排序,取最优匹配
  15. matches = sorted(matches, key=lambda x: x.distance)
  16. # 绘制前 50 个匹配点
  17. matched_img = cv2.drawMatches(
  18.     img1, kp1,
  19.     img2, kp2,
  20.     matches[:10],
  21.     None,
  22.     flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS
  23. )
  24. # 显示匹配结果
  25. plt.figure(figsize=(15, 8))
  26. plt.imshow(matched_img, cmap='gray')
  27. plt.title('SIFT Feature Matching')
  28. plt.axis('off')
  29. plt.show()
复制代码
相关链接


  • SIFT算法说明合集 SIFT Algorithm | Computer Vision

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册