图像处理中的 Gaussina Blur 和 SIFT 算法
Gaussina Blur 高斯模糊
高斯模糊的数学定义
高斯模糊是通过 高斯核(Gaussian Kernel) 对图像进行卷积操作实现的. 二维高斯函数定义为
\]
其中:
- \((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\sigma + 1\)sigmaX
和sigmaY
是高斯核在 X 和 Y 方向的标准差, 通常设为相同值
高斯核矩阵
在实际计算中, 高斯核需要离散化为一个二维矩阵. 例如, 当 \(\sigma = 1.0\) 时, 一个 3×3 的高斯核可能如下
\begin{bmatrix}
1 & 2 & 1 \\
2 & 4 & 2 \\
1 & 2 & 1 \\
\end{bmatrix}
\]
手动计算高斯核的示例
import cv2
import numpy as np
# 生成二维高斯核
def gaussian_kernel(size, sigma):
kernel = np.zeros((size, size))
# // 是整数除法运算符, 会将结果向下取整到最接近的整数
center = size // 2
for x in range(size):
for y in range(size):
dx, dy = x - center, y - center
kernel[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) = \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算法
提取关键点
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()
图像处理中的 Gaussina Blur 和 SIFT 算法的更多相关文章
- SIFT算法详解(转)
http://blog.csdn.net/zddblog/article/details/7521424 目录(?)[-] 尺度不变特征变换匹配算法详解 Scale Invariant Feature ...
- 【转】 SIFT算法详解
尺度不变特征变换匹配算法详解Scale Invariant Feature Transform(SIFT)Just For Fun zdd zddmail@gmail.com 对于初学者,从Davi ...
- 《sift算法详解》阅读笔记
原博客来自:http://blog.csdn.net/zddblog/article/details/7521424 定义: 尺度不变特征转化是一种计算机视觉算法,用于侦测和描述物体的局部性特征,在空 ...
- SIFT算法
备注:源代码还未理解,所以未附上——下周任务 一.SIFT算法 1.算法简介 尺度不变特征转换即SIFT (Scale-invariant feature transform)是一种计算机视觉的算法 ...
- SIFT算法详解
尺度不变特征变换匹配算法详解Scale Invariant Feature Transform(SIFT)Just For Fun zdd zddmail@gmail.com or (zddhub@ ...
- 转:sift算法详解
转自:http://blog.csdn.net/pi9nc/article/details/23302075 对于初学者,从David G.Lowe的论文到实现,有许多鸿沟,本文帮你跨越. 1.SIF ...
- SIFT算法详解(转)
原文地址 http://blog.csdn.net/pi9nc/article/details/23302075 尺度不变特征变换匹配算法详解 Scale Invariant Feature Tran ...
- 【图像处理笔记】SIFT算法原理与源码分析
[图像处理笔记]总目录 0 引言 特征提取就是从图像中提取显著并且具有可区分性和可匹配性的点结构.常见的点结构一般为图像内容中的角点.交叉点.闭合区域中心点等具有一定物理结构的点,而提取点结构的一般思 ...
- SIFT算法中DoG特征点的修正
SIFT算法中,在DoG空间找到极值点后,需要对极值点进行修正,本文主要详细的讲解一下为什么需要修正,以及如何对极值点进行修正. 下图演示了二维函数离散空间得到的极值点与连续空间的极值点之间的差别 利 ...
- SIFT算法:特征描述子
SIFT算法:DoG尺度空间生产 SIFT算法:KeyPoint找寻.定位与优化 SIFT算法:确定特征点方向 SIFT算法:特征描述子 目录: 1.确定描述子采样区域 2.生成描述子 2.1 旋 ...
随机推荐
- C#生成目录
在使用C#时,特别是做项目时,有时不会关注生成结果的目录结构的管理.但这样随着动态链接库的增多,文件夹中的文件数量会急剧增加.毕竟许多产品级的软件的清晰的目录是我们追求的目标. 通过以下简单的几步我们 ...
- Luogu P1613 跑路 题解 [ 蓝 ] [ 倍增 ] [ Floyd 最短路 ] [ 状压 dp ]
跑路:绝佳倍增好题,思路是化 \(2^k\) 为 \(1\) ,倍增起预处理作用. 最近不知道是撞了什么运,前一脚看的是绿题,写完之后交一发,发现直接被 lxl 升蓝了,血赚. 思路:Floyd 首先 ...
- RabbitMQ(八)——消息确认
RabbitMQ系列 RabbitMQ(一)--简介 RabbitMQ(二)--模式类型 RabbitMQ(三)--简单模式 RabbitMQ(四)--工作队列模式 RabbitMQ(五)--发布订阅 ...
- Vue实现企业微信扫码登录
Vue实现企业微信扫码登录 企业微信扫码登录原理 构建企业微信登录二维码 获取访问令牌access_token 请求方式:GET(HTTPS)请求URL:https://qyapi.wei ...
- Lombok 只会用@Setter @Getter @Data ? 老鸟带你玩转lombok
lombok的官网 官方网址 : https://projectlombok.org lombok 稳定特性文档:https://projectlombok.org/features/ lombok ...
- Winform ShowDialog如何让先前Show的窗体可以交互
背景描述 最近项目中有一个需求,全局有一个共用的窗体,能够打开不同模块的报告,由于需要兼容不同模块,代码复杂,启动速度慢.优化方案为将窗体启动时就创建好,需要查看报告时,使用此单例弹窗加载不同模块下的 ...
- 奥特曼autMan对接QQ机器人框架go-cqhttp的详细教程
前言 node-onebo用pm2,screen守护都不稳定,node-onebot扫码后ctrl+c,pm2没守护直接掉了,screen只能守护几个小时.因为服务器地区与你常登q的位置不同,时常有密 ...
- Hadoop - 执行start-dfs.sh、stop-dfs.sh 报错处理
执行 sbin/start-dfs.sh 和 sbin/stop-dfs.sh 报错,且进程仍然在 start-dfs.sh和stop-dfs.sh会去hadoop-env.sh中找JDK的值,但是设 ...
- 基于Openframeworks调取摄像头方式的定时抓拍保存图像方法小结
这次是采用Openframeworks来调取摄像头画面并抓图保存. 开始 借向导自动生成代码,因为要调取摄像头设备,因此增添ofVideoGrabber对象声明,又因为保存需求,所以还需添加ofPix ...
- Week09_day05(Hbase的安装搭建)
搭建完全分布式集群 HBase集群建立在hadoop集群基础之上,所以在搭建HBase集群之前需要把Hadoop集群搭建起来,并且要考虑二者的兼容性.现在就以5台机器为例,搭建一个简单的集群. 软件版 ...