2026年8月26日
OpenCV 图像拼接、答题卡识别、扇子掩模提取 知识点总结
核心技术:SIFT 特征匹配、RANSAC 单应矩阵、图像拼接;轮廓检测 + 四点透视变换答题卡矫正;Canny 边缘、轮廓筛选、mask 掩码、按位与 ROI 提取
一、核心知识点梳理
1. SIFT 特征点检测与描述子
cv2.SIFT_create() :SIFT 特征提取器,检测关键点 + 生成特征描述符,对旋转、缩放具备鲁棒性。
sift.detectAndCompute(gray, None)
输入灰度图,返回kps关键点对象,des描述子数组。
kp.pt: 关键点浮点坐标(x,y)。
一般输入灰度图像,减少计算量。
2 .特征匹配器
BFMatcher 暴力匹配 :逐个描述子距离计算,小数据集效果好;
FlannBasedMatcher 快速近似匹配 :大数据特征点,速度更快。
matcher.knnMatch(des1,des2,k=2) :k 近邻匹配,每个特征返回前 k 个匹配。
Lowe 比率测试 :m0.distance < ratio * m1.distance,过滤错误匹配,ratio 常用 0.4‑0.8。distance 为描述符欧式距离,数值越小相似度越高。
**cv2.drawMatchesKnn():**绘制匹配连线,可设置标记关键点样式。
3 .单应矩阵 & RANSAC & 图像拼接
cv2.findHomography(srcPoints,dstPoints,method,threshold)
求解单应矩阵 H(3×3 透视变换矩阵),支持多组点对。
cv2.RANSAC随机抽样一致性算法: 剔除外点(错误匹配点),返回H变换矩阵与mask内外点掩码。
ransacReprojThreshold: 重投影误差阈值,超过该值判定为外点。
cv2.warpPerspective(src, H, dsize): 执行透视变换,将图像按照矩阵 H 投影到新画布。
图像拼接逻辑:B 图透视变换到 A 图坐标系,画布扩大,再把 A 图拷贝到画布左侧,完成拼接。
至少需要 4 组有效匹配点才能求解单应矩阵。
4. 轮廓相关全套 API(答题卡 + 扇子提取共用)
cv2.Canny(blur, t1, t2): Canny 边缘检测,双阈值,输出二值边缘图。
cv2.findContours()轮廓查找
cv2.RETR_EXTERNAL: 只找最外层轮廓;
cv2.CHAIN_APPROX_SIMPLE: 压缩轮廓点,减少点数量。
cv2.contourArea(cnt): 计算轮廓面积;max(contours,key=cv2.contourArea)获取面积最大轮廓。
cv2.arcLength(cnt,closed=True): 轮廓周长。
cv2.approxPolyDP(cnt,epsilon,closed) 轮廓多边形近似;答题卡中用来找 4 角答题卡轮廓。
cv2.drawContours()
thickness=-1: 填充轮廓内部,用于生成 mask 掩模。
cv2.boundingRect(cnt):轮廓外接矩形,返回x,y,w,h;可以计算长宽比ar=w/h筛选圆形答题框。
5. 四点透视变换(答题卡矫正)
order_points(): 对 4 个角点重排序:左上、右上、右下、左下。
cv2.getPerspectiveTransform(src_pts,dst_pts): 输入 4 对对应点,得到透视变换矩阵 M。
cv2.warpPerspective(img,M,(w,h))做透视变换,把倾斜答题卡矫正成俯视正视图。
6. 掩码 mask 与按位运算(答题卡、扇子提取)
np.zeros_like(img) 创建和原图同尺寸全黑掩码。
cv2.bitwise_and(img,img,mask=mask): 按位与操作,只保留 mask 白色区域图像,黑色区域置 0 黑色,实现 ROI 目标区域提取。
**cv2.countNonZero(binary_img)**统计二值图中非 0 像素个数;答题卡中用来判断圆圈是否被涂黑。
7 .图像基础操作
cv2.resize(img,(w,h)) 缩放图像;注意参数顺序:(宽,高)。
cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) 逆时针旋转 90°。
cv2.GaussianBlur(img,(ksize,ksize),sigma) 高斯模糊,降噪,前置处理,提升边缘检测效果。
cv2.threshold() 二值化
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU :Otsu 自动阈值 + 反向二值化,适合答题卡。
cv2.imwrite() 保存图片。
**cv2.imshow()+cv2.waitKey(0)**图像显示。
8 .轮廓排序
根据外接矩形坐标,对轮廓从上到下、从左到右排序,答题卡用来按行读取答题选项。
二、代表性关键代码片段
片段 1:SIFT 特征匹配 + RANSAC 求单应矩阵(图像拼接)
# 1. SIFT提取特征
sift = cv2.SIFT_create()
kpsA, desA = sift.detectAndCompute(grayA, None)
kpsB, desB = sift.detectAndCompute(grayB, None)
# 2.BF匹配+Lowe筛选
matcher = cv2.BFMatcher()
rawMatches = matcher.knnMatch(desB, desA, k=2)
good = []
for m in rawMatches:
if len(m)==2 and m[0].distance < 0.65*m[1].distance:
good.append(m)
# 3.RANSAC求解单应矩阵
if len(good)>4:
ptsB = np.float32([kps_floatB[m[0].queryIdx] for m in good])
ptsA = np.float32([kps_floatA[m[0].trainIdx] for m in good])
H, mask = cv2.findHomography(ptsB, ptsA, cv2.RANSAC,10)
# 透视变换
result = cv2.warpPerspective(imageB, H, (imageA.shape[1]+imageB.shape[1],imageA.shape[0]))
result[0:imageA.shape[0],0:imageA.shape[1]] = imageA
片段 2:四点透视变换核心(答题卡矫正)
def order_points(pts):
rect = np.zeros((4,2),dtype=np.float32)
s = pts.sum(axis=1)
rect[0]=pts[np.argmin(s)]
rect[2]=pts[np.argmax(s)]
diff = np.diff(pts,axis=1)
rect[1]=pts[np.argmin(diff)]
rect[3]=pts[np.argmax(diff)]
return rect
# 获取变换矩阵
rect = order_points(docCnt.reshape(4,2))
dst = np.array([[0,0],[w-1,0],[w-1,h-1],[0,h-1]],np.float32)
M = cv2.getPerspectiveTransform(rect,dst)
warped = cv2.warpPerspective(image,M,(w,h))
片段 3:mask 掩码 + bitwise_and 提取目标区域(扇子案例)
# Canny边缘检测
blur = cv2.GaussianBlur(gray,(5,5),0)
edge = cv2.Canny(blur,50,150)
# 找最大轮廓
contours,_ = cv2.findContours(edge,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
max_cnt = max(contours,key=cv2.contourArea)
# 创建掩码,填充轮廓内部为白色
mask = np.zeros_like(gray)
cv2.drawContours(mask,[max_cnt],-1,255,-1)
# 按位与提取目标
roi_img = cv2.bitwise_and(img_rot,img_rot,mask=mask)
cv2.imwrite("shanzi.png",roi_img)
片段 4:答题卡判断填涂(mask+countNonZero)
mask = np.zeros(thresh.shape,np.uint8)
cv2.drawContours(mask,[c],-1,255,-1)
masked_img = cv2.bitwise_and(thresh,thresh,mask=mask)
total = cv2.countNonZero(masked_img) #统计涂黑像素
三、整体流程对比
图像拼接流程
读取两张图 → SIFT提取关键点描述子 → knn匹配+Lowe筛选 → RANSAC计算单应矩阵H → warpPerspective透视变换 → 画布合并完成拼接
答题卡识别流程
读取图片 →高斯模糊→Canny边缘→轮廓检测→多边形近似找到答题卡四角→四点透视矫正→灰度+Otsu二值化→筛选圆形答题框轮廓→轮廓从上到下排序→mask掩码统计非零像素判断填涂→对比标准答案计算分数
扇子目标提取流程
读取fan.jpg → resize(640,480) →逆时针旋转90° →灰度+高斯模糊 →Canny边缘检测 →查找外轮廓,取面积最大扇子轮廓 →生成填充mask掩码 →bitwise_and按位与提取扇子ROI →保存shanzi.png