小白从零开始勇闯人工智能:计算机视觉初级篇(OpenCV进阶操作(下))

引言

在本篇文章里,我们将要学习Harris角点检测的原理与应用,理解SIFT特征提取与描述的方法,并探索如何利用这些特征实现多幅图像的精准拼接。掌握这些技术,我们就能够赋予程序"识别"和"组装"图像的能力,为后续的目标跟等高级应用奠定基础。

一、特征检测之Harris角点检测

1、什么是角点?

角点是图像中一种重要的局部特征点,它指的是在两个或多个方向上灰度(或颜色)发生显著变化的像素位置。角点通常位于物体的边缘拐角处,是图像中"结构"信息最丰富的地方。由于其同时具有边缘变化剧烈和位置易于精确定位的特性,角点对图像的旋转、缩放都能保持相对稳定。在计算机视觉中,角点是图像匹配和目标跟踪的基础,因为它们是特征描述符(如SIFT、ORB)进行提取和匹配的关键位置。

2、Harris角点检测原理

Harris角点检测的原理是:通过量化图像局部窗口在各个方向移动时引起的灰度变化强度,来识别角点这一关键特征。首先,计算图像在x和y方向的梯度,接着基于这些梯度构造二阶矩矩阵,用以描述该点的局部灰度变化结构,随后,通常对该矩阵应用高斯加权以增强稳健性,计算每个像素的角点响应函数R值,最后,通过设定阈值筛选R值,并配合非极大值抑制来定位最终的角点。

3、Harris角点响应函数

Harris角点检测的角点响应函数 R 是一个关键的计算指标,其定义为:R = det(M) - k · (trace(M))²。 Harris角点检测的角点响应函数 R 是一个关键的计算指标,其定义为:R = det(M) - k · (trace(M))²。

其中,M 是之前步骤中计算得到的自相关矩阵,它综合了局部窗口内像素梯度的分布信息。矩阵的行列式 det(M) 近似代表了该点的两个主方向上的变化强度的乘积,而矩阵的迹 trace(M) 则近似代表了这两个方向上的变化强度之和。经验常数 k 通常取值在0.04到0.06之间,用于调节对边缘的敏感度。通过计算出的 R 值可以有效地对像素点进行分类:

1、R 值为较大的正数时,表示该点在任何方向上移动都会引起较大的灰度变化,即被判定为角点。

2、R 值为绝对值较大的负数时,表示该点仅在某个单一方向上变化显著,对应图像边缘。

3、R 值绝对值很小时,则对应灰度均匀的平坦区域。

4、OpenCV示例

复制代码
import cv2
import numpy as np
img = cv2.imread('R-C.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
dst = cv2.cornerHarris(gray,4,3,0.04)
# 标记检测到的角点
img[dst > 0.01 * dst.max()] = [0, 0, 255]
# 这里通过对角点响应进行阈值处理,标记出检测到的角点。
# 0.05 * dst.max() 是一个阈值,大于这个值的像素点会被标记为红色。
cv2.imshow('img',img)
cv2.waitKey(0)

二、特征检测之SIFT特征检测

1、为什么需要SIFT?

SIFT算法是为了解决Harris角点检测方法对图像尺度变化敏感的问题。SIFT的优势在于其实现了尺度不变性,它通过构造高斯差分金字塔来检测不同尺度下的稳定关键点,并为之生成独特的描述子,从而使得特征匹配能够在图像缩放、旋转等多种变换下保持鲁棒性,极大地提升了在复杂场景中特征识别的可靠性与实用性。

2、SIFT算法的特点与流程

首先,算法利用高斯差分金字塔进行尺度空间极值检测以发现潜在关键点。随后,通过关键点定位步骤精确定位其位置并剔除低对比度或边缘响应点。接着,方向分配步骤为每个关键点计算主方向,赋予其旋转不变性。最后,算法在关键点邻域内生成具有高区分度的128维特征描述向量。

3、OpenCV示例

复制代码
import cv2
import numpy as np
# 检测图像中的关键点
cv2.SIFT_create() #cv2.xfeatures2d.SIFT_create()#创建一个sift特征的提取对象
# sift.detect(img)在图像中查找关键点

img = cv2.imread('R-C.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#
sift = cv2.SIFT_create()  #sift对象
kp = sift.detect(img_gray)
# kp.pt:关键点的(x, y)
# 坐标。
# kp.size:关键点的大小(尺度)。
# kp.angle:关键点的方向。
# kp.response:关键点的响应值。
# kp.octave:关键点所在的金字塔层级。
#查找关键点
# drawKeypoints(image, keypoints, outImage, color=None, flags=None)
# image:原始图片
# keypoints:从原图中获得的关键点,这也是画图时所用到的数据
# outputimage:输出图像,可以是原始图片,也可以是None
# color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色。
# flags:绘图功能的标识设置                                       绘制富有信息的关键点。
img_sift = cv2.drawKeypoints(img,kp,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('img_sift',img_sift)


# 使用sift.compute()计算关键点描述符,方便后期的特征匹配
kp,des = sift.compute(img,kp)  #
print(np.array(kp).shape,des.shape)
cv2.waitKey(0)
# 输出关键点的形状和描述符的形状。
# np.array(kp).shape 表示关键点的数量和属性。
# des.shape 表示描述符的数量和属性。

三、图像拼接

1、图像拼接流程

图像拼接是将两幅图像合并为一张无缝全景图,其标准流程首先利用SIFT算法分别在两幅图像中检测出稳定的特征点。随后,通过特征匹配步骤建立这些点之间的对应关系。基于匹配点对,算法计算单应性矩阵以精确估计图像间的几何变换关系。接着,依据此变换将其中一幅图像投影到另一幅图像的坐标系中,实现几何对齐。最后,通过图像融合技术处理重叠区域,消除亮度差异和拼接痕迹,从而生成视觉连贯、自然平滑的最终拼接结果。

2、特征匹配策略

在特征匹配阶段,为了确保匹配的准确性,SIFT算法采用了基于最近邻距离比的稳健策略。对于待匹配的关键点A,首先在其目标图像中寻找欧氏距离最近的两个关键点X和Y,其距离分别记为d1和d2(且d1<d2)。随后计算比值d1/d2。若该比值较大(例如接近或超过0.8),则表明A与X的区分度不足,很可能由噪声或重复纹理引起,应该要拒绝,反之,若比值足够小(如低于0.7),则证明A与X的描述向量具有显著的独特性,从而判定为一次可靠的正确匹配。

3、图像拼接实现

复制代码
import cv2
import numpy as np
import sys

def cv_show(name, img):
    cv2.imshow(name, img)

def detectAndDescribe(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 将彩色图片转换成灰度图
    sift = cv2.SIFT_create()  # 建立SIFT生成器
    # 检测SIFT特征点,并计算描述符,第二个参数为掩膜
    (kps, des) = sift.detectAndCompute(gray, None)
    # 将结果转换成NumPy数组
    kps_float = np.float32([kpc.pt for kpc in kps])
    # kpc 包含两个值,分别是关键点在图像中的 x 和 y 坐标。这些坐标通常是浮点数,可以精确地描述关键点在图像中的位置。
    return (kps, kps_float, des)  # 返回特征点集,及对应的描述特征

'''读取拼接图片'''
imageA = cv2.imread("1.jpg")
cv_show('imageA', imageA)
imageB = cv2.imread("2.jpg")
cv_show('imageB', imageB)

'''计算图片特征点及描述符'''
(kpsA, kps_floatA, desA) = detectAndDescribe(imageA)
(kpsB, kps_floatB, desB) = detectAndDescribe(imageB)

'''建立匹配器BFMatcher,在匹配大图训练集合时使用FlannBasedMatcher速度更快。'''
matcher = cv2.BFMatcher()

rawMatches = matcher.knnMatch(desB, desA, k=2)
good = []
matches = []

for m in rawMatches:
    # 当最近距离跟次近距离的比值小于0.65时,保留此匹配对
    if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:
        good.append(m)
        # 存储两个点在featuresA、featuresB中的索引值
        matches.append((m[0].queryIdx, m[0].trainIdx))

print(len(good))
print(matches)

vis = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good, outImg=None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show("Keypoint Matches", vis)

'''透视变换'''
if len(matches) > 4:  # 当筛选后的匹配对大于4时,计算视角变换矩阵。
    # 获取匹配对的点坐标
    ptsB = np.float32([kps_floatB[i] for (i, _) in matches])  # matches是通过阈值筛选之后的特征点对象,
    ptsA = np.float32([kps_floatA[i] for (_, i) in matches])  # kps_floatA是图片A中的全部特征点坐标

    # 计算透视变换矩阵
    # findHomography(srcPoints, dstPoints, method=None, ransacReprojThreshold=None, mask=None, maxIters=None, confidence=None)
    # 计算视角变换矩阵,透视变换函数,与cv2.getPerspectiveTransform()的区别在与可多个数据点变换
    # 参数srcPoints:图片A的匹配点坐标
    # 参数dstPoints:图片B的匹配点坐标
    # 参数method:计算变换矩阵的方法。
    # 0 - 使用所有的点,最小二乘
    # RANSAC - 基于随机样本一致性,见 https://zhuanlan.zhihu.com/p/402727549
    # LMEDS - 最小中值
    # RHO - 基于渐近样本一致性
    # ransacReprojThreshold: 最大允许重投影错误阈值。该参数只有在method参数为RANSAC与RHO的时启用,默认为3
    # 返回值:中值为变换矩阵,mask是掩模标志,指示哪些点对应内点,哪些是外点。内点:指那些与估计的模型非常接近的数据点,通常是正确匹配或真实数据。外点:指那些与估计的模型非常接近的数据点,通常是正确匹配或真实数据。
    H, mask = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, 5.0)
else:
    print('图片未找到4个以上的匹配点')
    sys.exit()

result = cv2.warpPerspective(imageB, H, (imageB.shape[1] + imageA.shape[1], imageB.shape[0]))
cv_show('resultB', result)
# 将图片A传入resultB后显示
result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA
cv_show('result', result)
cv2.waitKey(0)

cv2.imwrite('pingjie.jpg', result)
相关推荐
NAGNIP11 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab13 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab13 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP16 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年16 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼17 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS17 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区18 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈18 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang18 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx