opencv實現(xiàn)答題卡識別
更新時間:2022年01月23日 17:49:23 作者:qq_36008031
這篇文章主要為大家詳細介紹了opencv實現(xiàn)答題卡識別,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了opencv實現(xiàn)答題卡識別的具體代碼,供大家參考,具體內(nèi)容如下
""" 識別答題卡 """ ? import cv2 import numpy as np ? def showImg(img_name, img): cv2.imshow(img_name, img) cv2.waitKey() cv2.destroyAllWindows() ? def get_max_rect(sorted_cnts): for cnt in sorted_cnts: # 輪廓近似 possible_cnts = [] epsilon = 0.1 * cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, epsilon, True) if len(approx) == 4: possible_cnts.append(cnt) possible_cnts = sorted(possible_cnts, key=lambda x: cv2.arcLength(x, True)) return possible_cnts ? def get_max_bounding_rect(possible_cnts): # for cnt in possible_cnts: # x, y, w, h = cv2.boundingRect(cnt) ? sorted_cnts = sorted(possible_cnts, key=lambda cnt: cv2.boundingRect(cnt)[2]*cv2.boundingRect(cnt)[3], reverse=True) print(sorted_cnts[0]) ? def show_countour(img, cnt): img_copy = img.copy() cv2.drawContours(img_copy, cnt, -1, (0,255, 0), 3) showImg("img_copy", img_copy) ? ? # 讀取答題卡圖片,并顯示 answer_sheet_img = cv2.imread("t1.jpg") print(answer_sheet_img.shape) showImg("answer_sheet_img", answer_sheet_img) ? # 高斯濾波,去除噪音 blur = cv2.GaussianBlur(answer_sheet_img,(5,5),0) showImg("blur", blur) ? # 圖像轉灰度值 sheet_gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY) showImg("sheet_gray", sheet_gray) ? # 二值化 retval, sheet_threshold = cv2.threshold(sheet_gray,177, 255, cv2.THRESH_BINARY) # print(type(sheet_threshold), sheet_threshold) showImg("sheet_threshold", sheet_threshold) ? # 邊界檢測 edges = cv2.Canny(sheet_threshold, 100, 200) showImg("edges", edges) # print(type(edges)) ? # 尋找輪廓 copy_edges = edges.copy() img_copy = answer_sheet_img.copy() img, cnts, hierarchy = cv2.findContours(copy_edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img_copy, cnts, -1, (0,0,255), 1) showImg("img_copy", img_copy) ? # 對所有輪廓加一個外接矩形,找最大的外接矩形 max_area_index = None area = 0 for index, cnt in enumerate(cnts): x, y, w, h = cv2.boundingRect(cnt) if w*h > area: max_area_index = index show_countour(answer_sheet_img, cnts[max_area_index]) ? # 仿射,拿到答題卡主要部位 x, y, w, h = cv2.boundingRect(cnts[max_area_index]) # 最大的邊界 cv2.rectangle(answer_sheet_img, (x, y),(x+w, y+h), (0,0,255), 2) showImg("answer_sheet_img", answer_sheet_img) pts1 = np.float32([[x,y], [x+w, y], [x+w, y+h]]) pts2 = np.float32([[0,0], [w, 0], [w, h]]) ? M = cv2.getAffineTransform(pts1, pts2) sheet_threshold_copy = sheet_threshold.copy() dst = cv2.warpAffine(sheet_threshold_copy, M, (w, h)) showImg("dst", dst) print(answer_sheet_img.shape) part_sheet_img = answer_sheet_img[y:y+h, x:x+w] showImg("part_sheet_img", part_sheet_img) ? # 對答案區(qū)域灰度,二值,找輪廓 part_answer_gray = cv2.cvtColor(part_sheet_img, cv2.COLOR_BGR2GRAY) # 灰度 ret, threshold_answer = cv2.threshold(part_answer_gray, 175, 255, cv2.THRESH_BINARY) showImg("threshold_answer", threshold_answer) ? img, answer_cnts, x = cv2.findContours(threshold_answer, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) part_sheet_img_copy = part_sheet_img.copy() cv2.drawContours(part_sheet_img_copy, answer_cnts, -1, (0, 0, 255), 1) showImg("dst_copy", part_sheet_img_copy) ? # 對所有輪廓找外接矩形,想過濾掉不合適的矩形 print("畫矩形") answer_filter_cnts = [] answer_circles = [] img_ = part_sheet_img.copy() for cnt in answer_cnts: x, y, w, h = cv2.boundingRect(cnt) if 30<w<40 and 30<h<40: print(x, y, w, h) circle_x = int(x + w/2) circle_y = int(y+h/2) r = int((w+h)/4) answer_circles.append((circle_x, circle_y, r)) answer_filter_cnts.append(cnt) ? answer_filter_cnts = np.array(answer_filter_cnts) cv2.drawContours(img_, answer_filter_cnts, -1, (0, 0, 255), 1) # cv2.rectangle(img, (x, y), (x+w, y+h), (0,255,0), 2) showImg("img_", img_) print("geshu", len(answer_circles)) ? ? # 從answer_circles中取25個 mask_dict = {1:[],2:[], 3:[], 4:[],5:[]} # 一共不一定是25個圓,將圓按照題目行分類, sorted_y_answer_circles = sorted(answer_circles, key=lambda circle: circle[1]) print("sorted_y_answer_circles", sorted_y_answer_circles) set_num = 1 for index, circle in enumerate(sorted_y_answer_circles): if index == 0: mask_dict[1].append(circle) else: if circle[1] - sorted_y_answer_circles[index-1][1] > 30: set_num += 1 mask_dict[set_num].append(circle) else: mask_dict[set_num].append(circle) ? print("mask_dict", mask_dict) ? for k, mask_circle_list in mask_dict.items(): # 對每一個題目,保留五個答案,多余的舍去 if len(mask_circle_list) == 5: sorted_x_mask_circle_list = sorted(mask_circle_list, key=lambda x:x[0]) mask_dict[k]=sorted_x_mask_circle_list else: sorted_x_mask_circle_list = sorted(mask_circle_list, key=lambda x: x[0]) sorted_x_mask_circle_list_5 = [] for i, c in enumerate(sorted_x_mask_circle_list): if i == 0: sorted_x_mask_circle_list_5.append(c) else: if abs(c[0] - sorted_x_mask_circle_list[i-1][0]) < 10: pass else: sorted_x_mask_circle_list_5.append(c) mask_dict[k] = sorted_x_mask_circle_list_5 ? print("mask_dict", mask_dict) ? # mask_dict 分好組的按照順序的圈圈 ? # 做掩碼 mask_img = np.zeros_like(part_sheet_img, dtype='uint8') # 全黑圖 showImg("threshold_answer", threshold_answer) threshold_answer = np.array(threshold_answer) # mask_dict = sorted(mask_dict, key=lambda x: mask_dict.keys()) all_scores = [] # 所有答案處的評分 for exercise_num, circle_mask_list in mask_dict.items(): # 對于每一題 score_list = [] # 每一題的每個選項的評分,涂黑的為選擇的,值越接近0, 評分較低 for circle_mask in circle_mask_list: mask_img_copy = cv2.cvtColor(mask_img, cv2.COLOR_BGR2GRAY) # 做一個當前圓的掩碼: cv2.circle(mask_img_copy, (circle_mask[0], circle_mask[1]), circle_mask[2], (255, 255, 255), -1) print(threshold_answer.shape, mask_img_copy.shape) mask_img_ = cv2.bitwise_and(threshold_answer, threshold_answer, mask=mask_img_copy) score = mask_img_.sum() score_list.append(score) # showImg("mask_img_", mask_img_) all_scores.append(score_list) ? ? all_score_np = np.array(all_scores) s = np.argmin(all_score_np, axis=1) # 找評分最低處即為選擇項 ? answer_dict = { 0: "A", 1: "B", 2: "C", 3: "D", 4: "E" } ? for index, v in enumerate(s): print("第%s題的答案是%s" %(index+1, answer_dict[v]))
效果圖:
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
numpy中meshgrid和mgrid的區(qū)別和使用詳解
本文主要介紹了numpy中meshgrid和mgrid的區(qū)別和使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-02-02python統(tǒng)計RGB圖片某像素的個數(shù)案例
這篇文章主要介紹了python統(tǒng)計RGB圖片某像素的個數(shù)案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03在Python 3中緩存Exception對象會造成什么后果?
這篇文章主要介紹了在Python 3中緩存Exception對象到底會造成什么后果?下面帶著這個問題一起看看文章的解析,需要的朋友可以參考一下2021-12-12