sheet.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # coding=utf-8
  2. import cPickle
  3. import cv2
  4. from imutils import contours
  5. from e import ContourCountError, ContourPerimeterSizeError, PolyNodeCountError
  6. from settings import ANS_IMG_THRESHOLD, CNT_PERIMETER_THRESHOLD, CHOICE_IMG_THRESHOLD, ANS_IMG_DILATE_ITERATIONS, \
  7. ANS_IMG_ERODE_ITERATIONS, CHOICE_IMG_DILATE_ITERATIONS, CHOICE_IMG_ERODE_ITERATIONS, CHOICE_MAX_AREA, \
  8. CHOICE_CNT_COUNT, ANS_IMG_KERNEL, CHOICE_IMG_KERNEL, CHOICE_MIN_AREA
  9. from utils import detect_cnt_again, get_init_process_img, get_max_area_cnt, get_ans, \
  10. get_left_right, get_top_bottom, sort_by_row, sort_by_col, insert_null_2_rows, get_vertical_projective, \
  11. get_h_projective
  12. def get_answer_from_sheet(base_img):
  13. # cv2.imshow('temp', base_img)
  14. # cv2.waitKey(0)
  15. # 灰度化然后进行边缘检测、二值化等等一系列处理
  16. img = cv2.cvtColor(base_img, cv2.COLOR_BGR2GRAY)
  17. img = get_init_process_img(img)
  18. # cv2.imshow('temp', img)
  19. # cv2.waitKey(0)
  20. # 获取最大面积轮廓并和图片大小作比较,看轮廓周长大小判断是否是答题卡的轮廓
  21. cnt = get_max_area_cnt(img)
  22. cnt_perimeter = cv2.arcLength(cnt, True)
  23. base_img_perimeter = (base_img.shape[0] + base_img.shape[1]) * 2
  24. if not cnt_perimeter > CNT_PERIMETER_THRESHOLD * base_img_perimeter:
  25. raise ContourPerimeterSizeError
  26. # cv2.drawContours(base_img, [cnt], 0, (0, 255, 0), 1)
  27. # cv2.imshow('temp', base_img)
  28. # cv2.waitKey(0)
  29. # 计算多边形的顶点,并看是否是四个顶点
  30. poly_node_list = cv2.approxPolyDP(cnt, cv2.arcLength(cnt, True) * 0.1, True)
  31. if not poly_node_list.shape[0] == 4:
  32. raise PolyNodeCountError
  33. # 根据计算的多边形顶点继续处理图片,主要是是纠偏
  34. processed_img = detect_cnt_again(poly_node_list, base_img)
  35. # cv2.imshow('temp', processed_img)
  36. # cv2.waitKey(0)
  37. # 调整图片的亮度
  38. processed_img = cv2.cvtColor(processed_img, cv2.COLOR_BGR2GRAY)
  39. processed_img = cv2.GaussianBlur( processed_img, (9, 9), 0)
  40. # cv2.imshow('temp', processed_img)
  41. # cv2.waitKey(0)
  42. # 通过二值化和膨胀腐蚀获得填涂区域
  43. # ret, ans_img = cv2.threshold(processed_img, ANS_IMG_THRESHOLD[0], ANS_IMG_THRESHOLD[1], cv2.THRESH_BINARY_INV)
  44. ans_img = cv2.adaptiveThreshold(processed_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 41, 35)
  45. ans_img = cv2.dilate(ans_img, ANS_IMG_KERNEL, iterations=ANS_IMG_DILATE_ITERATIONS)
  46. ans_img = cv2.erode(ans_img, ANS_IMG_KERNEL, iterations=ANS_IMG_ERODE_ITERATIONS)
  47. ret, ans_img = cv2.threshold(ans_img, ANS_IMG_THRESHOLD[0], ANS_IMG_THRESHOLD[1], cv2.THRESH_BINARY_INV)
  48. # cv2.imshow('temp', ans_img)
  49. # cv2.waitKey(0)
  50. # 通过二值化和膨胀腐蚀获得选项框区域
  51. choice_img = cv2.adaptiveThreshold(processed_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 51, 10)
  52. # ret, choice_img = cv2.threshold(processed_img, CHOICE_IMG_THRESHOLD[0], CHOICE_IMG_THRESHOLD[1],
  53. # cv2.THRESH_BINARY_INV)
  54. # cv2.imshow('temp', choice_img)
  55. # cv2.waitKey(0)
  56. # get_vertical_projective(choice_img)
  57. # get_h_projective(choice_img)
  58. for i in range(1):
  59. choice_img = cv2.dilate(choice_img, CHOICE_IMG_KERNEL, iterations=CHOICE_IMG_DILATE_ITERATIONS)
  60. choice_img = cv2.erode(choice_img, CHOICE_IMG_KERNEL, iterations=CHOICE_IMG_ERODE_ITERATIONS)
  61. # get_vertical_projective(choice_img)
  62. # get_h_projective(choice_img)
  63. # cv2.imshow('temp', choice_img)
  64. # cv2.waitKey(0)
  65. # 查找选项框以及前面题号的轮廓
  66. cnts, h = cv2.findContours(choice_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  67. question_cnts = []
  68. temp1_ans_img = ans_img.copy()
  69. for i, c in enumerate(cnts):
  70. # 如果面积小于某值,则认为这个轮廓是选项框或题号
  71. if CHOICE_MIN_AREA < cv2.contourArea(c) < CHOICE_MAX_AREA:
  72. cv2.drawContours(temp1_ans_img, cnts, i, (0, 0, 0), 1)
  73. question_cnts.append(c)
  74. # cv2.imshow('temp', temp1_ans_img)
  75. # cv2.waitKey(0)
  76. question_cnts = get_left_right(question_cnts)
  77. question_cnts = get_top_bottom(question_cnts)
  78. temp2_ans_img = ans_img.copy()
  79. for i in range(len(question_cnts)):
  80. cv2.drawContours(temp2_ans_img, question_cnts, i, (0, 0, 0), 1)
  81. # cv2.imshow('temp', temp2_ans_img)
  82. # cv2.waitKey(0)
  83. # 如果轮廓小于特定值,重新扫描
  84. # TODO 运用统计分析排除垃圾轮廓
  85. # if len(question_cnts) != CHOICE_CNT_COUNT:
  86. # raise ContourCountError
  87. # cv2.imshow('temp', temp_ans_img)
  88. # cv2.waitKey(0)
  89. # 对轮廓之上而下的排序
  90. question_cnts, cnts_pos = contours.sort_contours(question_cnts, method="top-to-bottom")
  91. rows = sort_by_row(list(cnts_pos))
  92. cols = sort_by_col(list(cnts_pos))
  93. # cv2.imshow('temp', temp2_ans_img)
  94. # cv2.waitKey(0)
  95. insert_null_2_rows(cols, rows)
  96. # 获得答案
  97. rows, res = get_ans(ans_img, rows)
  98. if not res[0]:
  99. print res[1]
  100. cv2.imshow('temp1', temp2_ans_img)
  101. cv2.waitKey(0)
  102. print 'end'
  103. else:
  104. print res