指纹验证案例中,指纹1与模板图片匹配成功了,分别在两图内标出匹配成功点的坐标
要求:匹配结果最近的distance小于次接近distance的0.4
提示:cv2.circle(src, (x,y), 3, (0, 0, 255), -1),绘制实心圆
分块详解
第1块:导入和辅助函数
import cv2
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
- 作用 :导入 OpenCV 库,定义显示图像的函数
cv_show,它创建一个窗口显示图像,并等待按键后关闭窗口(waitKey(0)表示无限等待)。
第2块:读取并显示原始图像
src1 = cv2.imread('1.bmp')
model = cv2.imread('3.bmp')
cv_show('src1', src1)
cv_show('model', model)
-
作用 :从文件读取两张待匹配的图像(
src1为待匹配图,model为模板图),并显示它们以确认读取成功。 -

第3块:SIFT 特征提取
sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(src1, None)
kp2, des2 = sift.detectAndCompute(model, None)
-
作用 :创建 SIFT 对象,检测每张图像的关键点(
kp)并计算对应的描述子(des)。描述子是 128 维向量,用于后续匹配。SIFT就像一个"细节提取机",它会自动在大图和小图里找出最突出的角角落落、纹理变化大的点 (比如扇子的尖角、图案的边缘)。这些点叫"关键点"(kp),而des就是每个点的"身份证号码"(一串数字)。 -
重要函数 :
cv2.SIFT_create()和detectAndCompute(image, mask):-
cv2.SIFT_create():返回 SIFT 对象,可选参数有nfeatures(特征点数量)、nOctaveLayers等。 -
detectAndCompute(image, mask):image是输入图像(灰度或彩色),mask是可选掩膜,指定感兴趣区域。返回值是(keypoints, descriptors),keypoints是KeyPoint对象列表,descriptors是形状为(N, 128)的 numpy 数组。
-
第4块:FLANN 匹配器创建与 kNN 匹配
flann = cv2.FlannBasedMatcher()
matches = flann.knnMatch(des1, des2, k=2)
-
作用 :基于 FLANN(快速最近邻搜索库)创建匹配器,对
des1中的每个描述子在des2中找出最近的 2 个 匹配(k=2),返回matches,它是一个列表,每个元素是包含 2 个DMatch对象的元组。其实就是找两个最像的描述子 -
重要函数 :
cv2.FlannBasedMatcher([index_params[, search_params]]):-
若不传参,使用默认参数,但对于 SIFT 描述子(浮点型),建议指定索引参数为
KDTree,例如:index_params = dict(algorithm=1, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
-
knnMatch(queryDescriptors, trainDescriptors, k):query为第一幅图的描述子,train为第二幅图的描述子,k为返回的最近邻个数。返回值matches是List[List[DMatch]]。
-
第5块:Lowe's 比率测试筛选优质匹配
good = \[\]
alist = \[\]
for m, n in matches:
if m.distance < 0.4 * n.distance:
alist.append((m.queryIdx, m.trainIdx))
good.append((m, n))
-
作用 :对每个
(m, n)对,m是最近邻,n是次近邻。如果m.distance远小于n.distance(阈值 0.4),则认为m是可靠的匹配。这里0.4设置得越小,留下的匹配点越少,但越精准。筛选后:-
alist存储匹配点对在各自关键点列表中的索引,用于后续绘制圆点。 -
good存储原始匹配对(m, n),但注意这里good的元素是元组,用于后续drawMatchesKnn时会出错(应为列表的列表)。
-
-
重要:Lowe 比率测试是 SIFT 匹配中的经典筛选方法,阈值通常取 0.7~0.8。
第6块:在两张原图上绘制筛选出的关键点(红色圆点)
for i, j in alist:
x, y = kp1i.pt
m, n = kp2j.pt
cv2.circle(src1, (int(x), int(y)), 3, (0, 0, 255), -1)
cv2.circle(model, (int(m), int(n)), 3, (0, 0, 255), -1)
cv_show('Marked src1', src1)
cv_show('Marked model', model)
-
作用 :遍历筛选出的匹配索引,提取关键点坐标,用红色实心圆标记在图像上。注意此处直接修改了
src1和model原图。 -
alist:只记了匹配上的点的"编号",.pt: 选取对应点的坐标

第7块:绘制匹配连线(显示匹配关系)
matched_image = cv2.drawMatchesKnn(
src1, kp1, model, kp2, good, None,
flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
)
cv_show('matched', matched_image)
-
作用 :生成一张拼接图像,左边是
src1,右边是model,并在两者之间用线条连接匹配点对。 -
重要函数 :
cv2.drawMatchesKnn(img1, keypoints1, img2, keypoints2, matches1to2, outImg, ...):-
参数:
-
img1:第一张图像。 -
keypoints1:第一张图像的关键点。 -
img2:第二张图像。 -
keypoints2:第二张图像的关键点。 -
matches1to2:必须是一个列表的列表 ,每个子列表包含一个或多个DMatch对象(通常用于 kNN 的 k>1 情形)。若只绘制单一匹配,应传入[[m1], [m2], ...]的形式。 -
outImg:输出图像,可传入None让函数自动创建。 -
flags:绘制标志,常用有:-
cv2.DRAW_MATCHES_FLAGS_DEFAULT(默认) -
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS(绘制关键点圆和方向) -
cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS(不绘制未匹配到的点)
-
-
-
返回值:绘制后的彩色图像。
-

重要代码单独总结
| 代码片段 | 作用 | 关键参数说明 |
|---|---|---|
sift = cv2.SIFT_create() |
创建 SIFT 对象 | 可选参数:nfeatures(保留特征点数量)、contrastThreshold(对比度阈值)等。 |
sift.detectAndCompute(img, mask) |
检测关键点并计算描述子 | img:输入图像,mask:感兴趣区域掩膜;返回 kp(KeyPoint 列表)和 des(N×128 数组)。 |
cv2.FlannBasedMatcher(index_params, search_params) |
创建 FLANN 匹配器 | index_params:索引参数,SIFT 常用 dict(algorithm=1, trees=5);search_params:搜索参数,常用 dict(checks=50)。 |
flann.knnMatch(des1, des2, k=2) |
k 近邻匹配 | des1 和 des2 为描述子矩阵,k=2 返回两个最近邻。返回 List[List[DMatch]]。 |
cv2.drawMatchesKnn(...) |
绘制匹配连线 | 关键参数已在上文详述,注意 matches 必须是列表的列表。 |