基于关键点匹配的图片对齐

在工业检测中,一个目标可能被不同相机拍摄,其输出的图往往是不对齐,这就给缺陷定位带来问题,本文基于关键点匹配去实现平移状态下的图片对齐

假设现在有同一物体,不同摄像头拍摄的两张图片,可以看出两张图片并没有对齐

基于关键点匹配的图片对齐-20250201153031

首先我们将图片转为灰度图,减少颜色的干扰,然后使用 2D 特征算子 SIFT 查找两张图片的关键点,然后使用 BFMatcher 匹配两张图片找到的关键点,并过滤出比较相近的匹配点,得到以下结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
gray1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

# Initiate SIFT detector
sift = cv2.xfeatures2d.SIFT_create()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(gray1, None)
kp2, des2 = sift.detectAndCompute(gray2, None)

# BFMatcher with default params
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)

# Apply ratio test
# 比值测试,首先获取与 A距离最近的点 B (最近)和 C (次近),
# 只有当 B/C 小于阀值时(0.75)才被认为是匹配,
# 因为假设匹配是一一对应的,真正的匹配的理想距离为0
good = []
for m, n in matches:
if m.distance < 0.5 * n.distance:
good.append([m])

# cv2.drawMatchesKnn expects list of lists as matches.
gray = np.ndarray([2, 2])
gray = cv2.drawMatchesKnn(gray1, kp1, gray2, kp2, good[:10], gray, flags=2)
plt.imshow(gray), plt.show()

基于关键点匹配的图片对齐-20250201153031-1

可以看出选择的 10 个匹配点,基本是平行,说明其中一张图可以通过另一张图平移得到。于是我们收集评分最高的 3 个匹配点,计算两张图的仿射变换矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pts1=[]
pts2=[]
idxs = list(range(len(good)))
np.random.shuffle(idxs)

# for idx in range(len(matches)):
for idx in idxs[:3]: # 收集3个点计算仿射变换矩阵
trainIdx=good[idx][0].trainIdx
queryIdx=good[idx][0].queryIdx

train_keypoint=kp1[queryIdx]
query_keypoint=kp2[trainIdx]

pts1.append(list(train_keypoint.pt))
pts2.append(list(query_keypoint.pt))

通过仿射变换矩阵处理其中一张图片,得到以下结果,第 1、3 张图片是应用仿射矩阵前后的图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rows, cols, ch = img1.shape
pts1 = np.float32(pts1)
pts2 = np.float32(pts2)

M = cv2.getAffineTransform(pts1, pts2)
print(M)
if M[0][1]>0.5 or M[1][0]>0.5:
print('仿射矩阵出现旋转')
else:
M[0][1]=0
M[1][0]=0
dst = cv2.warpAffine(img1, M, (cols, rows))

show_images([img1,img2[...,::-1],dst])

基于关键点匹配的图片对齐-20250201153032

将关键点匹配再次应用到上图的 2、3 图上,看看图片对齐程度,得到以下结果,可以发现图片得到对齐

基于关键点匹配的图片对齐-20250201153032-1