Intelligent Answer Sheet Recognition System Based on Python+OpenCV - Deep Learning and Image Recognition Algorithm Application (including all Python project source code) + training and test data sets


insert image description here

foreword

Based on Python and OpenCV image processing library, this project develops an answer card recognition system under the Windows platform. The system uses sophisticated computer vision algorithms to realize the function of identifying answer sheets in batches and exporting the information to an Excel table. This solution makes the marking process of answer sheets easy, efficient and accurate.

First of all, we use the Python language as the development basis, combined with the OpenCV image processing library, to provide the system with powerful image processing and analysis capabilities. This allowed us to accurately locate the answer sheet in the image, detect filled areas, and identify filled content.

Developing under the Windows platform, we can make full use of the functions of the operating system to ensure the stability and compatibility of the system in the user environment.

The computer vision algorithms in the system are carefully designed to reliably recognize the filled-in information on the answer sheet. From the scanned image, we were able to determine which options were filled in and extract this information with precision.

Once the information is extracted, the system can export the data to an Excel table, realizing efficient data sorting and statistical functions. This makes the marking process highly automated, reducing tedious manual work and reducing the risk of errors.

In summary, the development of this project utilizes the powerful functions of the Python language and the OpenCV image processing library to realize a comprehensive answer card recognition system. Through efficient image processing and data export functions, the system not only reduces the burden of judging papers, but also greatly improves the accuracy and efficiency of recognition. This has great practical value for educational institutions and examination institutions.

overall design

This part includes the overall structure diagram of the system and the system flow chart.

System overall structure diagram

The overall structure of the system is shown in the figure.

insert image description here

System flow chart

The system flow is shown in the figure.

insert image description here

operating environment

This part includes Python environment, OpenCV environment, image processing toolkit, requests, base64 and xlwt modules.

Python environment

Requires Python 3.6 and above configuration. Download Anaconda in the Windows environment to complete the required configuration of Python. The download address is https://www.anaconda.com/ .

PyCharm installation

Download the installation package for the corresponding machine from the website https://www.jetbrains.com/pycharm/ . Use the free community version to download the exe format file.

OpenCV environment

Install OpenCV 3.4.15 in PyCharm, select Interpreter in Project under Settings, click the plus sign in the upper right corner, search for the library to be added, select Specifyversion and 3.4.15, and click the OK button.

Install imutils, requests and base64 as above. By pip install xlwtinstalling the xlwt module, the function of writing data into an Excel table is realized.

module implementation

This project includes 4 modules: information recognition, Excel export, graphical user interface and handwriting recognition. The functions and related codes of each module are introduced below.

1. Information identification

Based on the OpenCV algorithm, the detection of option information and student identity information in the picture is realized. Before starting to write the system, use Photoshop software to draw the answer sheet used, as shown in the figure.

insert image description here
There are a total of 50 multiple-choice questions in the answer sheet, and each correct answer will get 2 points. If you miss a choice, you will be prompted with "Missed Choice", and if you choose multiple choices, you will be prompted with "Multiple Choices". Finally, a dictionary of results and statistical error options will be returned.

Information such as colleges, classes, student numbers, etc. is "painted out". Compared with the "written out" method in the first version of the system, the recognition accuracy is higher and the code is simpler.

The specific description is as follows:
(1) Using get_positionthe function, through the above information identification algorithm, get the barycenter coordinate array Info of the painted outline of the identity information and the barycentric coordinate array Answer of the painted outline of the option information.

Image preprocessing: After filtering and denoising the image, perform perspective transformation and adjust it to a unified specification of 2400X 2800, as shown in Figures 1 to 9.

The relevant code is as follows:

#导入相应数据包
import cv2
import matplotlib.pyplot as plt
import imutils
import numpy as np
def cv_show(name, img):   #展示图片
    cv2.namedWindow(name, 0)
    cv2.imshow(name, img)
    cv2.waitKey(0)
cv2.destroyAllWindows()
def order_points(pts):    #对4点进行排序
	#共4个坐标点
	rect = np.zeros((4, 2), dtype = "float32")
	#按顺序找到对应坐标0、1、2、3分别是左上、右上、右下、左下
	#计算左上和右下
	s = pts.sum(axis = 1)
	rect[0] = pts[np.argmin(s)]
	rect[2] = pts[np.argmax(s)]
	#计算右上和左下
	diff = np.diff(pts, axis = 1)
	rect[1] = pts[np.argmin(diff)]
	rect[3] = pts[np.argmax(diff)]
	return rect
def toushi_transform(image, pts): #输入原始图像和4角点坐标
	#获取输入坐标点
	rect =  order_points(pts)
	(tl, tr, br, bl) = rect
	#计算输入的w和h值
	widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
	widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
	maxWidth = max(int(widthA), int(widthB))
	heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
	heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
	maxHeight = max(int(heightA), int(heightB))
	#变换后对应坐标位置
	dst = np.array([
		[0, 0],
		[maxWidth - 1, 0],
		[maxWidth - 1, maxHeight - 1],
		[0, maxHeight - 1]], dtype = "float32")
	#计算变换矩阵
	print("原始四点坐标:\n",rect,"\n变换后四角点坐标:\n",dst)
	M = cv2.getPerspectiveTransform(rect, dst)
	print("变换矩阵:",M)
	warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
	#返回变换后结果
	return warped
def get_postion(image_name):
    #读入图片
image = cv2.imread(image_name)
#预处理
#转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#高斯滤波
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
#自适应二值化方法
blurred=cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,51,2)
cv_show('blurred',blurred)
edged = cv2.Canny(blurred, 10, 100)
#为透视变换做准备
    cnts = cv2.findContours(edged, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if imutils.is_cv2() else cnts[1]
    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 = approx
                break
    newimage=image.copy()
    for i in docCnt:
        #circle函数为在图像上作图,新建一个图像用来演示4角选取
        cv2.circle(newimage, (i[0][0],i[0][1]), 50, (255, 0, 0), -1)
    #透视变换
    paper = toushi_transform(image, docCnt.reshape(4, 2))
    warped = toushi_transform(gray, docCnt.reshape(4, 2))
        #cv_show('warped',warped)
    #对灰度图应用二值化算法
thresh=cv2.adaptiveThreshold(warped,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,53,2)
    #重塑可能用到的图像
    width1=2400
    height1=2800
    #转换成标准大小:2400*2800
    thresh = cv2.resize(thresh, (width1, height1), cv2.INTER_LANCZOS4)
    paper = cv2.resize(paper, (width1, height1), cv2.INTER_LANCZOS4)
    warped = cv2.resize(warped, (width1, height1), cv2.INTER_LANCZOS4)
cv2.imwrite("warped.jpg", warped)
识别被涂选项轮廓的重心相关代码如下:
#透视变换、resize成2400*2800的图片
    #均值滤波
    ChQImg = cv2.blur(thresh, (23, 23))
    #二进制二值化
    ChQImg = cv2.threshold(ChQImg, 100, 225, cv2.THRESH_BINARY)[1]
    #cv_show('ChQImg',ChQImg)
    #在二值图像中查找轮廓
    cnts = cv2.findContours(ChQImg, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if imutils.is_cv2() else cnts[1]
    Answer=[]
    Info=[]
    for c in cnts:
    #计算轮廓的边界框,利用边界框数据计算宽高比
        (x, y, w, h) = cv2.boundingRect(c)
        if (x > 1200 and y > 1700): continue  #排除右下角区域的误选
    #if (w > 60 &h > 20)and y>900 and y<2000:
        if (95 > w > 60) and y > 880 and y < 2050:
            M = cv2.moments(c)
            cX = int(M["m10"] / M["m00"])
            cY = int(M["m01"] / M["m00"])
            #绘制中心及其轮廓
            cv2.drawContours(paper, c, -1, (0, 0, 255), 5, lineType=0)
            cv2.circle(paper, (cX, cY), 7, (255, 255, 255), -1)
            #保存题目坐标信息
            Answer.append((cX, cY))
        if ( 90> w > 55) and y<800 and x<1750 :
            M = cv2.moments(c)
            cX = int(M["m10"] / M["m00"])
            cY = int(M["m01"] / M["m00"])
            #绘制中心及其轮廓
            cv2.drawContours(paper, c, -1, (0, 255, 0), 5, lineType=0)
            cv2.circle(paper, (cX, cY), 7, (255, 255, 255), -1)
            #保存题目坐标信息
            Info.append((cX, cY))
cv_show('paper',paper)
    cv2.imwrite("paper.jpg", paper)
    imm = cv2.resize(paper, (180, 210), cv2.INTER_LANCZOS4)
    cv2.imwrite("imm.jpg", imm)
    print(Answer)
    print(len(Answer))
    print(Info)
return Info,Answer

insert image description here

Figure 1 read picture

insert image description here

Figure 2 The image after grayscale processing

insert image description here

Figure 3 The picture after denoising by Gaussian filter

insert image description here

Figure 4 The picture after binarization

insert image description here

Figure 5 Canny filtered picture

insert image description here

Figure 6 The picture after perspective transformation and binarization

insert image description here

Figure 7 Grayscale image after perspective transformation

insert image description here

Figure 8 Binarization results after resizing

insert image description here

Figure 9 The final result map Take the test picture as an example, and return the coordinates of the center of gravity of the option contour Answer:

[ (977, 1992),(165, 1992),(523, 1926),(861,1925 ),( 1097,1859 ),(403,1853 ),(978,1790),( 284, 1784 ),(861,1717),(166,1716),(2239, 1643),( 1544, 1638),(978, 1631),(406, 1629),(2237, 1572),(1542, 1569),(286, 1557 ),( 859,1561 ),( 2238,1503 ),(1422,1497),(167,1486 ),(739,1490),( 1306, 1428 ),(2118, 1432),(1095, 1424),(523,1417),( 1657,1362), (1997,1360), (976,1359), (405,1347),(1999,1273),(1424,1264),( 738,1264),(165,1256) ,(1303, 1200) ,(1877, 1199) ,(1094,1199),( 521, 1189), ( 2242,1130),(976 ,1129),(1660, 1128) ,(402,1118),(1542, 1062),(2123,1060) ,(853, 1058),( 282,1049),( 2000,990),(1423,991) ,(161, 976),(734, 982) ]

50 total, matching the 50 options painted.

Return the center of gravity coordinates of the profile of personal information Info: [ (1531, 528) , (1218, 238), (336, 239), (889, 235), (437, 167), (992, 165) , (1428, 162) , (1634, 96) ], a total of 8 points, including 2 confirmed colleges, 2 confirmed classes, 3 confirmed student numbers, and 1 confirmed student number.

(2) Use explain ()the function to explain the coordinates of the center of gravity of the profile of personal information. Returns the corresponding college, class and student ID. During preprocessing, the answer sheets are taken out of the captured pictures through perspective transformation, and the pictures are adjusted to the specifications of 2400 X 2800, as shown in Figure 10 and Figure 11.

insert image description here

Figure 10 The system reads in pictures

insert image description here

Figure 11 Preprocessed picture

The location of each information is basically unchanged. Use Photoshop to view the pixel position coordinates, and repeatedly adjust the boundary parameters, as shown in the figure below.

insert image description here

Figure 12 Pixel segmentation of personal information area

Determine the image pixel coordinates of the center of gravity of the contour in the above information array. Judging the information type (student number, class or college) according to the interval of the x-coordinate of the center of gravity; judging the size of the number according to the interval of the y-coordinate of the center of gravity:

def judge(x,y):
    xt0=[285,385,485, 850,940,1040, 1385,1480,1580,1680]
    yt0=[60,120,195,265,340,410,480,555,625,700,756]
flagy=-1
    flagx=-1
    for j in range(10):
        if yt0[j]<y and y<yt0[j+1]:
            flagy=j
    for i in range(7):
        if i<=1:
            if xt0[i]<x and x<xt0[i+1]:
                flagx=i
        elif i<=3:
            if xt0[i+1]<x and x<xt0[i+2]:
                flagx=i
        else:
            if xt0[i+2]<x and x<xt0[i+3]:
                flagx=i
return flagx,flagy
def explain(Info):
    id={
    
    }
    for item in Info:
        if item[0]!=-1 or item[1]!=-1:
            pos,num=judge(item[0],item[1])
            id[pos]=num
    sch_num=id[0]*10+id[1]
    cls_num=id[2]*10+id[3]
    stu_num=id[4]*100+id[5]*10+id[6]
    print("学号:",sch_num,"班级:",cls_num,"学号:",stu_num)
return sch_num,cls_num,stu_num

Take the test picture as an example to return the result—college: 21, class: 21, student number: 160.

(3) Use the calculate () function to interpret the coordinates of the center of gravity of the option outline. Return a dictionary containing the corresponding question numbers and options, and return the prompts of "overpainting" and "leaking paint" if you encounter overpainting or missing painting. Also use Photoshop to view the pixel position coordinates, and repeatedly adjust the boundary parameters, as shown in the figure below.

insert image description here

Figure 13 Answer sheet pixel region segmentation

Write the judgey0() function to judge the question number and the judgex0 function to judge the options. According to the characteristics that every four options are in a pile, do division and take the remainder, and use the judge0() function to match the question number with the painted options.

The relevant code is as follows:

def judgey0(y):
    if (y / 5 < 1):
        return  y + 1
    elif y / 5 < 2 and y/5>=1:
        return y % 5 + 20 + 1
    else:
        return y % 5 + 40 + 1
def judgex0(x):
    if(x%5==1):
        return 'A'
    elif(x%5==2):
        return 'B'
    elif(x%5==3):
        return 'C'
    elif(x%5==4):
        return 'D'
def judge0(x,y):   #返回题号和答案
    if x/5<1 :
        #print(judgey0(y))
        return judgey0(y),judgex0(x)
    elif x/5<2 and x/5>=1:
        #print(judgey0(y)+5)
        return judgey0(y)+5,judgex0(x)
    elif x/5<3 and x/5>=2:
        #print(judgey0(y)+10)
        return judgey0(y)+10,judgex0(x)
    else:
        #print(judgey0(y)+15)
        return judgey0(y)+15,judgex0(x)
def calculate(Answer):
    xt1 = [0, 90, 220, 350, 455, 575, 680, 800, 920, 1040, 1160, 1260, 1370, 1490, 1600, 1720, 1830, 1940, 2060, 2180, 2330]#横向划分点
    yt1 = [960, 1027, 1100, 1165, 1235, 1300, 1385, 1465, 1536, 1600, 1655, 1755, 1820, 1885, 1960, 2040]#纵向划分点
    ans_dict = {
    
    }
    for i in Answer:
        for j in range(0, len(xt1) - 1):
            if i[0] > xt1[j] and i[0] < xt1[j + 1]:
                for k in range(0, len(yt1) - 1):
                    if i[1] > yt1[k] and i[1] < yt1[k + 1]:
                        a, b = judge0(j, k)
                        if (a in ans_dict.keys()):
                            ans_dict[a]='多选' #之前有被选过,判多选
                        else:
                            ans_dict[a] = b
                        break
    print('ans:',ans_dict)
return ans_dict

According to the interval where the coordinates of the center of gravity are located, the corresponding question number and options are obtained. Take the test picture as an example, return the dictionary with option information ans:{50: 'C' ,45: 'A',44: 'D',49: 'B' ,48: 'D',43: 'C' , 47: 'C', 42: 'B',46: 'B', 41 : 'A', 40: 'D', 35: 'C' ,30:'C',25:'C',39: 'D',34:'C',24:'B',29:'B',38:'D',33:'B',23:'A',28:'A',32:'A ',37:'C',27:'D',22:'D',31:'D',36:'B',26:'C',21:'C',20:'B', 15:'B',10:'A',5:'A', 14:'A', 19:'A', 9:'D',4:'D' ,18:'D',8: 'C',13:'D',3:'C',12:'C',17:'C',7:'B',2:'B',16:'B',11:'B ',1:'A',6:'A'}. Where ans[question number]=painted answer.

(4) Use sumall()the function to summarize the above functions, compare the correct answer with the student's scribbled answer, and return to the college, class, student number, score, and wrong question to complete the information identification function.

def sumall(image_name,true_ans=true_ans):
    Info,Answer=get_postion(image_name)        #拿到信息轮廓数组
    sch_num, cls_num, stu_num=explain(Info)   #解释个人信息		
    ans=calculate(Answer)					   #判断所涂选项
    score=0
    false_ans={
    
    }
    for i in range(1,len(true_ans)+1):
        if (i in ans.keys()):
            if(ans[i]==true_ans[i]):
                score+=2
            else:
                false_ans[i]=ans[i]
        else:
            false_ans[i]='漏选'
    print(false_ans)
return sch_num,cls_num,stu_num,score,false_ans

2. Excel export module

The system uses the data dictionary to record the information for each recognition, and the data dictionary is initialized as follows: data={"序号": ["学 院","班级","学号","成绩","错题"]}, use xlwt to export the information in the data dictionary to the Excel table named data.xls under the current path.

The relevant code is as follows:

import xlrd,xlwt,os
def set_stlye(name,height,bold=False):
    #初始化样式
    style = xlwt.XFStyle()
    #创建字体
    font = xlwt.Font()
    font.bold = bold
    font.colour_index = 4
    font.height = height
    font.name = name
    style.font = font
return style
def write_excel(data):
    if os.path.exists("data.xls"):
        os.remove("data.xls")
    book = xlwt.Workbook(encoding='utf-8')  #创建Workbook,相当于创建Excel
    #创建sheet,Sheet1为表的名字,cell_overwrite_ok为覆盖单元格
    sheet1 = book.add_sheet(u'Sheet1', cell_overwrite_ok=True)
    r = 0
    for i, j in data.items():  #i表示data中的key,j表示data中的value
        le = len(j)  #values返回的列表长度
        if r == 0:
            sheet1.write(r, 0, i,set_stlye("Time New Roman",220,True))  
#添加第 0 行 0 列数据单元格背景设为黄色
        else:
            sheet1.write(r, 0, i,set_stlye("Time New Roman",220,True) )  
#添加第1列的数据
        for c in range(1, le + 1):  #values列表中索引
            if r == 0:
                sheet1.write(r, c, j[c - 1],set_stlye("Time New Roman",220,True))  
#添加第 0 行2 列到第 5 列的数据单元格背景设为黄色
            else:
                sheet1.write(r, c, j[c - 1],set_stlye("Time New Roman",220,True))
        r += 1  #行数
    #sheet_merge()合并单元格
    book.save('data.xls')
print("已导出至:data.xls")

If data.xls exists, it will be overwritten when exporting. Taking the test as an example, the result is shown in the figure.

insert image description here

3. Graphical User Interface Module

Use the Python standard GUI library Tkinter to realize the function of this module, as shown in Figure 14 and Figure 15.

insert image description here

Figure 14 System main interface

insert image description here

Figure 15 Initialize the main interface of the test paper

When reading pictures, the user can input the picture address and click the [Select File] button to process local picture files in batches. Select the folder where the pictures are located, and the system will identify each picture that meets the conditions.

In the settings, users can customize the answer. Click the [Identify] button, the system can identify the selected picture file, and display the identified information such as college, class, student number, grades, wrong questions, etc. on the right. Click the [Export] button to export all the data recognized by the system to the data.xls table.

The relevant code is as follows:

import tkinter as tk
from iidd import sumall
from ooctest import  getinfo
from PIL import Image,ImageTk
import cv2
from excel import write_excel
data = {
    
    
    "序号": ["学院", "班级", "学号", "成绩","错题"]
}
cnt=0
import os
def walk(path):
    files=[]
    if not os.path.exists(path):
        return -1
    for root, dirs, names in os.walk(path):
        for filename in names:
            file=os.path.join(root, filename)
            print(file)  #路径和文件名连接构成完整路径
            files.append(file)
    return files
#if __name__=='__main__':
#path='C:/Users/wanli/answer sheet/images'
#walk(path)
def discern():
    global imgs
    print(entry_img_name.get())
    global cnt
    cnt+=1
    da=[]    sch_num,cls_num,stu_num,score,false_ans=sumall(entry_img_name.get(),true_ans=true_ans)    da.append(sch_num);da.append(cls_num);da.append(stu_num);da.append(score);da.append(str(false_ans));
    data[cnt]=da
    imm = Image.open('imm.jpg')       #将照片展示
    imgs = ImageTk.PhotoImage(imm)
    print(score)
    l_info1.config(text='学院:'+ str(sch_num)+'班级: '+str(cls_num))
    l_info2.config(text='学号: '+str(stu_num))
    l_info3.config(text='错题:'+str(false_ans))
    l_score.config(text='成绩:'+str(score))
    imLabel.config(image=imgs)
def set_ans():
    def confirm():
        global ans_str,true_ans
        ans_str = new_ans.get()
        window_set_ans.destroy()
        true_ans=eval(ans_str)
    window_set_ans=tk.Toplevel(window)
    window_set_ans.geometry('350x200')
    window_set_ans.title('初始化试卷')
    new_ans = tk.StringVar()
    new_ans.set(str(true_ans))
    tk.Label(window_set_ans, text='输入正确答案').place(x=10, y=10)
    entry_new_ans = tk.Entry(window_set_ans, textvariable=new_ans,
justify='left')
    entry_new_ans.place(x=100, y=10,width=230,height=150)
    btn_confirm = tk.Button(window_set_ans, text='确定', command=confirm)
    btn_confirm.place(x=150, y=130)
    hbar=tk.Scrollbar(window_set_ans,orient='horizontal', command=entry_new_ans.xview)
    entry_new_ans.configure(xscrollcommand=hbar.set)
    hbar.pack(side='bottom',fill='x')
    entry_new_ans.columnconfigure(0, weight=1)
true_ans={
    
    1:"A",  2:'B',  3:'C',  4:'D',  5:'A',
        6:"A", 7:'A', 8:'C', 9:'D', 10:'A',
        11:"B", 12:'C', 13:'D', 14:'A', 15:'B',
        16:"B", 17:'C',18:'D', 19:'A', 20:'B',
        21:"C", 22:'D', 23:'A', 24:'B', 25:'C',
        26:"C", 27:'D', 28:'A', 29:'B', 30:'C',
        31:"D", 32:'A', 33:'B', 34:'C', 35:'D',
        36:"D", 37:'A', 38:'B', 39:'C', 40:'D',
        41:"A", 42:'B', 43:'C', 44:'D', 45:'A',
        46:"A", 47:'B', 48:'C', 49 :'C', 50:'C' }
def write():
    print(data)
    write_excel(data)
    tell.config(text='已导入到data.xls')
window = tk.Tk()
window.title('答题卡识别系统')
window.geometry('550x400')
menubar=tk.Menu(window)
filemenu = tk.Menu(menubar,tearoff=0)
menubar.add_cascade(label='设置',menu=filemenu)
filemenu.add_cascade(label='初始化试卷',command=set_ans)
l_score=tk.Label(window,text='成绩:')
l_score.place(x=250,y=350)
l_info1=tk.Label(window,text='学院:班级:')
l_info1.place(x=250,y=250)
l_info2=tk.Label(window,text='姓名:学号:')
l_info2.place(x=250,y=300)
l_info3=tk.Label(window,text='错题:')
l_info3.place(x=330,y=350)
var_img_name=tk.StringVar()
var_img_name.set("new2.jpg")
#var_name=tk.StringVar()
#var_id=tk.StringVar()
#var_class=tk.StringVar()
#var_school=tk.StringVar()
l_en=tk.Label(window,text='输出图片地址')
l_en.place(x=25,y=225)
entry_img_name=tk.Entry(window,textvariable=var_img_name)
entry_img_name.place(x=30,y=250)
btn_test=tk.Button(window,text='识别',command=discern)
btn_test.place(x=40,y=300)
btn_excel=tk.Button(window,text='导出',command=write)
btn_excel.place(x=40,y=350)
#显示图片
#im = Image.open('mario_star.jpg')
#mario= ImageTk.PhotoImage(im)
imLabel = tk.Label(window,text='结果:')
imLabel.place(x=270,y=20)
def choose_fiel():
    selectFileName = tk.filedialog.askopenfilename(title='选择文件')  #选择文件
    var_img_name.set(selectFileName)
def getall():
    selectFileName0 = tk.filedialog.askdirectory()  #选择文件
    #var_img_name.set(selectFileName0)
    files=walk(selectFileName0)
    for filename in files:
        global cnt
        cnt += 1
        da = []
        sch_num, cls_num, stu_num, score, false_ans = sumall(filename, true_ans=true_ans)
        da.append(sch_num);
        da.append(cls_num);
        da.append(stu_num);
        da.append(score);
        da.append(str(false_ans));
        data[cnt] = da
    tell.config(text='批量处理完毕')
submit_button1 = tk.Button(window, text ="选择文件", command = choose_fiel)
submit_button1.place(x=30,y=180)
submit_button1 = tk.Button(window, text ="批量处理", command = getall)
submit_button1.place(x=100,y=180)
tell=tk.Label(window,text='欢迎进入机读卡识别系统')
tell.place(x=30,y=70)
window.config(menu=menubar)
window.mainloop()
print(data)

4. Handwriting recognition module

The answer sheet of the first version of the system is shown in the figure.

insert image description here

Similar to the final version of the system, operations such as preprocessing and region division are performed on incoming images. But here, students are asked to fill in their personal information in the way of "writing it out". For the personal information part, Baidu API is called to recognize the handwritten characters of the college and name, and to recognize the numbers of the class and student number, as shown in the figure.

insert image description here

Register on the Baidu AI Open Platform, and create applications that call handwritten character recognition and digital recognition, as shown in the figure.

insert image description here

Use the API Key and Secret Key to obtain the access_token, perform handwritten text recognition on the college and name obtained from the answer sheet, perform digital recognition on the class and student number, and summarize the information into the dict dictionary.

The relevant code is as follows:

#encoding:utf-8
import requests
import base64
host= 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id= &client_secret= '
response = requests.get(host)
if response:
    print(response.json())
request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/handwriting"
#二进制方式打开图片文件
school = open('school.jpg', 'rb')
school_img = base64.b64encode(school.read())
name = open('name.jpg', 'rb')
name_img = base64.b64encode(name.read())
params_s = {
    
    "image":school_img}
params_n = {
    
    "image":name_img}
#access_token =“按上面方法获得” 
#print(access_token)
request_url = request_url + "?access_token=" + access_token
headers = {
    
    'content-type': 'application/x-www-form-urlencoded'}
responseS = requests.post(request_url, data=params_s, headers=headers)
dict={
    
    }
if responseS:
    print(responseS.json())
    print (responseS.json()['words_result'][0]['words'])
    dict['school']=responseS.json()['words_result'][0]['words']
responseN = requests.post(request_url, data=params_n, headers=headers)
if responseN:
    print (responseN.json()['words_result'][0]['words'])
    dict['name']=responseN.json()['words_result'][0]['words']
#数字识别
cls = open('cls.jpg', 'rb')
cls_img = base64.b64encode(cls.read())
id = open('id.jpg', 'rb')
id_img = base64.b64encode(id.read())
params_c = {
    
    "image":cls_img}
params_i = {
    
    "image":id_img}
ru='https://aip.baidubce.com/rest/2.0/ocr/v1/numbers'
ru = ru + "?access_token=" + access_token
responseC = requests.post(ru, data=params_c, headers=headers)
responseI = requests.post(ru, data=params_i, headers=headers)
if responseS:
    print (responseC.json()['words_result'][0]['words'])
    dict['class']=responseC.json()['words_result'][0]['words']
if responseN:
    print (responseI.json()['words_result'][0]['words'])
dict['id']=responseI.json()['words_result'][0]['words']

The running results of the first version of the system are shown in the figure.

insert image description here

Due to the low accuracy rate of this method, the need for networking, slow speed, and limited number of uses, it is no longer used in the current system. I have considered building a neural network, but the accuracy rate is still not up to the requirement, and the code is cumbersome, which violates the original intention of building a lightweight system, so I chose to let the students paint out the information, and identify it according to the above OpenCV algorithm, and the accuracy rate is almost 100%. %.

System test

This part includes system identification accuracy and system identification application.

1. System recognition accuracy

By drawing several answer sheets for testing, the recognition accuracy rate reaches 100%. The principle of identifying the answer sheet is: if the photo is not standardized, the system will not recognize it; if the system can recognize it, it is necessary to ensure that the recognition result is completely correct. The test results of each answer sheet are shown in Figure 16~Figure 22.

insert image description here

Figure 16 Test Example 1

insert image description here

Figure 17 Test example 2

insert image description here

Figure 18 Test example 3

insert image description here

Figure 19 Test Example 4

insert image description here

Figure 20 invalid input

insert image description here

Figure 21 Leakage and overcoating

insert image description here

Figure 22 leak coating

The first 4 test charts were filled in normally and randomly, and they were all accurate.

For pictures that do not meet the requirements, the system prompts that they are illegal.

For the situation of overcoating and missing coating, this system can accurately identify and feedback information in the wrong dictionary.

Although the stability of the system cannot be verified through a large amount of data, it at least shows that the program is accurate. For pictures that meet the requirements, it can correctly identify the student information and option information in the photo answer sheet.

2. System identification application

After configuring the environment, the running answer sheetfiles turntogui.pycan successfully enter the system, as shown in the figure.

insert image description here

The top is the [Settings] menu, click it to pop up the [Initialize Test Paper] window, drag the scroll bar to modify the standard answer dictionary. Click the [OK] button to complete the modification and return to the main interface, as shown in the figure.

insert image description here

Below the menu bar is the prompt information.

Click [Select File] to select local file recognition; click [Batch Processing] button to select a specified folder and identify the pictures that meet the requirements in the folder.

Manually enter the image address, click the [Recognition] button to identify the image, and click the [Export] button to export the information as a data.xls file.

After the recognition is started, the recognized information will be displayed on the right side of the window, such as pictures, colleges, student numbers, grades and wrong question sets, etc.

The system test results are shown in the figure.

insert image description here

Project source code download

See my blog resource download page for details


Other information download

If you want to continue to learn about artificial intelligence-related learning routes and knowledge systems, welcome to read my other blog " Heavy | Complete artificial intelligence AI learning-basic knowledge learning route, all materials can be downloaded directly from the network disk without paying attention to routines "
This blog refers to Github's well-known open source platform, AI technology platform and experts in related fields: Datawhale, ApacheCN, AI Youdao and Dr. Huang Haiguang, etc. There are about 100G related materials, and I hope to help all friends.

Guess you like

Origin blog.csdn.net/qq_31136513/article/details/132598680