提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
在数字化时代,图像处理技术的应用日益广泛,其中表盘校正作为一项重要技术,在工业自动化、智能监控、时间同步等领域发挥着至关重要的作用。传统的表盘校正方法往往依赖于人工操作,不仅效率低下,而且精度难以保证。随着计算机视觉技术的飞速发展,基于算法的自动表盘校正技术逐渐成为研究热点。
本文将为您介绍一种基于BEBLID(Binary Efficient Boosted Local Identity Features)特征点匹配技术的表盘校正方法。BEBLID作为一种高效的特征描述符,以其独特的优势在众多特征点匹配算法中脱颖而出。本文将从原理、实现步骤以及实际应用等方面,详细阐述如何利用特征点匹配实现表盘的自动校正。
一、特征点匹配介绍
特征点匹配是计算机视觉中的一项核心技术,它能够帮助计算机识别和理解图像中的关键特征,进而实现图像间的对齐、拼接、物体识别等功能。特征点匹配的实现步骤主要包括以下几个方面:
-
特征点检测:首先,在图像中检测出具有显著特征的点。这些特征点可以是角点、边缘点或其他具有独特性质的点。常用的特征点检测算法有SIFT、SURF、ORB等。
-
特征描述符计算:对每个检测到的特征点,计算一个描述符,这个描述符是对特征点周围图像区域的一个定量描述。描述符应具有对图像变换(如缩放、旋转、光照变化等)的不变性。常见的描述符算法有SIFT描述符、SURF描述符、ORB描述符等。
-
特征点匹配:使用特征描述符,通过匹配算法在两幅图像之间找到对应的特征点对。匹配算法通常基于描述符之间的距离,距离越小,匹配度越高。常用的匹配算法有暴力匹配、FLANN等。
-
匹配筛选:由于匹配过程中可能会产生错误的匹配,因此需要筛选出可靠的匹配点。常用的方法包括最近邻距离比测试(NNDR)和RANSAC(随机抽样一致)算法。
-
变换模型估计:利用筛选后的匹配点对,估计一个变换模型(如仿射变换、透视变换等),这个模型描述了两幅图像之间的几何关系。
-
变换应用:将估计的变换模型应用到一幅图像上,以校正图像或实现图像间的对齐。
特征点匹配在计算机视觉领域具有广泛的应用,如图像拼接、三维重建、物体识别等。通过特征点匹配,计算机可以更好地理解图像内容,实现图像的自动处理和分析。
二、特征点检测
特征点检测是计算机视觉中的一个关键步骤,它涉及到在图像中识别出具有独特性质的点,这些点在图像的后续处理中起着至关重要的作用。特征点通常具有以下特点:
- 角点:这些点是图像中物体的边缘的交叉点,它们在图像中具有显著的梯度变化
- 边缘点:这些点位于物体的边缘上,它们的梯度值在某个方向上有一个显著的峰值。
- 中心点:这些点位于物体的中心,它们的梯度值在各个方向上都比较均匀。
- 局部极值点:这些点在局部区域内具有最高的梯度值。
常见的特征点检测的算法有常用的特征点检测算法有SIFT(尺度不变特征变换)、SURF(加速稳健特征)、ORB(Oriented FAST and Rotated BRIEF)等。本次使用的是ORB特征点检测法,
ORB(Oriented FAST and Rotated BRIEF)是一种特征点检测和描述符计算的算法,它是由David G. Lowe和Bruno Lepeletier在2011年提出的。ORB算法结合了FAST(Features from Accelerated Segment Test)和BRIEF(Binary Robust Independent Elementary Features)算法,旨在提供一种快速且稳健的特征检测和描述方法。ORB算法首先使用FAST角点检测器在图像中检测角点。FAST角点检测器通过检测图像中局部区域的边缘变化来确定角点。对于每个检测到的角点,ORB算法计算其方向,并将该方向信息存储在关键点描述中。ORB算法的主要优点是它的高计算效率和稳健性。由于它使用了二进制描述符,因此计算速度非常快。同时,由于BRIEF描述符对光照变化、旋转和尺度变化具有一定的不变性,ORB算法在实际应用中表现出了较好的稳健性。
在opencv中提供了其api为cv2.ORB_create(nfeatures=None, scaleFactor=1.2, nlevels=8, edgeThreshold=31, firstLevel=0, WTA_K=2, scoreType=cv2.ORB_FAST_SCORE, patchSize=31)
,函数介绍:
nfeatures:可选参数,用于指定要检测的最大特征点数量。如果设置为 None,则检测所有检测到的特征点。
scaleFactor:图像金字塔的缩放因子,用于在不同尺度下检测特征点。
nlevels:图像金字塔的层数。
edgeThreshold:用于FAST角点检测的边缘阈值。
firstLevel:图像金字塔的起始层数。
WTA_K:在描述符计算过程中,用于选择K个最佳描述符的参数。
scoreType:描述符的评分类型。
patchSize:用于描述符计算的局部区域大小。
本次只使用orb计算特征点,不计算描述符,故只设置nfeatures特征,并调用类中detect方法检测特征点,使用如下:
detector = cv2.ORB_create(10000)
kpts1 = detector.detect(img1, None)
三、特征描述符计算
描述符是图像特征点的量化表示,它通过对特征点周围图像区域的特征进行编码,从而能够在不依赖于原始图像数据的情况下识别和匹配特征点。描述符的主要目的是提供一种紧凑且信息丰富的表示,以便在图像匹配和识别任务中使用。
描述符的特点包括:
- 紧凑性:描述符通常是一个固定长度的向量,即使对于高分辨率的图像,其大小也非常小。
- 信息丰富:描述符应该能够提供足够的局部图像信息,以便在不同的图像和不同的视角下识别相同的特征点。
- 不变性:描述符应该对图像的某些变换(如缩放、旋转、光照变化等)保持不变,以便在不同的图像条件下仍然能够准确匹配。
本次使用的描述符为BEBLID描述符,BEBLID描述符基于二进制编码,通过对特征点周围的小区域进行采样,并比较该区域的像素值,来生成一个二进制特征向量。与传统的浮点数描述符相比,BEBLID描述符的计算速度更快,因为它只需要比较像素值是否大于某个阈值,而不是计算像素值的差异。
BEBLID描述符的计算过程包括以下几个步骤:
- 选择特征点周围的局部区域:首先,选择特征点周围的一个小区域作为描述符的计算区域。
- 对局部区域内的像素进行采样:在这个区域内,对像素值进行采样,以生成描述符的样本。
- 对采样到的像素值进行比较:比较相邻像素值的大小,如果一个像素值大于另一个像素值,则标记为1,否则标记为0。
- 生成二进制特征向量:将比较结果组合起来,形成一个二进制特征向量。
- 对特征点进行旋转,重复上述步骤:为了提高描述符的稳健性,可以对特征点进行旋转,并重复上述步骤,以获得多个方向上的描述符。
- 组合描述符:将这些描述符组合起来,形成最终的BEBLID描述符。 优点
BEBLID描述符的主要优点包括:
- 高效计算:由于其二进制编码,BEBLID描述符的计算速度非常快,非常适合实时应用。
- 不变性:BEBLID描述符对图像的某些变换(如缩放、旋转、光照变化等)具有较好的不变性,这使得它能够在不同的图像条件下进行有效的匹配。
BEBLID描述符在opencv的api为:descriptor = cv2.xfeatures2d.BEBLID_create(weight=None)
weight:可选参数,用于指定权重因子。权重因子用于在计算描述符时对图像梯度方向直方图进行加权。如果设置为 None,则使用默认权重。
使用:
descriptor = cv2.xfeatures2d.BEBLID_create(0.75)
kpts1, desc1 = descriptor.compute(img1, kpts1)
四,描述符的匹配筛选
在获得描述符之后,需要对描述符进行匹配和筛选,本次使用的方法为knn匹配,并对匹配后的结果的欧氏距离进行筛选,使用代码:
matcher = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE_HAMMING)
nn_matches = matcher.knnMatch(desc1, desc2, 2)
matched1 = []
matched2 = []
nn_match_ratio = 2 # Nearest neighbor matching ratio
good_matches = []
for m, n in nn_matches:
if m.distance < 0.9 * n.distance:
good_matches.append(m)
cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE_HAMMING) 是用于创建一个描述符匹配器的函数。这个匹配器是基于Hamming距离的暴力匹配器(Brute-Force Matcher),它用于在两组描述符之间找到匹配对。其中cv2.DescriptorMatcher_BRUTEFORCE_HAMMING:这是一个枚举值,用于指定匹配器使用Hamming距离来计算描述符之间的相似度。Hamming距离是衡量两个等长字符串差异的指标,对于二进制描述符来说,它计算的是两个描述符中不同位的数量。cv2.DescriptorMatcher_create 函数返回一个描述符匹配器对象,这个对象可以用于在两组描述符之间执行匹配操作。通过这个对象,可以调用其方法来执行匹配,如knnMatch、bruteForceMatch等,本次选择的匹配方法为knnmatch。
五,根据匹配结果映射图片
在获取到特征点之后,使用特征点匹配来估计两幅图像之间的仿射变换矩阵,并应用该变换矩阵到输入图像上,以实现图像的校正。
首先提取匹配的特征点对:
dst_pts = np.float32([kpts1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
src_pts = np.float32([kpts2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
这两行代码从两组匹配的特征点中分别提取出匹配的特征点对。good_matches 是一个包含匹配对的列表,每个匹配对是一个DMatch对象,包含源图像(img1)中的特征点索引(m.queryIdx)和目标图像(img2)中的特征点索引(m.trainIdx)。
然后使用cv2.estimateAffine2D函数估计两幅图像之间的仿射变换矩阵M。src_pts和dst_pts分别是源图像和目标图像中匹配的特征点对。method=cv2.RANSAC参数表示使用RANSAC(随机抽样一致)算法来估计变换矩阵,这是一种鲁棒的方法,可以处理噪声数据。mask是一个布尔数组,表示哪些匹配点对被用于估计变换矩阵。
M, mask = cv2.estimateAffine2D(src_pts, dst_pts, method=cv2.RANSAC)
最后将仿射变换矩阵应用于图像上:
img2_aligned = cv2.warpAffine(img2, M, (width, height))
六,整体代码:
from __future__ import print_function
import cv2
import numpy as np
import argparse
parser = argparse.ArgumentParser(description='Code for feature matching and transforming image 2 to image 1.')
parser.add_argument('--input1', help='Path to input image 1.', default=r'F:\cv_traditional\1.png')
parser.add_argument('--input2', help='Path to input image 2.', default=r'F:\cv_traditional\2.png')
args = parser.parse_args()
img1 = cv2.imread(args.input1)
img2 = cv2.imread(args.input2)
if img1 is None or img2 is None:
print('Could not open or find the images!')
exit(0)
detector = cv2.ORB_create(10000)
descriptor = cv2.xfeatures2d.BEBLID_create(0.75)
kpts1 = detector.detect(img1, None)
kpts2 = detector.detect(img2, None)
kpts1, desc1 = descriptor.compute(img1, kpts1)
kpts2, desc2 = descriptor.compute(img2, kpts2)
matcher = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE_HAMMING)
nn_matches = matcher.knnMatch(desc1, desc2, 2)
matched1 = []
matched2 = []
nn_match_ratio = 2 # Nearest neighbor matching ratio
good_matches = []
for m, n in nn_matches:
if m.distance < 0.9 * n.distance:
good_matches.append(m)
# 提取匹配点对的坐标
dst_pts = np.float32([kpts1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
src_pts = np.float32([kpts2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
# 估计仿射变换矩阵
M, mask = cv2.estimateAffine2D(src_pts, dst_pts, method=cv2.RANSAC)
# 应用仿射变换到img2上
height, width = img1.shape[:2]
img2_aligned = cv2.warpAffine(img2, M, (width, height))
# 将变换后的img2与img1进行叠加(此处简单叠加,可根据需要调整)
result = cv2.addWeighted(img1, 0.5, img2_aligned, 0.5, 0)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
# 显示结果
cv2.imshow('Aligned Image', img2_aligned)
cv2.waitKey(0)
cv2.destroyAllWindows()
七,效果:
目标图像:
输入图像:
校正图像: