智能图像处理:Python和OpenCV实现-课件 13.3答题卡检测与分割_第1页
智能图像处理:Python和OpenCV实现-课件 13.3答题卡检测与分割_第2页
智能图像处理:Python和OpenCV实现-课件 13.3答题卡检测与分割_第3页
智能图像处理:Python和OpenCV实现-课件 13.3答题卡检测与分割_第4页
智能图像处理:Python和OpenCV实现-课件 13.3答题卡检测与分割_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

答题卡的检测与分割13.3基于OpenCV实现0

10

30

20

4答题卡轮廓检测答题卡不同区域的提取识别填涂答案答题卡用户界面的设计与封装1、运用智能图像处理第9、第12章图像特征的提取与描述中关于图像轮廓提取知识,定位具有答题卡轮廓特征的目标。2、根据答题卡上半部分与下半部分中轮廓大小确定答题卡不同答题区域。3、根据已经存储在内存中的各个选项的印刷位置(不同答题区域),定位各道题的各个选项在图像上的坐标位置。4、选取一定区域的像素(通常比允许答题者涂的范围小一些),计算每个区域内所有像素的灰度值的总和,与某个门限值进行比对,高于它就认为答题者涂上某个选项。答题卡分割与检测主要流程检测轮廓轮廓提取轮廓排序答案筛选答案判别01答题卡轮廓检测01答题卡轮廓检测使用第9章9.6节cv2.Canny函数做边缘检测,寻找答题卡区域边缘。cv2.Canny算子使用第12章中12.2.1节的轮廓函数cv2.findContours从Canny算子提供的边缘图中寻找轮廓,

设定参数cv2.RETR_EXTERNAL只检测外轮廓痕迹,

通过cv2.CHAIN_APPROX_SIMPLE参数,保留轮廓定终点坐标。cv2.findContours算子答题卡在图中一般具有明显的轮廓,对图像的矫正可以对轮廓进行筛选,提取出具有四个顶点的近似轮廓即为答题卡的位置,获得图像中最大轮廓的坐标。主要应用以下算子获得答题卡轮廓:用此两种算子前需要使用算子cv2.cvtColor转换为灰度图像,为使轮廓更加明显使用第10章10.1.2节cv2.adaptiveThreshold自适应二值化去掉背景,突出答题卡01答题卡轮廓检测为确保答题卡被检测到,并获取答题卡在图中的具体位置,方便提取答题卡具体图像。使用if函数与for函数循环检测,确保至少有一个轮廓被找到,并将轮廓按大小降序排序。如果检测到近似有四个顶点,认定答题卡存在位置,获取四个顶点剪裁答题卡。主要使用函数如下:第12章12.3.1节的轮廓面积cv2.contourArea(cnt,True)函数,计算轮廓大小方便排序,寻找答题卡位置。函数语法格式如下:cnt为输入的单个轮廓值;True用来指定对象的形状是闭合轮廓还是曲线第12章12.3.1的周长cv2.arclength(cnt,True)函数,计算连线长度进行度量。函数语法格式如下:Cnt为输入的单个轮廓值;True用来指定对象的形状是闭合轮廓还是曲线第12章12.3.4节的近似轮廓cv2.approxPolyDP(cnt,epsilon,True)函数,为避免图像轮廓不平坦,获得一个近似矩形。函数语法格式如下:cnt为输入的轮廓值;epsilon为阈值,表示多边形的轮廓接近实际轮廓的程度,通常使用轮廓的周长作为阈值,值越小越精确。True表示轮廓闭合01答题卡轮廓检测代码展示defgetFourPtTrans(img): gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图像

blurred=cv2.GaussianBlur(gray,(7,7),0)#高斯滤波

#自适应二值化方法

blurred=cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,2)

edged=cv2.Canny(blurred,10,100)#canny边缘检测

#从边缘图中寻找轮廓,然后初始化答题卡对应的轮廓

cnts=cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

轮廓检测程序与运行结果cnts=cnts[1]ifimutils.is_cv3()elsecnts[0]

docCnt=None

iflen(cnts)>0:#确保至少有一个轮廓被找到

#将轮廓按大小降序排序

cnts=sorted(cnts,key=cv2.contourArea,reverse=True)

forcincnts:#对排序后的轮廓循环处理

peri=cv2.arcLength(c,True)#获取近似的轮廓

approx=cv2.approxPolyDP(c,0.02*peri,True)

iflen(approx)==4:#如果近似轮廓有四个顶点,那么就认为找到了答题卡

docCnt=approx

break

docCnt=docCnt.reshape(4,2)

returndocCnt#取顶点defgetXY(docCnt):

'''return(minX,minY,maxX,maxY)'''

minX,minY=docCnt[0]

maxX,maxY=docCnt[0]

foriinrange(1,4):

minX=min(minX,docCnt[i][0])

maxX=max(maxX,docCnt[i][0])

minY=min(minY,docCnt[i][1])

maxY=max(maxY,docCnt[i][1])

returnminX,minY,maxX,maxY代码展示02答题卡不同区域提取02答题卡不同区域提取在经过校正后识别出最大的方框为答题部分,从而根据答题区域的轮廓位于答题卡中的方位、大小以此寻找出答题卡其他的部分,分别为答题区域、答题卡的左上部、答题卡的右上部,其中答题卡的左上部最大轮廓为准考证号,答题卡的右上部为考试科目defsolve(imgPath):#

image=cv2.imread(imgPath)

ansCnt=getFourPtTrans(image)#答案的四点坐标

xy=getXY(ansCnt)

ansImg=image[xy[1]:xy[3],xy[0]:xy[2]]

ansImg=four_point_transform(image,ansCnt)

ansImg=cv2.resize(ansImg,(800,600))

cv2.imshow("ans",ansImg)

cv2.waitKey()

cv2.destroyAllWindows()

xy=getXY(ansCnt)

stuNum=image[0:xy[1],xy[0]:xy[2]]#切取上半部分的图

检测程序与运行结果numCnt=getFourPtTrans(stuNum)

cv2.imshow("stuNum",cv2.resize(stuNum.copy(),(400,600)))

cv2.imshow("stu_f",cv2.resize(four_point_transform(stuNum,numCnt),(400,600)))

xy=getXY(numCnt)

#切右半部分的图,方便识别科目

course=image[0:int(xy[3]*1.1),xy[2]:len(image)]

courseCnt=getFourPtTrans(course)#科目矩形的四点

cv2.imshow("course",cv2.resize(course.copy(),(600,800)))

cv2.imshow("course_f",cv2.resize(four_point_transform(course,courseCnt),(600,800)))

cv2.waitKey()

cv2.destroyAllWindows()if__name__=="__main__":solve(‘answersheet.jpg')02答题卡不同区域提取检测程序与运行结果检测程序与运行结果02答题卡不同区域提取答题卡上半部分区域截取答题卡上半部分答题区域提取03填涂答案识别03填涂答案识别在前面步骤中,获取答题卡中最大面积的区域即为答题区。在四点标记的答题区域上将涂黑选项标记,在二值图中涂黑的选项与答题卡环境有差别,将查找到的选项轮廓涂黑并画圈注明,并取得其坐标位置,定义判定方式根据坐标位置断定答案是否正确。1、确定答题区域后,使用第一部分所定义轮廓检测的二值化、边缘检测、区域提取和区域面积计算所得最小区域即为答题填涂方格。2、定义二值化阈值范围,范围内的数值即为填涂位置。并返回填涂位置方格坐标。3、在方格边缘利用方格坐标绘画红色圆圈标记填涂位置。答案填涂位置答题区域定位判断1、题号之间位置关系确定题号。2、根据填涂答案与正确答案方格坐标位置与答案方格取模,返回除法的余数确定ABCD选项。3、判断填涂答案与正确答案之间返回值是否一致。03填涂答案识别答案填涂位置程序defmarkOnImg(img,width,height):

'''在四点标记的图片上,将涂黑的选项标记,并返回(图片,坐标)'''

docCnt=getFourPtTrans(img)

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

paper=four_point_transform(img,docCnt)

warped=four_point_transform(gray,docCnt)

#灰度图二值化

thresh=cv2.adaptiveThreshold(warped,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,2)

#resize

thresh=cv2.resize(thresh,(width,height),cv2.INTER_LANCZOS4)

paper=cv2.resize(paper,(width,height),cv2.INTER_LANCZOS4)

warped=cv2.resize(warped,(width,height),cv2.INTER_LANCZOS4)

ChQImg=cv2.blur(thresh,(13,13))

#二值化,120是阈值

ChQImg=cv2.threshold(ChQImg,120,225,cv2.THRESH_BINARY)[1]

cnts=cv2.findContours(ChQImg,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#二值图中找答案轮廓cnts=cnts[1]ifimutils.is_cv3()elsecnts[0]forcincnts:x,y,w,h=cv2.boundingRect(c)ifw>50andh>20andw<100andh<100:M=cv2.moments(c)cX=int(M["m10"]/M["m00"])cY=int(M["m01"]/M["m00"])

cv2.drawContours(paper,c,-1,(0,0,255),5)cv2.circle(paper,(cX,cY),7,(255,255,255),2)Answer.append((cX,cY))returnpaper,Answer答案填涂位置程序03填涂答案识别03填涂答案识别答案区域判断程序defjudgeQ(x,y):#判断题号

'''传入时记得x+1,y+1'''

ifx<6:

returnx+(y-1)//4*5

else:

return((x-1)//5-1)*25+10+(x-1)%5+1+(y-1)//4*5

defjudgeAns(y):#判断答案

ify%4==1:

return'A'

ify%4==2:

return'B'

ify%4==3:

return'C'

ify%4==0:

return'D'

defjudge0(x,y):

return(judgeQ(x,y),judgeAns(y))IDAnswer=[]

forainAnswer:

forxinrange(0,len(xt1)-1):

ifa[0]>xt1[x]anda[0]<xt1[x+1]:

foryinrange(0,len(yt1)-1):

ifa[1]>yt1[y]anda[1]<yt1[y+1]:

IDAnswer.append(judge0(x+1,y+1))

IDAnswer.sort()

ansImg=cv2.resize(ansImg,(600,400))

cv2.imshow("answer",ansImg)

cv2.imwrite("answer.jpg",ansImg)

print(IDAnswer)

标记答案位置xt1=[0,110,210,310,410,565,713,813,913,1013,1163,1305,1405,1505,1605,1750,1895,1995,2095,2195,2295]

yt1=[0,125,175,225,300,422,471,520,600,716,766,817,902,1012,1064,1113,1195,1309,1357,1409,1479]03填涂答案识别答案区域判断程序width1,height1=2300,1500'''处理答案'''

ansImg,Answer=markOnImg(image,width1,height1)

#[(题号,答题卡上的答案),]

IDAnswer=[]

forainAnswer:

forxinrange(0,len(xt1)-1):

ifa[0]>xt1[x]anda[0]<xt1[x+1]:

foryinrange(0,len(yt1)-1):

ifa[1]>yt1[y]anda[1]<yt1[y+1]:

IDAnswer.append(judge0(x+1,y+1))

IDAnswer.sort()

ansImg=cv2.resize(ansImg,(600,400))

cv2.imshow("answer",ansImg)

cv2.imwrite("answer.jpg",ansImg)

print(IDAnswer)

'''处理学号'''

width2,height2=1000,1000

numImg,Answer=markOnImg(stuNum,width2,height2)

Answer.sort()

#xt2=list(range(0,1100,100))

yt2=[227,311,374,442,509,577,644,711,781,844]

NO=''

forainAnswer:

foryinrange(len(yt2)-1):

ifa[1]>yt2[y]anda[1]<yt2[y+1]:

NO+=str(y)

ifNO=='':

NO="Nan"

numImg=cv2.resize(numImg,(300,200))

#'''处理科目'''

width3,height3=300,1000

courseImg,Answer=markOnImg(course,width3,height3)

yt3=list(range(250,1000,65))

course_list=['政治','语文','数学','物理','化学','英语',

'历史','地理','生物','文综',

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论