特征匹配效果优异但单应变换结果不佳的优化方案咨询
扫描图像与低质量数字模板的高精度对齐问题
需求
我需要将扫描得到的2D图像进行旋转、平移,使其与一张近乎相同但质量更低的数字模板精准对齐,这样后续就能基于模板的布局知识对扫描图做后期处理。
当前尝试与问题
我试过多种基于特征匹配的方法(基于findContour的方法效果很差),最终选定用OpenCV的单应匹配方案:通过SIFT提取特征点,FLANN做匹配,再用findHomography计算变换矩阵,最后用warpPerspective应用变换。
目前匹配点的数量很可观:即使把距离阈值设得非常严格(比如0.2),仍能得到数十个匹配点;阈值调到0.8左右时,匹配点超过2400个。但不管怎么调整距离阈值和findHomography的RANSAC参数,最终得到的变换效果还是达不到要求——虽然比初始状态好,但没法满足基于模板布局修改扫描图的精度需求。
所用代码
from matplotlib import pyplot as plt import numpy as np import cv2 as cv def feature_match(scanned_image, template_image, MIN_MATCH_COUNT=10, dist_thresh=0.2, RANSAC=10.0): # 初始化SIFT检测器 sift = cv.SIFT_create() # 用SIFT提取关键点和描述子 kp1, des1 = sift.detectAndCompute(scanned_image, None) kp2, des2 = sift.detectAndCompute(template_image, None) FLANN_INDEX_KDTREE = 1 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) flann = cv.FlannBasedMatcher(index_params, search_params) matches = flann.knnMatch(des1, des2, k=2) # 保存通过Lowe比率测试的匹配点 good = [] for m, n in matches: if m.distance < dist_thresh * n.distance: good.append(m) if len(good) > MIN_MATCH_COUNT: print(f"{len(good)} good matches using distance threshold of {dist_thresh}") src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, RANSAC) matchesMask = mask.ravel().tolist() # 应用单应矩阵做透视变换 warped_image = cv.warpPerspective(scanned_image, M, (scanned_image.shape[1], scanned_image.shape[0])) plt.imshow(warped_image, 'gray'), plt.show() else: print(f"Not enough matches are found - {len(good)}/{MIN_MATCH_COUNT}") matchesMask = None # 可视化匹配质量 draw_params = dict(matchColor=(0, 255, 0), # 匹配点用绿色绘制 singlePointColor=None, matchesMask=matchesMask, # 只绘制内点 flags=2) match_quality = cv.drawMatches(scanned_image, kp1, template_image, kp2, good, None, **draw_params) plt.imshow(match_quality, 'gray'), plt.show() cv.imwrite(r"img1.png", cv.cvtColor(img1, cv.COLOR_GRAY2RGB)) cv.imwrite(r"img2.png", cv.cvtColor(img2, cv.COLOR_GRAY2RGB)) cv.imwrite(r"warped_image.png", cv.cvtColor(warped_image, cv.COLOR_GRAY2RGB)) # 加载图像 img1_path = r"scanned_image.png" img2_path = r"template_image.png" img1 = cv.imread(img1_path) img1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY) img2 = cv.imread(img2_path) img2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY) # 将模板图放大到目标尺寸,省去后续缩放步骤 img2 = cv.resize(img2, (img2.shape[1] * 2, img2.shape[0] * 2), cv.IMREAD_UNCHANGED) feature_match(scanned_image=img1, template_image=img2, MIN_MATCH_COUNT=10, dist_thresh=0.2)
相关图像
扫描图像

模板图像

注:模板图像质量低、初始分辨率更低,和扫描图存在细微差异,但我认为这些差异不足以影响匹配效果。
匹配点(距离阈值0.2时)

- 距离阈值设为0.2时,得到100个匹配点;阈值设为0.8左右时,匹配点超过2400个
变换后的扫描图像

变换后扫描图与模板图叠加效果

疑问
考虑到匹配点的数量,我原本预期会有更好的对齐效果。现在想请教:
- 是否应该更换其他对齐方法?
- 有没有我没充分调整的参数可以优化效果?
- 是不是受模板质量或当前方法的限制,这已经是能达到的最佳效果了?
内容的提问来源于stack exchange,提问作者ConcernedAboutOwls
相关产品推荐
相关产品推荐

