Mùa COVID, thử xây dựng hệ thống chấm điểm trắc nghiệm tự động

Chào toàn thể anh em. Đang là mùa cao điểm COVID, nhà nhà người người thực hiện Work from home nên có tý thời gian. Hôm nay chúng ta cùng thử xây dựng hệ thống chấm điểm trắc nghiệm tự động để giúp đỡ các thầy cô nhé.

Ở đây mình cũng xin nói trước là ở mức độ cơ bản để các bạn nắm được cách thức làm việc, kết hợp các thủ thuật. Khi áp dụng thực tế sẽ cần nhiều biện pháp riêng, phù hợp với điều kiện thực tế của bài toán của các bạn nhé.

Phần 1 – Tư tưởng bài toán

Đề bài của bài toán này như sau:

  • Chúng ta sẽ chụp ảnh một form trắc nghiệm đã được học sinh tô màu chọn các ô đáp án.
  • Sau đó phần mềm tự động nhận dạng đáp án được chọn, tính điểm và hiển thị lên màn hình.

Ví dụ về một form trắc nghiệm như sau:

chấm điểm tự động

Bây giờ chúng ta cùng bắt đầu tìm cách làm nhé!

Phần 2 – Thuật toán cho bài toán chấm điểm tự động

Một số bài toán cần phải có các điểm định vị trên tờ giấy, một số khác thì cần phải kẻ bảng rõ ràng mới có thể định vị. Bài này mình làm linh hoạt một chút là sẽ ko cần điểm định vị, không cần kẻ bảng nhé.

Cách làm sẽ như sau:

  • Bước 1: Các bạn cần xử lý trường hợp chụp một tờ giấy thi trên mặt bàn.
  • Bước 2: Tìm contour và chúng ta cần xác định được đâu là tờ giấy, sau đó thực hiện crop và xoay tờ giấy cho thẳng ra. Phần này chúng ta tìm contour lớn thứ 2 (loại trừ contour lớn nhất là contour bao quanh bức ảnh) trong ảnh là okie.
  • Bước 3: Chúng ta thực hiện tìm các ô tick trong các câu hỏi. Với món này thì cứ duyệt hết contours và tìm các contour phù hợp với handcraft features như: w và h trên 30 pixel, và là hình tròn nghĩa là tỷ lệ giữa w/h tầm xấp xỉ 1.0 là được (cái này tùy bài sẽ do người dùng handmade nhé).
  • Bước 4: Thực hiện duyệt qua từng hàng (từng câu hỏi), kiểm tra xem người dùng chọn đúng/sai để tính điểm. Chúng ta duyệt theo từng hàng, xem ô nào được tô đen nhất thì ô đó là lựa chọn của người dùng và so sánh với đáp áp chúng ta đã có từ trước để quyết định đúng/sai nhé.

Phần 3 – Triển khai chương trình chấm điểm trắc nghiệm

Rồi, thuật toán đại khái là như vậy, bây giờ các bạn tải mã nguồn về so sánh giữa mã nguồn và thuật toán và sau đó là chạy thử nhé.

Các bạn tạo 1 project mới bằng Pycharm (khuyến nghị dùng món này để mỗi bài là một môi trường riêng, đỡ lỗi nhé, ai chưa có thì cài tại www.pycharm.org ). Các bạn tạo project xong thì vào thư mục venv gõ lệnh:

git clone https://github.com/thangnch/MiAI_Auto_Grading

Đợi chút source sẽ bay về, bây giờ các bạn thực hiện cài dặt các thư viện cần thiết:

pip install -r setup.txt

Okie done! Cài cắm xong bây giờ các bạn để ý sẽ có 2 file python:

  • File utils.py : Là file chứa các hàm phục vụ chương trình như vẽ chữ, sắp xếp contour, xoay hình….
  • File grade.py : Là file chính của chương trình sẽ thực hiện các bước trong thuật toán. Mình đã comment rất kỹ trong source để các bạn hiểu được.

Mình sẽ cùng tìm hiểu source file grade.py nhé. Đây là các bước xử lý thông thường với ảnh:

# 1. Doc anh, chuyen thanh anh xam
image = cv2.imread("omr_test_02.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

 
# 2. Threshold de
thresh = cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,            cv2.THRESH_BINARY_INV,31,3)
cv2.imshow("Anh tai buoc 2",thresh)
cv2.waitKey()

Sau đó chúng ta tiến hành lấy contour xung quanh tờ giấy va crop nó riêng ra:

# 3. Tim khung ben ngoai de tach van ban khoi nen
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=lambda x: cv2.contourArea(x),reverse=True)
approx = cv2.approxPolyDP(contours[1], 0.01 * cv2.arcLength(contours[1], True), True)
rect = cv2.minAreaRect(contours[1])
box = cv2.boxPoints(rect);

Tiếp theo chúng ta thực hiện phép xoay 4 góc để tờ giấy thẳng ra để sau đó xử lý tiếp:

# 4. Thuc hien transform de xoay van ban
corner = find_corner_by_rotated_rect(box,approx)
image = four_point_transform(image,corner)
wrap = four_point_transform(thresh,corner)
cv2.imshow("Anh sau buoc 4",wrap)
cv2.waitKey()

Việc còn lại bây giờ khá đơn giản, ta tìm tất cả các contour thỏa mãn điều kiện là hình tròn trong hình và kiểm tra xem đâu là phương án tick của người dùng và so sánh với đáp án:

# 5. Tim cac o tick trong hinh
contours, _ = cv2.findContours(wrap, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
tickcontours = []
# loop over the contours
for c in contours:
    (x, y, w, h) = cv2.boundingRect(c)
    ar = w / float(h)
    if w >= 30 and h >= 30 and 0.8 <= ar <= 1.2:
        tickcontours.append(c)
# 6. So sanh cac o tick voi dap an

# Dinh nghia dap an
right_anser = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1,5: 1,6: 0,7: 4}

# Sap xep cac contour theo hang
tickcontours = sort_contours(tickcontours, method="top-to-bottom")[0]

correct = 0

for (q, i) in enumerate(np.arange(0, len(tickcontours), 5)):

    # Dinh nghia mau rieng cho tung cau hoi
    color = (random.randint(0, 255),random.randint(0, 255),random.randint(0, 255))
    # Sap xep cac contour theo cot
    cnts = sort_contours(tickcontours[i:i + 5])[0]
    #cv2.drawContours(image, cnts, -1, color, 3)

    choice = (0,0)
    total = 0
    # Duyet qua cac contour trong hang
    for (j, c) in enumerate(cnts):

        # Tao mask de xem muc do to mau cua contour
        mask = np.zeros(wrap.shape, dtype="uint8")
        cv2.drawContours(mask, [c], -1, 255, -1)
        mask = cv2.bitwise_and(wrap, wrap, mask=mask)
        total = cv2.countNonZero(mask)

        # Lap de chon contour to mau dam nhat
        if total > choice[0]:
            choice = (total, j)

    # Lay dap an cua cau hien tai
    current_right = right_anser[q]
    # Kiem tra voi lua chon cua nguoi dung
    if current_right == choice[1]:
        # Neu dung Thi to mau xanh
        color = (0, 255, 0)
        correct += 1
    else:
        # Neu sai Thi to mau do
        color = (0, 0, 255)
    # Ve ket qua len anh
    cv2.drawContours(image, [cnts[current_right]], -1, color, 3)

Nếu đọc mà có khó khăn gì hoặc cài bị lỗi các bạn cứ post lên Group trao đổi, chia sẻ: https://facebook.com/groups/miaigroup để cùng thảo luận nhé.

Còn bây giờ, chạy thử thôi, các bạn gõ lệnh

python grade.py

Chương trình chạy sẽ in ra ảnh trong từng bước để các bạn theo dõi:

Sau khi threshold ảnh gốc
Sau khi thực hiện xoay ảnh
Sau khi chấm điểm

Các bạn để ý ảnh cuối, các ô khoanh đỏ/xanh là các ô đáp án của từng câu hỏi. Nếu người dùng chọn đúng sẽ khoanh màu xanh, người dùng chọn sai thì sẽ khoanh màu đỏ. Ví dụ:

  • Câu 1: Đáp án đúng là 2, người dùng chọn 3 nên là sai. Màu đỏ
  • Câu 6: Đấp án đúng là 2, người dùng chọn 2 nên là đúng. Màu xanh

Như vậy mình đã hướng dẫn các bạn làm phần mềm chấm điểm trắc nghiệm tự động. Chúng ta sẽ chụp ảnh một form trắc nghiệm đã được học sinh tô màu chọn các ô đáp án. Sau đó phần mềm tự động nhận dạng đáp án được chọn, tính điểm và hiển thị lên màn hình.

Mình xin dừng bài này tại đây và hẹn gặp lại các bạn trong các bài tiếp theo nhé!

Chúc các bạn thành công!

Hãy join cùng cộng đồng Mì AI nhé!

Fanpage: http://facebook.com/miaiblog
Group trao đổi, chia sẻ: https://www.facebook.com/groups/miaigroup
Website: https://miai.vn
Youtube: http://bit.ly/miaiyoutube

Cảm ơn bài tham khảo rất hay của tác giảby Adrian Rosebrock.

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *