在教育領域,選擇題的批改工作通常較為繁瑣且重復性高。為了提高批改效率,我們可以利用計算機視覺技術,通過 OpenCV 實現選擇題的自動批改。本文將詳細介紹如何使用 Python 和 OpenCV 實現一個簡單的選擇題自動批改系統。
1. 項目背景
選擇題的批改通常是通過人工檢查答題卡上的涂黑點來完成的。這種方式不僅耗時,還容易出錯。如果能夠通過計算機自動識別答題卡上的涂黑點,并與標準答案進行比對,就可以大大提高批改效率。OpenCV 是一個強大的計算機視覺庫,提供了豐富的圖像處理功能,非常適合用于實現這種自動批改系統。
2. 系統實現步驟
2.1 圖像預處理
首先,我們需要讀取答題卡的圖像,并對其進行預處理,以便后續的輪廓檢測和透視變換。預處理步驟包括灰度化、高斯模糊和邊緣檢測。
image = cv2.imread(r'./images/test_01.png')
contours_img = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
cv_show('blurred', blurred)
edged = cv2.Canny(blurred, 75, 200)
cv_show('edged', edged)
- 灰度化:將彩色圖像轉換為灰度圖像,減少數據量,便于后續處理。
- 高斯模糊:去除圖像中的噪聲,使圖像更加平滑,有助于邊緣檢測。
- 邊緣檢測:使用 Canny 算法檢測圖像中的邊緣,為輪廓檢測做準備。
2.2 輪廓檢測與透視變換
接下來,我們需要檢測答題卡的輪廓,并對其進行透視變換,以便將答題卡的圖像轉換為一個規則的矩形圖像。這一步是實現自動批改的關鍵。
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3)
cv_show('contours_img', contours_img)
docCnt = Nonecnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:peri = cv2.arcLength(c, True)approx = cv2.approxPolyDP(c, 0.02 * peri, True)if len(approx) == 4:docCnt = approxbreakwarped_t = four_point_transform(image, docCnt.reshape(4,2))
warped_new = warped_t.copy()
cv_show('warped', warped_t)
- 輪廓檢測:使用
cv2.findContours
函數檢測圖像中的輪廓,并按輪廓面積從大到小排序。 - 透視變換:通過
four_point_transform
函數對答題卡的輪廓進行透視變換,將其轉換為規則的矩形圖像。
2.3 閾值處理與圓圈輪廓檢測
為了識別答題卡上的涂黑點,我們需要對透視變換后的圖像進行閾值處理,并檢測圓圈輪廓。
warped = cv2.cvtColor(warped_t, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv_show('thresh', thresh)
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
warped_Contours = cv2.drawContours(warped_t, cnts, -1, (0, 255, 0), 1)
cv_show('warped_Contours', warped_Contours)
- 閾值處理:使用 Otsu 方法自動計算閾值,并將圖像轉換為二值圖像。
- 圓圈輪廓檢測:檢測二值圖像中的輪廓,并篩選出符合圓圈特征的輪廓。
2.4 答案識別與評分
最后,我們需要識別每個選項的涂黑情況,并與標準答案進行比對,計算得分。
questionCnts = []
for c in cnts:(x, y, w, h) = cv2.boundingRect(c)ar = w / float(h)if w >= 20 and h >= 20 and 0.9 <= ar <= 1.1:questionCnts.append(c)questionCnts = sort_contours(questionCnts, method="top-to-bottom")[0]
correct = 0for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):cnts = sort_contours(questionCnts[i:i + 5])[0]bubbled = Nonefor (j, c) in enumerate(cnts):mask = np.zeros(thresh.shape, dtype="uint8")cv2.drawContours(mask, [c], -1, 255, -1)cv_show('mask', mask)thresh_mask_and = cv2.bitwise_and(thresh, thresh, mask=mask)cv_show('thresh_mask_and', thresh_mask_and)total = cv2.countNonZero(thresh_mask_and)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 += 1cv2.drawContours(warped_new, [cnts[k]], -1, color, 3)cv_show('warpeding', warped_new)score = (correct / 5.0) * 100
print("[INFO score: {:.2f}%".format(score))
cv2.putText(warped_new, "{:.2f}%".format(score), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
cv2.imshow("Original", image)
cv2.imshow("Exam", warped_new)
cv2.waitKey(0)
- 答案識別:通過掩膜操作和非零點計數,識別每個選項的涂黑情況。
- 評分:將識別出的答案與標準答案進行比對,計算得分,并在圖像上標注正確和錯誤的選項。
3. 實驗結果
通過上述步驟,我們成功實現了選擇題的自動批改。實驗結果表明,該系統能夠準確識別答題卡上的涂黑點,并與標準答案進行比對,計算出得分。以下是實驗結果的示例:
- 原始圖像:顯示答題卡的原始圖像。
- 透視變換后的圖像:顯示經過透視變換后的答題卡圖像。
- 閾值處理后的圖像:顯示經過閾值處理后的二值圖像。
- 最終結果:顯示批改后的答題卡圖像,正確選項用綠色標記,錯誤選項用紅色標記,并顯示得分。
運行結果
4. 總結與展望
本文介紹了一個基于 OpenCV 的選擇題自動批改系統。通過圖像預處理、輪廓檢測、透視變換、閾值處理和答案識別等步驟,實現了對答題卡的自動批改。該系統能夠大大提高批改效率,減少人工操作的繁瑣性。
然而,該系統仍有一些可以改進的地方。例如,目前系統只能處理單選題,對于多選題的識別和批改還需要進一步優化。此外,系統的魯棒性還可以進一步提高,以應對不同光照條件和答題卡質量的情況。
未來,我們可以探索更多計算機視覺技術在教育領域的應用,例如自動識別手寫文字、自動批改簡答題等,為教育信息化做出更大的貢獻。