计算机视觉(图像拼接问题总结1)

前言

因为计算机视觉课的这条"主线"结束了,所以我写下这篇文章来总结一下这条重要主线的相关知识.我计划将这个总结分为5篇文章,刚好对应了5步.

正文

首先我们总体的说一下这条主线的几个重要步骤,他们分别是:"

第一步:特征点检测;

第二步:描述子构建打上描述子;

第三步:匹配两张图的特征点;

第四步:求解线性变换方程组;

第五步:图像的插值"

接下来我将对每一步都进行知识点的详细描述,前有认真,敬请期待!

1.特征点检测

我们想要选取一个图像中的特征点,那么这个特征点该有什么样的性质呢?显而易见的,特征点需要具有以下几个重要的性质:

1. 独特性(Distinctiveness):特征点应该在图像中是独一无二的,即不同的图像区域应该具有不同的特征点。这样可以确保在特征匹配的过程中能够准确地找到对应的特征点。

2. 不变性(Invariant):特征点应该对图像的旋转、尺度变化、光照变化等具有一定的不变性。这意味着即使在不同的图像条件下,同一个场景中的特征点应该能够保持相似的描述子,以便进行准确的匹配。

3. 定位精度(Localization):特征点应该能够准确地定位在图像中的位置。这是由于特征点的位置信息是后续处理任务的重要输入,因此需要具备较高的定位精度。

4. 鲁棒性(Robustness):特征点应该对于图像中的噪声、遮挡、模糊等情况具有一定的鲁棒性。这意味着特征点检测算法应该能够在复杂的图像条件下仍然能够提取到准确的特征点。

5. 重复性(Repeatability):特征点应该在不同的图像中能够重复出现。这是为了保证在不同的图像中能够找到相同的特征点,以便进行跨图像的匹配和对齐。

那么我们该用什么算法来选取特征点呢,这里我们会先讲一种方法,那就是哈里斯角点:

哈里斯角点
理论

哈里斯角点简称角点,它其实不完全满足上面列出来的几种性质,,但是让我们先忘记这件事情().总之我们先认为有这么一种角点,它具备了稳定,稀疏,特殊的性质,可以作为图像的特征点,那么,让我们回到最核心的问题,该怎么判断呢?我对于这里的理解就是想象一个小窗口,假如这个小窗口向任何方向移动很小的距离都能引起其中的像素值发生很大的变化,那这个小窗口就是所谓的角点.那么我们该如何从数学的角度来描述这一事件呢?

一个点是否为角点有一套量化的评判规则,评判指标为:使得该点领域窗口(窗口的大小是依经验选取的)在图像上移动至新位置后,新窗口的像素值和原窗口的像素值 差值为 1,此时的窗口位移量为 deltaX 与 deltaY,deltaX 与 deltaY 值越相近,且越小, 则该点越适合作为 Harris 角点。事实上 deltaX 和 deltaY 的值相互制约,其值形成一个 椭圆,我们希望这个椭圆是一个较小的正圆,而经过推导,该椭圆的长短轴大小仅依赖 于该点在图像中位置附近的像素信息,且该位置附近像素信息可以被抽象成( 邻域窗口 二阶导矩阵 ):
这段话似乎有点不好理解,在我的理解里就是说:"在Harris角点检测中,通过计算二阶导矩阵的特征值和行列式,可以得到一个椭圆的形状。如果这个椭圆的长短轴接近,且较小,说明该点附近的像素分布在两个方向上都有较大的梯度变化,从而被认为是角点。这样的椭圆通常被认为是近似于一个正圆,表示该点是一个稳定的角点。而该点附近的像素信息可以被抽象成邻域窗口的二阶导数矩阵,也就是上面图里的矩阵"
正因如此,我们可以从M中提取出这个表达式来表示该点的椭圆接近于小面积正圆的程度:
这里的K值依然是经验值,而我们在使用这个表达式的时候就是要判断r(x)的值是否大于了我们设定的阈值,如果大于了,那这个x点就是角点(恭喜!!!)
那么数学原理说完了,我们该如何使用代码来实现这个角点检测呢?接下啦我们来说一下代码的部分:
代码

先用文字讲一下代码的部分吧,代码的话分为四步,第一步就是先对所有像素点求一阶偏导,第二步是求二阶偏导,第三步是做一次高斯模糊对每一个像素点的领域窗口的所有像素点的二姐偏导数求和,实际上就是想要得到M矩阵,第四步就是使用上面那个r(x)公式求出来每个像素点的值,判断一下是不是角点,简单的代码示例如下:

import cv2
import numpy as np

# Step 1: 计算一阶偏导
def compute_gradients(image):
    dx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)  # 在x方向上计算一阶导数
    dy = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)  # 在y方向上计算一阶导数
    return dx, dy

# Step 2: 计算二阶偏导
def compute_second_derivatives(dx, dy):
    Ixx = dx**2  # x方向上的二阶导数
    Ixy = dx * dy  # x和y方向上的混合导数
    Iyy = dy**2  # y方向上的二阶导数
    return Ixx, Ixy, Iyy

# Step 3: 计算M矩阵(通过高斯模糊)
def compute_m_matrix(Ixx, Ixy, Iyy, ksize):
    Ixx_blur = cv2.GaussianBlur(Ixx, (ksize, ksize), 0)  # 对Ixx进行高斯模糊
    Ixy_blur = cv2.GaussianBlur(Ixy, (ksize, ksize), 0)  # 对Ixy进行高斯模糊
    Iyy_blur = cv2.GaussianBlur(Iyy, (ksize, ksize), 0)  # 对Iyy进行高斯模糊
    return Ixx_blur, Ixy_blur, Iyy_blur

# Step 4: 计算角点响应函数值
def compute_harris_response(Ixx_blur, Ixy_blur, Iyy_blur, k=0.04):
    det_M = Ixx_blur * Iyy_blur - Ixy_blur**2  # M矩阵的行列式
    trace_M = Ixx_blur + Iyy_blur  # M矩阵的迹
    r = det_M - k * trace_M**2  # Harris角点响应函数
    return r

# 阈值化,得到角点
def detect_corners(image, threshold):
    dx, dy = compute_gradients(image)
    Ixx, Ixy, Iyy = compute_second_derivatives(dx, dy)
    ksize = 5  # 高斯模糊的核大小
    Ixx_blur, Ixy_blur, Iyy_blur = compute_m_matrix(Ixx, Ixy, Iyy, ksize)
    r = compute_harris_response(Ixx_blur, Ixy_blur, Iyy_blur)
    corners = np.where(r > threshold)  # 大于阈值的点被认为是角点
    return corners

# 读取图像
image = cv2.imread('image.jpg', 0)  # 读取灰度图像
threshold = 100000  # 阈值,用于筛选角点
corners = detect_corners(image, threshold)

# 在图像上绘制角点
for corner in zip(*corners):
    x, y = corner
    cv2.circle(image, (y, x), 5, 255, -1)  # 在角点位置画圆

# 显示结果
cv2.imshow('Corners', image)  # 显示包含角点的图像
cv2.waitKey(0)
cv2.destroyAllWindows()

对了,这里补一下对于高斯模糊的解释吧:

高斯模糊(Gaussian blur)是一种常用的图像处理技术,用于减少图像中的噪声和细节,使图像变得更加平滑。它的基本思想是对图像中的每个像素点,按照其周围像素的权重进行加权平均,其中权重由一个高斯函数确定。

高斯函数是一种钟形曲线,具有以下特性:

1. **中心最大:** 曲线的中心具有最大值,即像素点自身的权重最高。
2. **对称性:** 曲线在中心点对称,保证了平滑性。
3. **渐进性:** 曲线两侧的数值逐渐减小,因此离中心点较远的像素的权重较低。

在高斯模糊中,对图像中的每个像素点,将其周围的像素值按照高斯函数的权重进行加权平均,得到新的像素值。这样可以使图像中的噪声和细节被平滑掉,从而得到一个更加模糊的图像。

在图像处理中,高斯模糊通常用于预处理,以减少图像的噪声,或者在某些特定任务中,比如边缘检测前的图像平滑。高斯模糊的程度(即模糊的程度)由一个参数σ(sigma)来控制,σ值越大,模糊程度越高。

在实际的图像处理库中(例如OpenCV),可以使用内置的函数来进行高斯模糊操作,这些函数会自动计算权重并进行加权平均,无需手动实现高斯函数。

SIFT特征点
理论

由于我们上面见到的哈里斯角点实际上有着各种各样的问题,例如不满足对于整体光照变化以外的光照不变形,还有不满足对于旋转平移变换外的几何变换不变形.所以我们选择了满足尺度不变形和旋转不变性的描述子,那就是SIFT特征点提取算法.

SIFT(Scale-Invariant Feature Transform)是一种用于图像处理和计算机视觉中的特征提取算法,具有尺度不变性(Scale Invariance)和旋转不变性(Rotation Invariance),这意味着它能够在不同尺度和旋转角度下稳定地检测和描述图像中的特征点。以下是SIFT特征点提取的内在原理的详细介绍:

1. 尺度空间极值点检测(Scale Space Extrema Detection)

SIFT首先通过构建尺度空间(Scale Space)来检测图像中的极值点,这些极值点在不同尺度下稳定存在。为了实现尺度不变性,SIFT使用高斯滤波器在不同尺度下对图像进行平滑处理。在每个尺度下,通过对图像使用不同尺度的高斯核函数进行卷积,得到一系列图像(高斯金字塔),然后在每个尺度的图像上寻找局部极值点,这些极值点可能是关键点。

2. 关键点定位(Key Point Localization)

在尺度空间极值点的基础上,SIFT对检测到的极值点进行精确定位,以亚像素级别的精度确定关键点的位置。SIFT使用尺度空间的近邻像素进行拟合,找到关键点的亚像素位置,这样可以提高关键点的精度。

3. 方向赋值(Assigning Orientations to Key Points)

为了保持旋转不变性,SIFT对每个关键点分配一个主方向。SIFT在关键点周围的图像区域计算梯度幅值和方向,然后构建梯度直方图,选择直方图中最大的峰值作为关键点的主方向。这样可以确保在不同角度下,同一个场景的特征点具有相同的描述。

总的来说,SIFT通过构建尺度空间、关键点定位、方向赋值和关键点描述这些步骤,提取图像中具有尺度不变性和旋转不变性的特征点。这些特征点可以用于很多计算机视觉任务,如物体识别、图像拼接等。

这里老师讲的不是特别详细.....

代码
import cv2

# 读取图像
image = cv2.imread('image.jpg')
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 创建SIFT对象
sift = cv2.SIFT_create()

# 检测关键点
keypoints, descriptors = sift.detectAndCompute(gray_image, None)

# 在图像上绘制关键点
output_image = cv2.drawKeypoints(gray_image, keypoints, image)

# 显示结果
cv2.imshow('SIFT Keypoints', output_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

没错我直接调用这个函数了,哈哈哈

第一部分结语

总之特征点检测部分是到此结束了!!

猜你喜欢

转载自blog.csdn.net/m0_73872315/article/details/134170597