答题卡识别

© Fu Xianjun. All Rights Reserved.

1、导包

import cv2

import numpy as np

def cv_show(name,img):

    cv2.imshow(name,img)

    cv2.waitKey(0)

    cv2.destroyAllWindows()

2、轮廓检测

ANSWER_KEY = {0:1,1:4,2:0,3:3,4:1}
image = cv2.imread("test_01.png")
contours_img = image.copy()
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
gs = cv2.GaussianBlur(gray,(5,5),0)
edge = cv2.Canny(gs,75,200)
cnts = cv2.findContours(edge,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(contours_img,cnts,-1,(255,255,0),2)

3、轮廓排序,透视变换

def order_points(pts):
    rect = np.zeros((4,2),dtype="float32")
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    d = np.diff(pts,axis=1)
    rect[1] = pts[np.argmin(d)]
    rect[3] = pts[np.argmax(d)]
    return rect
def four_point_transform(image,pts):
    rect = order_points(pts)
    (tl,tr,br,bl) = rect
    widthA = np.sqrt((br[0]-bl[0])**2+(br[1]-bl[1])**2)
    widthB = np.sqrt((tr[0]-tl[0])**2+(tr[1]-tl[1])**2)
    maxWidth = max(int(widthA),int(widthB))
    heightA = np.sqrt((br[0]-tr[0])**2+(br[1]-tr[1])**2)
    heightB = np.sqrt((bl[0]-tl[0])**2+(bl[1]-tl[1])**2)
    maxHeight = max(int(heightA),int(heightB))
    dst = np.array([[0,0],[maxWidth-1,0],[maxWidth-1,maxHeight-1],\
                   [0,maxHeight-1]],dtype="float32")
    M = cv2.getPerspectiveTransform(rect,dst)
    warp = cv2.warpPerspective(image,M,(maxWidth,maxHeight))
    return warp
docCnt = None
if len(cnts)>0:
    cnts = sorted(cnts,key = cv2.contourArea,reverse = True)
    for c in cnts:
        peri = cv2.arcLength(c,True)
        approx = cv2.approxPolyDP(c,0.02*peri,True)
        if len(approx)==4:
            docCnt=approx
            print(docCnt)
            break
warp = four_point_transform(gray,docCnt.reshape(4,2))

4、寻找圆圈轮廓

def sort_contours(cnts,method="left-to-right"):
    reverse = False
    i = 0
    if method == "right-to-left" or method=="bottom-to-top":
        reverse = True
    if method == "top-to-bottom" or method=="bottom-to-top":
        i = 1
    boundingBoxes = [cv2.boundingRect(c)for c in cnts]
    (cnts,boundingBoxes) = zip(*sorted(zip(cnts,boundingBoxes),
                                      key = lambda b:b[1][i],reverse = reverse))
    return cnts,boundingBoxes
thresh = cv2.threshold(warp,0,255,cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)[1]
thresh_contours = thresh.copy()
cnts = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(thresh_contours,cnts,-1,(255,255,0),2)
question_Cnts=[]

5、输出每个轮廓,对比答案

for c in cnts:
    (x,y,w,h) = cv2.boundingRect(c)
    ar = w/float(h)
    if w>=20 and h>=20 and ar>=0.9 and ar<1.1:
        question_Cnts.append(c)
question_Cnts = sort_contours(question_Cnts,method = "top-to-bottom")[0]
correct = 0
for (q,i) in enumerate(np.arange(0,len(question_Cnts),5)):
    cnts = sort_contours(question_Cnts[i:i+5])[0]
    bubbled = None
    for (j,c) in enumerate(cnts):
        mask = np.zeros(thresh.shape,dtype="uint8")
        cv2.drawContours(mask,[c],-1,255,-1)    
        mask = cv2.bitwise_and(thresh,thresh,mask = mask)
        total = cv2.countNonZero(mask)        
        if bubbled is None or total>bubbled[0]:
            bubbled = (total,j)
        color = (0,0,255)
        k = ANSWER_KEY[q]
        if k==bubbled[1]:
            color = (0,255,0)
            total+=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值