当前位置:   article > 正文

实战三、OpenCv答题卡识别判卷_c#中opencv识别

c#中opencv识别
  1. import cv2
  2. import numpy as np
  3. ANSWER_KEY={0:1,1:4,2:0,3:3,4:1}
  4. # 获取坐标点
  5. def order_points(pts):
  6. # 一共4个坐标点
  7. rect = np.zeros((4, 2), dtype="float32")
  8. # 按顺序找到对应坐标0123分别是 左上,右上,右下,左下
  9. # 计算左上,右下
  10. s = pts.sum(axis=1)
  11. rect[0] = pts[np.argmin(s)]
  12. rect[2] = pts[np.argmax(s)]
  13. # 计算右上和左下
  14. diff = np.diff(pts, axis=1)
  15. rect[1] = pts[np.argmin(diff)]
  16. rect[3] = pts[np.argmax(diff)]
  17. return rect
  18. def four_point_transform(image, pts):#pts是原始图像的四个坐标点
  19. # 获取输入坐标点
  20. rect = order_points(pts)
  21. (tl, tr, br, bl) = rect
  22. #计算输入的w和h值
  23. widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))#根号下(x3-x4)^2+(y3-y4)^2
  24. widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))#根号下(x2-x1)^2+(y2-y1)^2
  25. maxWidth = max(int(widthA), int(widthB))#取得两个中的最大值,作为目标图像的宽
  26. heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))#根号下(x4-x1)^2+(y4-y1)^2
  27. heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))#根号下(x3-x2)^2+(y3-y2)^2
  28. maxHeight = max(int(heightA), int(heightB))#取得两个中的最大值,作为目标图像的高
  29. # 变换后对应坐标位置:目标图像中对应的四个点
  30. dst = np.array([
  31. [0, 0],#目标图像中的tl坐标
  32. [maxWidth - 1, 0],#目标图像中tr坐标
  33. [maxWidth - 1, maxHeight - 1],#目标图像的br坐标
  34. [0, maxHeight - 1]], dtype="float32")#目标图像的bl坐标
  35. # 计算变换矩阵
  36. M = cv2.getPerspectiveTransform(rect, dst) #通过输入和输出的四个坐标,就可以计算出变换矩阵
  37. warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))#dsize是目标图像的大小
  38. # 返回变换后结果
  39. return warped
  40. def sort_contours(contours,method="left-to-right"):
  41. reverse = False
  42. i = 0
  43. if method == "right-to-left" or method == "bottom-to-top":
  44. reverse = True
  45. if method == "top-to-bottom" or method == "bottom-to-top":
  46. i = 1
  47. # 把找到的形状用最小的矩形包起来,外接矩形,x,y,h,w
  48. boundingBoxes = [cv2.boundingRect(c) for c in contours]
  49. # 直接用x来判断出来轮廓的排列顺序
  50. (contours, boundingBoxes) = zip(*sorted(zip(contours, boundingBoxes), key=lambda b: b[1][i], reverse=reverse))
  51. return contours, boundingBoxes
  52. #图像的预处理操作
  53. image=cv2.imread("/Users/macbook/Desktop/project3.png")#读入原始图像
  54. contours_img=image.copy()
  55. gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)#将BGR图像转换成灰度图像
  56. blurred=cv2.GaussianBlur(gray,(5,5),0)#对灰度图像进行高斯滤波操作,去除噪点
  57. edged=cv2.Canny(blurred,75,200)#对滤波后进行边缘检测操作
  58. cv2.imshow("edged",edged)#显示边缘检测后的图像
  59. #检测外轮廓
  60. cnts,hierarchy=cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
  61. cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)#在原始图像上用红色画笔画出轮廓
  62. docCnt=None
  63. if len(cnts)>0:#确保检测到了轮廓
  64. cnts=sorted(cnts,key=cv2.contourArea,reverse=True)#根据面积的大小对检测的外轮廓按照面积的大小进行排序处理
  65. for c in cnts:
  66. peri = cv2.arcLength(c, True)
  67. approx = cv2.approxPolyDP(c,0.02*peri,True)#c表示输入的点集,True表示闭合
  68. if(len(approx)==4):#表示检测到了矩形的轮廓,直接退出循环即可
  69. docCnt=approx
  70. break
  71. #透视变换
  72. warped=four_point_transform(gray,docCnt.reshape(4,2))
  73. thresh=cv2.threshold(warped,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1]#自定义阈值,二值化操作
  74. cv2.imshow("thresh",thresh)#显示二值化图像处理的结果
  75. # 学生涂的区域白色部分比较多,就是非0区域面积比较大,没涂的部分非0区域比较少
  76. thresh_Contours=thresh.copy()
  77. #找到每一个圆圈选项的轮廓:对应有各自的掩码图像
  78. Cnts,hierarchy=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
  79. cv2.drawContours(thresh_Contours,Cnts,-1,(0,0,255),3)
  80. cv2.imshow("thresh_Contours",thresh_Contours)
  81. questionCnts=[]
  82. #遍历每一个轮廓:筛选轮廓
  83. for c in Cnts:
  84. #计算比例和大小
  85. (x,y,w,h)=cv2.boundingRect(c)#对每一个轮廓用最小的外包矩形来包围
  86. ar=w/float(h)
  87. if w>=20 and h>=20 and ar>=0.9 and ar<=1.1:#根据实际情况制定标准,因为学生涂卡时可能没涂满,也有可能涂到外面了
  88. questionCnts.append(c)
  89. #对得到的轮廓进行排序
  90. questionCnts=sort_contours(questionCnts,method="top-to-bottom")[0]
  91. correct=0#表示正确的题目数量
  92. for(q,i) in enumerate(np.arange(0,len(questionCnts),5)):#每道题目有五个选项:5
  93. cnts=sort_contours(questionCnts[i:i+5])[0]
  94. bubbled=None
  95. for(j,c)in enumerate (cnts):
  96. mask = np.zeros(thresh.shape, dtype='uint8')#作出与二进制图像大小相同的掩码图像
  97. cv2.drawContours(mask, [c], -1, 255, -1)#在掩码图像上对轮廓所处的区域用白色填充好
  98. cv2.imshow("mask2",mask)#展示此时的掩码图像
  99. mask=cv2.bitwise_and(thresh,thresh,mask=mask)#进行与操作,掩码白色区域的thresh图像保留下来,其他变成黑色
  100. cv2.imshow("mask3",mask)#展示此时的掩码图像
  101. total=cv2.countNonZero(mask)#计算掩码区域非零的值,涂黑区域的非零值会更多
  102. if bubbled is None or total>bubbled[0]:
  103. #表示是每一题的第一个选项或者现在的非零区域更多,就把bubbled的值换成目前的total值
  104. bubbled=(total,j)#j表示q题学生填写答案的列数
  105. #对比正确答案:
  106. color=(0,0,255)
  107. k=ANSWER_KEY[q]#q代表题数,从0开始,ANSWER_KEY[k]就是q题目对应的正确答案的列数
  108. if k==bubbled[1]:#表示填写答案与正确答案相同
  109. color=(0,255,0)#绿色表示正确
  110. correct+=1
  111. #绘图
  112. cv2.drawContours(warped,[cnts[k]],-1,color,3)
  113. #计算正确率
  114. score=(correct/5.0)*100
  115. print("[INFO] score: {:.2f}%".format(score))
  116. cv2.putText(warped, "{:.2f}%".format(score), (10, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
  117. result=cv2.cvtColor(warped,cv2.COLOR_GRAY2BGR)
  118. cv2.imshow("result",result)
  119. cv2.waitKey(0)
  120. cv2.destroyAllWindows()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/812048
推荐阅读
相关标签
  

闽ICP备14008679号