1.H = cv2.getPerspectiveTransform(rect, transform_axes) 获得投射变化后的H矩阵

参数说明:rect表示原始的位置左上,右上,右下,左下, transform_axes表示变换后四个角的位置

2.cv2.warpPerspective(gray, H, (width, height)) 根据H获得变化后的图像

参数说明: gray表示输入的灰度图像, H表示变化矩阵,(width, height)表示变换后的图像大小
3. cv2.approxPloyDP(contour, length*0.02, True) # 计算轮廓的近似值

参数说明:contour表示输入的轮廓值, length表示轮廓的大小, True表示是否闭合

4. cv2.threshold(wrap, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_AUTO) # 进行图像的二值化操作
参数说明: wrap表示输入图片,0表示最小值,255表示最大值,THRESH_BINARY_INV | cv2.THRESH_AUTO表示方法,即大于最小阈值的为0, 小于最小阈值的为255

5. cv2.draw_contours(image, [contour], -1, 255, -1) # 对轮廓进行画图

参数说明:image表示输入图片. [contour] 表示单个轮廓, -1表示轮廓的index, 255表示颜色,-1表示对轮廓进行填充

6. cv2.bitwise(image, image, mask=mask)  # 与判断,如果两个都大于1才为1,否则都为0

参数说明:image表示输入图片,image表示输出图片, mask=mask表示掩膜

7. cv2.countNoneZeros(mask) # 用于计算图像中不等于0的像素点

参数说明:mask表示经过图像与掩膜的与操作以后的图像

8.cv2.putText(image, text, org, font, font_scale, color, ticking) # 在图像上加上文字

参数说明:image表示输入图片,text表示文字,org表示文字位置,font表示字体的格式,font_scale表示字体的胖瘦,color表示颜色,ticking表示粗细

答题卡识别判卷, 需要做的就是将画圈圈的地方识别出来。

    

原始图像                             涂了铅笔的比没涂白色部分要多,使用掩膜进行逐个遍历

第一部分:对图片进行透视变化,使得图片中的答题卡可以凸显出来

第一步:读入图片

第二步:使用cv2.gray() 进行灰度值的变化
第三步:使用cv2.GuassianBlur() 进行高斯滤波操作

第四步:使用cv2.Canny找出图片的边缘信息,为了下一步找出轮廓值做准备

第五步:使用cv2.findCountor() 找出图片的轮廓值,使用key = cv2.ContourArea对轮廓值进行排序

第六步:对轮廓值进行遍历,使用cv2.approxPolyDP(c, 0.02*lenght, True) 获得轮廓的近似值,如果近似值的维度为4,即为最外层答题卡的四个角的维度,则跳出循环

第七步:构造函数,对求得的轮廓值,根据其位置信息,将其变成左上,右上,右下,左上的形式的rect

第八步:计算width,height,计算出变换后的四个角的位置(transform_axes)

第九步:使用H = cv2.getPerspectiveTransform(rect, transform_axes) rect为变化前的位置,transform_axes为变化后的位置,以x,y表示,获得变化矩阵H

第十步:使用cv2.warpPerspective(thresh, H, (width, height)) 获得最终的变化结果

第二步:根据正确答案和图卡的答案来判断正确率

第一步:根据上述获得的wrapped,进行二值化操作, 使用cv2.COLOR_BINARY_INV将图了颜色的地方变成白色

第二步:使用cv2.findContours进行轮廓检测

第三步:对获得的轮廓,使用外接矩形cv2.boundingRect的(x, y, w, h)对轮廓进行筛选,找出答案的轮廓
第四步:对轮廓进行从上到下的排序

第五步:分别对每一行进行遍历,np.arange(0, len(question_cnts, 5)), 遍历每一行的轮廓值,根据图像构造掩膜mask图像,使用cv2.draw_contours在掩膜上画出对应位置的白色轮廓, 使用cv2.bitwise_and 获得原始图像当前位置等于1的点,使用cv2.countNoneZero计算出不是零的点,我们发现涂了颜色的要比没涂颜色的要大

第六步:计算出颜色值最大的位置和Nonezeros的值,correct+= 1

第七步:使用cv2.draw_contours在正确位置上进行画图操作

第八步:使用cv2.putText将正确率打印在图像上

代码:

# 第一部分代码:

  1. import cv2
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4.  
  5. # 正确答案
  6. ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}
  7. def cv_show(name, image):
  8. cv2.imshow(name, image)
  9. cv2.waitKey(0)
  10. cv2.destroyAllWindows()
  11.  
  12. def four_point_transform(image, dotCnt):
  13. # 第七步:按照轮廓近似的位置,将结果变成左上,右上,右下,左下的位置
  14. rect = sort_dotCnt(dotCnt)
  15. (tl, tr, br, bl) = rect
  16. # 第八步:计算轮廓的宽和长,构造出变化后四个角的位置
  17. widthA = np.sqrt(((tl[0]-tr[0])**2) + ((tl[1]-tr[1])**2))
  18. widthB = np.sqrt(((bl[0]-br[0])**2) + ((bl[1] - br[1])**2))
  19. widthMax = max(int(widthB), int(widthA))
  20.  
  21. heightA = np.sqrt(((tl[0]-bl[0])**2) + ((tl[1]-bl[1])**2))
  22. heightB = np.sqrt(((tr[0]-br[0])**2) + ((tr[1] - br[1])**2))
  23. heightMax = max(int(heightA), int(heightB))
  24. # 四个角的位置信息
  25. transform_axis = np.array([
  26. [0, 0],
  27. [widthMax-1, 0],
  28. [widthMax-1, heightMax-1],
  29. [0, heightMax-1],
  30. ], dtype='float32')
  31.  
  32. # 第九步:使用cv2.getPerspectiveTransform构造变化矩阵H
  33. H = cv2.getPerspectiveTransform(rect, transform_axis)
  34. # 第十步:使用cv2.warpPerspective()获得变化后的矩阵
  35. wrapped = cv2.warpPerspective(image, H, (widthMax, heightMax))
  36.  
  37. cv_show('wrapped', wrapped)
  38.  
  39. return wrapped
  40.  
  41. def sort_dotCnt(kps):
  42.  
  43. rect = np.zeros((4, 2), dtype='float32')
  44. s = kps.sum(axis=1)
  45. # 找出左上和右下
  46. rect[0] = kps[np.argmin(s)]
  47. rect[2] = kps[np.argmax(s)]
  48. # 找出右上和左下
  49. diff = np.diff(kps, axis=1)
  50. rect[1] = kps[np.argmin(diff)]
  51. rect[3] = kps[np.argmax(diff)]
  52.  
  53. return rect
  54.  
  55. def sorted_contours(cnt, model='left-to-right'):
  56.  
  57. if model == 'top-to-bottom':
  58. cnt = sorted(cnt, key=lambda x:cv2.boundingRect(x)[1])
  59.  
  60. elif model == 'left-to-right':
  61. cnt = sorted(cnt, key=lambda x:cv2.boundingRect(x)[0])
  62.  
  63. return cnt
  64.  
  65. # 第一部分:使用投射变化进行图像的转换, 将答题卡放在图片的正中央
  66. # 第一步:读入图片
  67. image = cv2.imread('images/test_01.png')
  68. # 第二步:进行灰度化操作
  69. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  70. cv_show('gray', gray)
  71.  
  72. # 第三步: 进行高斯变化
  73. Guass = cv2.GaussianBlur(gray, (5, 5), 0)
  74. # 第四步:使用cv2.Canny 找出图像的边缘部分
  75. edges = cv2.Canny(Guass, 50, 200)
  76. cv_show('edges', edges)
  77. # 第五步:使用cv2.findCountours找出图像的轮廓, 并对轮廓进行排序
  78. cnt = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
  79. ret = cv2.drawContours(image.copy(), cnt, -1, (0, 0, 255), 2)
  80. cv_show('ret', ret)
  81.  
  82. dotCnt = None
  83.  
  84. if len(cnt) > 0:
  85.  
  86. cnt = sorted(cnt, key=cv2.contourArea, reverse=True)
  87. # 第六步: 遍历轮廓,获得cv2.approxPolyDP获得轮廓的近似值, 如果approx=4,即为填图卡的轮廓近似
  88. for c in cnt:
  89.  
  90. length = cv2.arcLength(c, True)
  91. # 获得轮廓的近似值
  92. approx = cv2.approxPolyDP(c, 0.02*length, True)
  93. # 如果轮廓的维度是4,即由4个点组成,就是一个方框,那就是外面的方框
  94. if len(approx) == 4:
  95.  
  96. dotCnt = approx
  97. break
  98.  
  99. wrapped = four_point_transform(gray, dotCnt.reshape(4, 2))
  100. cv_show('wrapped', wrapped)

            

原始图片                            灰度变化后图片         边缘检测的图片                 检测到的轮廓图            最终透射变化结果

# 第二部分代码:

  1. # 第二部分:对变化后的wrapped进行操作,构造mask根据有无填涂的特性,进行位置的计算
  2.  
  3. #第一步:对图像进行二值化操作
  4. thresh = cv2.threshold(wrapped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
  5. cv_show('thresh', thresh)
  6.  
  7. # 第二步:对图像进行轮廓检测
  8. cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
  9.  
  10. # 第三步:使用cv2.boudingRect将答案信息的轮廓进行筛选
  11.  
  12. questionCnts = []
  13. for c in cnts:
  14.  
  15. (x, y, w, h) = cv2.boundingRect(c)
  16. arc = w / float(h)
  17.  
  18. # 根据实际情况找出合适的轮廓
  19. if w > 20 and h > 20 and arc >= 0.9 and arc<=1.1:
  20. questionCnts.append(c)
  21.  
  22. # 第四步:将轮廓进行从上到下的排序
  23. questionCnts = sorted_contours(questionCnts, model='top-to-bottom')
  24.  
  25. # 第五步:对每一行的轮廓进行遍历,构造掩码,对每一行答案的轮廓进行遍历,使用cv2.countNoneZeros()计算出涂了颜色的答案,并计算最终的结果
  26. correct = 0
  27. for j, qC in enumerate(np.arange(0, len(questionCnts), 5)):
  28.  
  29. questionCnt = questionCnts[qC:qC+5]
  30. # 进行排序
  31. questionCnt = sorted_contours(questionCnt)
  32. questionCnt = np.array(questionCnt)
  33. # 每个问题的答案
  34. bubbled = None
  35. for k, c in enumerate(questionCnt):
  36. # 根据轮廓值构造掩膜, 因为有涂答案的地方是白色的
  37. mask = np.zeros(thresh.shape, np.uint8)
  38. # 使用cv2.drawContours画出轮廓值
  39. cv2.drawContours(mask, [c], -1, 255, -1)
  40. cv_show('mask', mask)
  41. mask = cv2.bitwise_and(thresh, thresh, mask=mask)
  42. # 第六步:使用cv2.countNoneZero计算出白色最多的位置
  43. Nonezero = cv2.countNonZero(mask)
  44. if bubbled == None or Nonezero > bubbled[0]:
  45. bubbled = (Nonezero, k)
  46.  
  47. question_answer = int(bubbled[1])
  48. answer_True = ANSWER_KEY[j]
  49.  
  50. # 如果结果和正确结果相同,就+1
  51. if question_answer == answer_True:
  52. correct += 1
  53. # 第七步:对正确答案的轮廓进行画图操作
  54. cv2.drawContours(wrapped, [questionCnt[answer_True]], -1, 0, 2)
  55.  
  56. cv_show('wrapped', wrapped)
  57.  
  58. score = (correct / 5) * 100
  59. # 第八步:使用cv2.putText将正确率打印在图上
  60. cv2.putText(wrapped, 'correct_score:%d' %score, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
  61. 0.8, 0, 2)
  62. cv2.imshow('orginal', image)
  63. cv2.imshow('wrapped', wrapped)
  64.  
  65. cv2.waitKey(0)
  66. cv2.destroyAllWindows()

               

Binary_Inv二值化的结果         draw_contours画出掩膜轮廓                      最终的结果图

机器学习进阶-案例实战-答题卡识别判 1.cv2.getPerspectiveTransform(获得投射变化后的H矩阵) 2.cv2.warpPerspective(H获得变化后的图像) 3.cv2.approxPolyDP(近似轮廓) 4.cv2.threshold(二值变化) 7.cv2.countNonezeros(非零像素点个数)6.cv2.bitwise_and(与判断)的更多相关文章

  1. 机器学习进阶-案例实战-停车场车位识别-keras预测是否停车站有车

    import numpy import os from keras import applications from keras.preprocessing.image import ImageDat ...

  2. 机器学习进阶-项目实战-信用卡数字识别 1.cv2.findContour(找出轮廓) 2.cv2.boudingRect(轮廓外接矩阵位置) 3.cv2.threshold(图片二值化操作) 4.cv2.MORPH_TOPHAT(礼帽运算突出线条) 5.cv2.MORPH_CLOSE(闭运算图片内部膨胀) 6. cv2.resize(改变图像大小) 7.cv2.putText(在图片上放上文本)

    7. cv2.putText(img, text, loc, text_font, font_scale, color, linestick) # 参数说明:img表示输入图片,text表示需要填写的 ...

  3. 机器学习进阶-案例实战-图像全景拼接-图像全景拼接(RANSCA) 1.sift.detectAndComputer(获得sift图像关键点) 2.cv2.findHomography(计算单应性矩阵H) 3.cv2.warpPerspective(获得单应性变化后的图像) 4.cv2.line(对关键点位置进行连线画图)

    1. sift.detectAndComputer(gray, None)  # 计算出图像的关键点和sift特征向量 参数说明:gray表示输入的图片 2.cv2.findHomography(kp ...

  4. 机器学习进阶-案例实战-图像全景拼接-书籍SIFT特征点连接 1.cv2.drawMatches(对两个图像的关键点进行连线操作)

    1.cv2.drawMatches(imageA, kpsA, imageB, kpsB, matches[:10], None, flags=2)  # 对两个图像关键点进行连线操作 参数说明:im ...

  5. webpack4入门到进阶案例实战课程

    愿景:"让编程不在难学,让技术与生活更加有趣" 更多教程请访问xdclass.net 第一章 webpack4前言 第一集 webpack4入门到进阶案例实战课程介绍 简介:讲述w ...

  6. 浅谈PHP答题卡识别(一)

    最近期末考试考完了,我们也要放寒假了.于是突发奇想,想用PHP写一个答题卡识别程序.已经实现了一些,现分享给大家. 具体的步骤如下: 上传答题卡=>图片二值化(已实现)=>寻找定位点(已实 ...

  7. LeadTools答题卡识别方案

    /// <summary> /// 批改操作 /// </summary> public AnswerCard DoCorrect(Stream AnserCardFile) ...

  8. 机器学习进阶-图像金字塔与轮廓检测-轮廓检测 1.cv2.cvtColor(图像颜色转换) 2.cv2.findContours(找出图像的轮廓) 3.cv2.drawContours(画出图像轮廓) 4.cv2.contourArea(轮廓面积) 5.cv2.arcLength(轮廓周长) 6.cv2.aprroxPloyDP(获得轮廓近似) 7.cv2.boudingrect(外接圆)..

    1. cv2.cvtcolor(img, cv2.COLOR_BGR2GRAY) # 将彩色图转换为灰度图 参数说明: img表示输入的图片, cv2.COLOR_BGR2GRAY表示颜色的变换形式 ...

  9. Opencv2教程一:图像变换之阈值二值threshold

    网名:无名   QQ:16349023 email:mengwzy@qq.com 曾经非常少写教程,写的可能有点乱希望大对家有帮助 threshold 方法是通过遍历灰度图中点.将图像信息二值化,处理 ...

随机推荐

  1. 学习笔记之pandas

    Python Data Analysis Library — pandas: Python Data Analysis Library https://pandas.pydata.org/ panda ...

  2. php的语句

    1.php流程语句 1.php代码执行从上到下 2.条件语句 if else 和 switch 案例: $name=56; if($name>56) echo "hello world ...

  3. google最新的书签导入导出

    1.google浏览器地址栏最右边,自定义及控制--->书签----->书签管理器 2. 右上角,有整理图标, 3.点击按钮即可导入导出书签

  4. windows10如何查看wifi密码

    1.首先,在你的电脑的右下角的WiFi的图标,右击它,选择"网络和internet设置"或者选择打开设置 :如下图 点击"更改适配器选项" 选择 WLAN选项, ...

  5. 基于JMX动态配置Log4J日志级别

    先来看比较low的修改日志级别的方式,在写程序里面. http://blog.gssxgss.me/java%E8%BF%90%E8%A1%8C%E6%97%B6%E5%8A%A8%E6%80%81% ...

  6. 《Java 程序设计》课堂实践项目 课后学习总结

    <Java 程序设计>课堂实践项目 课后学习总结 String类的使用(sort) 目录 Linux命令(sort) 课堂实践 课后思考 学习老师的代码之后的思考:int与Integer ...

  7. 安装sublime txt3 并且设置为默认的text打开方式

    1.安装 安装可以参考 http://jingyan.baidu.com/article/fa4125acb8569b28ac7092ea.html 1.添加sublime text 3的仓库: su ...

  8. HTTP协议的简单解析

    超文本传输协议(HTTP,HyperText Transfer Protocol)是用于从服务器传输超文本到本地浏览器的传输协议,是应用最为广泛的网络协议.B/S网络架构的核心是HTTP,掌握HTTP ...

  9. Hibernate QBC

    QBC查询: Query By Criteria 使用面向对象的方式查询 和HQL单表查询相似,但不包含别名查询和具名查询   1 全表查询 Criteria ce = session.createC ...

  10. sqoop导入导出

    sqoop产生背景 什么是sqoop sqoop的优势 sqoop1与sqoop2的比较 为什么选择sqoop1 sqoop在hadoop生态体系中的位置 sqoop基本架构 sqoop import ...