ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

答题卡识别

2022-01-20 12:33:54  阅读:189  来源: 互联网

标签:gray cnt img cv2 答题卡 questionCnt docCnt 识别


两个idea:

1、霍夫变换找圆在复杂环境并不理想,可以找轮廓,然后限制外接矩形w和h来排除

2、坐标排序时,可能同一行的x有些许误差,则可以这样排序(分两次排序):假设一行5个,

先从上向下排序,则每5个即为一道题的选项,虽然是乱序的,但只要再对每5个从左向右排序即可

主要判断论述:

 

 

import cv2
import numpy as np
import math

def show(img):
    cv2.imshow('name', img)
    cv2.waitKey()
    cv2.destroyAllWindows()

# def equal(x, y): #如果相差在15以内,则说明相等
#     if abs(x - y) <= 15:
#         return 1
#     return 0
#
# def cnt_sort(docCnt):
#     for i in range(len(docCnt) - 1):
#         for j in range(len(docCnt) - i - 1):
#             if equal(docCnt[j][1], docCnt[j + 1][1]) == 1:
#                 if(docCnt[j][0] > docCnt[j + 1][0]):
#                     tmp = docCnt[j + 1].copy()
#                     docCnt[j + 1] = docCnt[j]
#                     docCnt[j] = tmp
#             else:
#                 if docCnt[j][1] > docCnt[j + 1][1]:
#                     tmp = docCnt[j + 1].copy()
#                     docCnt[j + 1] = docCnt[j]
#                     docCnt[j] = tmp
#     return docCnt


def cnt_sort(docCnt):

    docCnt = sorted(docCnt, key = lambda x : x[1])
    ret = []
    for i in range(0, len(docCnt), 2):
        cnts = docCnt[i : i + 2]
        cnts = sorted(cnts, key = lambda x : x[0])
        ret += cnts

    return ret


def four_point_transform(img, docCnt):
    # print(docCnt)
    docCnt = cnt_sort(docCnt)
    docCnt = np.array(docCnt, dtype = 'float32')

    coner1, coner2, coner3, coner4 = docCnt
    # print(docCnt)
    w = int(max(math.sqrt((coner1[0] - coner2[0]) ** 2 + (coner1[1] - coner2[1]) ** 2), math.sqrt((coner3[0] - coner4[0]) ** 2 + (coner3[1] - coner4[1]) ** 2)))
    h = int(max(math.sqrt((coner1[0] - coner3[0]) ** 2 + (coner1[1] - coner3[1]) ** 2), math.sqrt((coner2[0] - coner4[0]) ** 2 + (coner2[1] - coner4[1]) ** 2)))
    rightCnt = np.array([[0, 0], [w, 0], [0, h], [w, h]], dtype = 'float32')
    # print(docCnt, rightCnt)
    transform_matrix = cv2.getPerspectiveTransform(docCnt, rightCnt) #输入类型需要一样,都是float32就行
    img = cv2.warpPerspective(img, transform_matrix, (w, h)) #w和h需要是整数
    return img


def questionCnt_sort(questionCnt, flag):
    # flag为1就是从上向下,0就是从左到右
    boundingbox = [cv2.boundingRect(cnt) for cnt in questionCnt]
    questionCnt, boundingbox = zip(*sorted(zip(questionCnt, boundingbox), key = lambda x : x[1][flag]))
    return questionCnt

if __name__ == '__main__':
    img = cv2.imread('C:/Users/WTSRUVF/Downloads/card/answer sheet/images/test_01.png')
    img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    img_gray = cv2.GaussianBlur(img_gray, (5, 5), 0)
    edged = cv2.Canny(img_gray, 75, 200)
    # show(edged)
    contours = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
    contours = sorted(contours, key = cv2.contourArea, reverse = True)
    docCnt = None
    for cnt in contours:
        peri = cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, peri * 0.02, True)
        if len(approx) == 4:
            docCnt = approx
            break
    img_gray_copy = img_gray.copy()
    # img_copy = cv2.drawContours(img_copy, [docCnt], -1, (0, 0, 255), 2)
    img_s = four_point_transform(img_gray_copy, docCnt.reshape(4, 2))
    # show(img_s)
    thresh = cv2.threshold(img_s, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
    threshContours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
    questionCnt = []
    for cnt in threshContours:
        (x, y, w, h) = cv2.boundingRect(cnt)
        ar = w / float(h)
        if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:
            questionCnt.append(cnt)
    questionCnt = questionCnt_sort(questionCnt, 1)
    #先从上向下排序,则每5个即为一道题的选项,虽然是乱序的,但只要再对每5个从左向右排序即可
    for k, i in enumerate(range(0, len(questionCnt), 5)):
        cnts = questionCnt_sort(questionCnt[i : i + 5], 0)
        answer = None
        for j, cnt in enumerate(cnts):
            mask = np.zeros(img_s.shape, dtype = 'uint8')
            mask = cv2.drawContours(mask, [cnt], -1, 255, -1) #-1为填充
            mask = cv2.bitwise_and(thresh, thresh, mask = mask)
            total = cv2.countNonZero(mask)
            if answer == None or answer[0] < total:
                answer = (total, j + 1)
        print(answer[1])

 数据集和代码链接:https://pan.baidu.com/s/1SMJ76fL1sbFmWUGurAjoQQ
提取码:qgz6

标签:gray,cnt,img,cv2,答题卡,questionCnt,docCnt,识别
来源: https://www.cnblogs.com/WTSRUVF/p/15825882.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有