当前位置: 首页 > 后端技术 > Python

使用Python开发智能批改系统

时间:2023-03-26 01:39:43 Python

随着现代图像处理和人工智能技术的飞速发展,许多学者尝试将CV应用到教学领域,可以代替教师批改试卷,将教师从繁琐繁琐的作业中解放出来。累人的标记。为进一步有效推动教学质量更上一层楼。传统的人工阅卷繁琐、效率低下,进度难以控制,容易出现漏试卷和登记错误的情况。现代“机器打标”方便、高效、易于操作。只需要一个相机(手机),拍一张照片就可以得到分数。它可以导入到Excel表格中,以便于存档管理。下面从代码实现的角度来解释一下我们这个简易答题卡识别系统的工作原理。第一步导入工具包和一系列预处理importnumpyasnpimportargparseimportimutilsimportcv2#Setparameterap=argparse.ArgumentParser()ap.add_argument("-i","--image",default="test_01.png")args=vars(ap.parse_args())#正确答案ANSWER_KEY={0:1,1:4,2:0,3:3,4:1}#deforder_points(pts):#一共4个坐标点rect=np.zeros((4,2),dtype="float32")#依次找到对应的坐标0、1、2、3,分别是左上、右上、右下、lowerleft#计算左上和右下s=pts.sum(axis=1)rect[0]=pts[np.argmin(s)]rect[2]=pts[np.argmax(s)]#计算upper右下角diff=np.diff(pts,axis=1)rect[1]=pts[np.argmin(diff)]rect[3]=pts[np.argmax(diff)]returnrectdeffour_point_transform(image,pts):#获取输入坐标点rect=order_points(pts)(tl,tr,br,bl)=rect#计算输入的w和h值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))高度A=np.sqrt(((tr[0]-br[0])**2)+((tr[1]-br[1])**2))heightB=np.sqrt(((tl[0]-bl[0])**2)+((tl[1]-bl[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)warped=cv2.warpPerspective(image,M,(maxWidth,maxHeight))returnwarped#返回变换后结果defsort_contours(cnts,method="left-to-right"):reverse=Falsei=0ifmethod==“从右到左”或方法==“从下到上”:reverse=Trueifmethod==“top-to-bottom”或method==“bottom-to-top”:i=1boundingBoxes=[cv2.boundingRect(c)forcincnts](cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),key=lambdab:b[1][i],reverse=reverse))returncnts,boundingBoxesdefcv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyAllWindows()image=cv2.imread(args["image"])contours_img=image.copy()gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)blurred=cv2.GaussianBlur(gray,(5,5),0)edged=cv2.Canny(模糊,75,200)#轮廓检测cnts=cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[1]cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)docCnt=None#如果len(cnts)>0:#Sortaccordingtocontoursizecnts=sorted(cnts,key=cv2.contourArea,reverse=True)forcincnts:#遍历每个轮廓#=cv2.arcLength(c,True)approx=cv2.approxPolyDP(c,0.02*peri,True)#准备透视变换iflen(approx)==4:docCnt=approxbreak#执行透视变换warped=four_point_transform(gray,docCnt.reshape(4,2))thresh=cv2.threshold(warped,0,255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)[1]thresh_Contours=thresh.copy()#找到每个圆的轮廓cnts=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[1]cv2.drawContours(thresh_Contours,cnts,-1,(0,0,255),3)questionCnts=[]forcincnts:#遍历#计算比例和大小(x,y,w,h)=cv2.boundingRect(c)ar=w/float(h)#根据实际情况指定标准如果w>=20andh>=20andar>=0.9andar<=1.1:questionCnts.append(c)#从上到下排序questionCnts=sort_contours(questionCnts,method="top-to-bottom")[0]correct=0#Thereare5optionsineachrowfor(q,i)inenumerate(np.arange(0,len(questionCnts),5)):cnts=sort_contours(questionCnts[i:i+5])[0]bubbled=Nonefor(j,c)inenumerate(cnts):#遍历每一个结果#使用mask判断结果mask=np.zeros(thresh.shape,dtype="uint8")cv2.drawContours(mask,[c],-1,255,-1)#-1表示填充#通过统计非零点的个数来计算是否选择这个答案mask=cv2.bitwise_and(thresh,thresh,mask=mask)total=cv2.countNonZero(mask)#如果bubbled是None或者total,则通过threshold判断>bubbled[0]:bubbled=(total,j)#第二步,与corre比较ctanswercolor=(0,0,255)k=ANSWER_KEY[q]#判断正确ifk==bubbled[1]:color=(0,255,0)correct+=1cv2.drawContours(warped,[cnts[k]],-1,color,3)#drawing#Correctratetextdisplayscore=(correct/5.0)*100print("[INFO]score:{:.2f}%".格式(分数))cv2.putText(扭曲,"{:.2f}%".format(分数),(10,30),cv2.FONT_HERSHEY_SIMPLEX,0.9,(0,0,255),2)cv2.imshow("Input",image)cv2.imshow("Output",warped)cv2.waitKey(0)最终效果如下:本文由博客发布平台OpenWrite发布!