@Fu Xianjun. All Rights Reserved.
前言
批改答题卡对于许多来说简直就是折磨,眼睛都看花了还要继续批改,还要保持正确率,实在是太费老师了,所以我们使用OPENCV来解决这个问题,自动批改答题卡
提示:以下是本篇文章正文内容,下面案例可供参考
一、为什么使用OPENCV?
不要问,问就是因为我只学了这个,好,下面开始了
二、使用步骤
1.引入库
代码如下(示例):
import cv2
import numpy as np
2.写入基本函数,这样打包好就可以套用了,多少方便不知道
代码如下(示例):
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
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(img,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(img,M,(maxWidth,maxHeight))
return warp
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
3.导入图片利用上面的函数来进行处理,没错就是这么简单
img = cv2.imread("test_01.png")
contours_img= img.copy()
gray = cv2.cvtColor(img,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)
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
break
warp = four_point_transform(gray,docCnt.reshape(4,2))
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=[]
ANSWER_KEY = {0:1,1:4,2:0,3:3,4:1}
for c in cnts:
(x,h,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)
correct +=1
cv2.drawContours(warp,[cnts[k]],-1,color,3)
score = (correct/5.0)*100
cv_show("warp",warp)
下面是原图和效果图对比,简单明了
总结
非常的实用有没有,虽然有一点点的复杂,但这个是值得的