Python+Opencv实现自动化阅卷
目錄
- 一、什么是自動化閱卷/網上閱卷?
- 二、自動化閱卷有哪些優勢?
- 三、 自動化閱卷的實現流程
- 四、自動化閱卷代碼實戰
- 五、自動化閱卷可視化及分析
- 六、自動化閱卷效果展示
- 七、問題探討
- 參考資料
- 注意事項
??在我們的日常生活中有很多自動化閱卷的需求,比如我們的期中考試、期末考試、中考、高考、四級、六級等等。總而言之,現實場景中我們有很多的考試,但是每一次考完試后,焦慮的不僅僅是學生,還有老師!老師們需要夜以繼日的去閱卷,盡快得出學生的考試成績,這是一個費人費力但又是剛需的一個任務。慶幸的是當前這個任務基本上已經被自動化啦,本文的任務就是來理解這其中的奧秘!
一、什么是自動化閱卷/網上閱卷?
百度的定義-網上閱卷全稱是網上閱卷系統,是指以計算機網絡技術和電子掃描技術為依托,實現客觀題自動閱卷,主觀題網上評卷的一種現代計算機系統。
這里面有幾點需要進行說明:
- 當前的網上閱卷系統還是部分自動化的,即智能實現客觀題目的自動閱卷,最典型的就是選擇題!而主觀題還是需要進行網上閱卷的。
- 當前的網上閱卷系統主要依托于兩個儀器,計算機+電子掃描儀,電子掃描儀的任務是將學生的答題卡錄入到電腦中去,充當了攝像機的功能。
二、自動化閱卷有哪些優勢?
??正如文章開頭所講,現實的場景中我們有各種各樣的考試,老師們需要進行大量的閱卷工作,因而解決這個問題具有重大的意義。
三、 自動化閱卷的實現流程
步驟1-檢測圖片中的答題卡;
步驟2-采取透視變換取得答題卡自上而下的俯視圖.;
步驟3-從第二步結果中獲取泡泡集(例如可能的答案選項);
步驟4-按行進行排序處理;
步驟5-確認每行用戶填寫的答案
步驟6-查找正確的答案,判斷用戶選擇是否正確
步驟7-遍歷所有的問題,重復以上的步驟。
四、自動化閱卷代碼實戰
# coding=utf-8 # 導入一些python包 from imutils.perspective import four_point_transform from imutils import contours import numpy as np import argparse import imutils import cv2# 配置一些需要改變的參數 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True,help="path to the input image") args = vars(ap.parse_args())# 定義將問題編號映射到正確答案的答案鍵,即正確的問題編號 ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}# 讀取輸入圖片 image = cv2.imread(args["image"]) # 輸入圖片灰度化 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 進行高斯濾波 blurred = cv2.GaussianBlur(gray, (5, 5), 0) # 進行邊緣檢測處理 edged = cv2.Canny(blurred, 75, 200)# 在邊緣圖像中發現輪廓 cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) docCnt = None# 確保至少發現一個輪廓 if len(cnts) > 0:# 根據輪廓的大小進行排序cnts = sorted(cnts, key=cv2.contourArea, reverse=True)# 依次遍歷每一個輪廓for c in cnts:# 對整個輪廓做近似peri = cv2.arcLength(c, True)approx = cv2.approxPolyDP(c, 0.02 * peri, True)# 如果我們在近似輪廓中發現4個點,表明我們發現了答題卡if len(approx) == 4:docCnt = approxbreak# 將變換關系應用到原始的輸入圖像和灰度圖像中,從而獲得一個答題卡的鳥瞰圖 paper = four_point_transform(image, docCnt.reshape(4, 2)) warped = four_point_transform(gray, docCnt.reshape(4, 2))# 在warped圖像上面使用Otsu方法進行閾值分割 thresh = cv2.threshold(warped, 0, 255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]# 在二值圖像中尋找輪廓 cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) questionCnts = []# 遍歷每一個輪廓 for c in cnts:# 計算輪廓的BB,并根據BB獲得橫縱比(x, y, w, h) = cv2.boundingRect(c)ar = w / float(h)# 為了將輪廓標記為問題,區域應足夠寬、足夠高,且長寬比約等于1# 即選擇滿足條件的結果if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:questionCnts.append(c)# 對問題輪廓進行排序 questionCnts = contours.sort_contours(questionCnts,method="top-to-bottom")[0] correct = 0# 對于每一個問題而言,有5個可能的答案,遍歷每一個可能的答案 for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):# 對每一個問題的5個答案進行排序cnts = contours.sort_contours(questionCnts[i:i + 5])[0]bubbled = None# 循環遍歷每一個輪廓for (j, c) in enumerate(cnts):# 為每行的答案創建一個mask模板mask = np.zeros(thresh.shape, dtype="uint8")cv2.drawContours(mask, [c], -1, 255, -1)# 將mask應用到閾值圖像中,然后計算氣泡區域中的非零像素數mask = cv2.bitwise_and(thresh, thresh, mask=mask)total = cv2.countNonZero(mask)# 如果它大于該非0像素,我們認為它是答案if bubbled is None or total > bubbled[0]:bubbled = (total, j)# 初始化輪廓顏色和正確答案的索引color = (0, 0, 255)k = ANSWER_KEY[q]# 將用戶的答案和標準答案進行對比,進行統計if k == bubbled[1]:color = (0, 255, 0)correct += 1# 在圖像中繪制結果cv2.drawContours(paper, [cnts[k]], -1, color, 3)# 計算正確率并打印得分 score = (correct / 5.0) * 100 print("[INFO] score: {:.2f}%".format(score)) # 顯示原始圖片和測試后的結果并顯示得分 cv2.putText(paper, "{:.2f}%".format(score), (10, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2) cv2.imshow("Original", image) cv2.imshow("Exam", paper) cv2.waitKey(0)五、自動化閱卷可視化及分析
??上圖展示了整個算法運行的一些中間輸出結果,其中第1行第1列表示輸入的原圖,對應于程序中的image;第1行第2列表示灰度化的結果,對應于程序中的gray;第1行第3列表示邊緣檢測的結果,對應于程序中的edged;第1行第4列是對原圖中所有檢測到的輪廓的可視化,我們可以觀察到基本上所有的答題區域都可以檢測到;第2行第1列表示的使用坐標變換后的原圖,即從原圖中裁剪出來的答題卡圖片,對應于程序中的paper;第2行第2列表示的灰度化的圖片的變換結果,對應于程序中的warped;第2行第3列表示的在paper中檢測到的所有輪廓,我們需要的答題區域都可以檢測出來,答過的結果和沒有答過的結果差距較大;第2行第2列表示最終的輸出結果,可以看出該答題卡的答案和正確的答案完全符合,因此得100分。
??上圖展示了整個mask的生成過程,使用.gif動態圖進行展示,我們可以觀察到整個mask從上到下,從左到右遍歷所有的答題位置,并判斷當前的結果是否和標準答案相同。
六、自動化閱卷效果展示
??上面幾幅圖展示了整個算法的實際測試效果,整體來看,整個算法的準確率高,基本可以滿足實時場景的需要。
七、問題探討
??盡管從上面的測試結果來看該算法比較魯棒、可靠,但是在現實場景中會遇到一些其它的問題,比如
1、空白答題卡
??對于這種情況而言,當計算cv2.countNonZero時,我們可以設置一個最小的閾值(108行),如果這個值足夠大,我們就可以將泡泡標記為"已填涂".相反,如果total太小,我們就跳過那個泡泡.如果直到行結尾,沒有泡泡具有足夠大的閾值計數,就將該問題標記為測試者"跳過".
2、每個問題填寫了多個答案
??對于問題2而言,我們采用類似的方法,我們追蹤一個問題具有total的泡泡數量是否超過預定義值,我們將其標記為無效問題或者是錯誤答案。
3、對于復雜的答題卡該如何處理呢?
??上圖僅僅是答題卡的一種,對于答題卡而言,基本每一個考試會有一種類型,對于這些類型我們不可能分別設計一個算法吧,這是基于深度學習的方法就具有獨特的優勢啦。具體的效果大家可以去實現并測試一些歐。
參考資料
1、參考博客
注意事項
[1] 該博客是本人原創博客,如果您對該博客感興趣,想要轉載該博客,請與我聯系(qq郵箱:1575262785@qq.com),我會在第一時間回復大家,謝謝大家的關注。
[2] 由于個人能力有限,該博客可能存在很多的問題,希望大家能夠提出改進意見。
[3] 如果您在閱讀本博客時遇到不理解的地方,希望您可以聯系我,我會及時的回復您,和您交流想法和意見,謝謝。
[4] 本文測試的圖片可以通過該鏈接進行下載。測試圖片鏈接- 提取碼:mj3s
[5] 本人業余時間承接各種本科畢設設計和各種小項目,包括圖像處理(數據挖掘、機器學習、深度學習等)、matlab仿真、python算法及仿真等,有需要的請加QQ:1575262785詳聊!!!
總結
以上是生活随笔為你收集整理的Python+Opencv实现自动化阅卷的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win10截屏动画失效怎么恢复 Win1
- 下一篇: Python+Opencv建立一个文档扫