1.研究背景與意義
項(xiàng)目參考AAAI Association for the Advancement of Artificial Intelligence
研究背景與意義:
隨著科技的不斷發(fā)展,計(jì)算機(jī)視覺(jué)技術(shù)在各個(gè)領(lǐng)域中的應(yīng)用越來(lái)越廣泛。其中,基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)在教育領(lǐng)域中具有重要的意義。傳統(tǒng)的答題卡批閱方式需要大量的人力和時(shí)間,容易出現(xiàn)錯(cuò)誤和漏批的情況。而基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)可以實(shí)現(xiàn)自動(dòng)化、高效率的批閱,大大提高了批閱的準(zhǔn)確性和效率。
在教育領(lǐng)域中,答題卡是一種常見(jiàn)的考試方式。學(xué)生通過(guò)在答題卡上選擇選項(xiàng)來(lái)回答問(wèn)題,然后教師需要將答題卡進(jìn)行批閱和評(píng)分。傳統(tǒng)的批閱方式需要教師手動(dòng)逐一檢查每個(gè)答題卡,容易出現(xiàn)疲勞和錯(cuò)誤。而基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)可以通過(guò)圖像處理和模式識(shí)別的技術(shù),自動(dòng)識(shí)別和分析答題卡上的選項(xiàng),實(shí)現(xiàn)自動(dòng)化的批閱和評(píng)分。這不僅可以減輕教師的工作負(fù)擔(dān),還可以提高批閱的準(zhǔn)確性和效率。
另外,基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)還可以應(yīng)用于各種考試場(chǎng)景,包括學(xué)校的期中考試、期末考試、高考、托福、雅思等。這些考試通常涉及大量的答題卡,傳統(tǒng)的批閱方式需要大量的人力和時(shí)間,容易出現(xiàn)錯(cuò)誤和漏批的情況。而基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)可以實(shí)現(xiàn)自動(dòng)化、高效率的批閱,大大提高了批閱的準(zhǔn)確性和效率。同時(shí),該系統(tǒng)還可以提供詳細(xì)的統(tǒng)計(jì)數(shù)據(jù)和分析報(bào)告,幫助教師和學(xué)校更好地了解學(xué)生的學(xué)習(xí)情況和能力水平。
此外,基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)還可以應(yīng)用于各種研究領(lǐng)域,包括心理學(xué)、教育評(píng)估、社會(huì)調(diào)查等。通過(guò)分析答題卡上的選項(xiàng),可以得到大量的數(shù)據(jù)和信息,用于研究學(xué)生的學(xué)習(xí)行為、學(xué)習(xí)能力、心理狀態(tài)等。這些數(shù)據(jù)和信息可以幫助研究者更好地了解學(xué)生的學(xué)習(xí)情況和發(fā)展趨勢(shì),為教育改革和教學(xué)改進(jìn)提供科學(xué)依據(jù)。
綜上所述,基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)在教育領(lǐng)域中具有重要的意義。它可以實(shí)現(xiàn)自動(dòng)化、高效率的批閱,減輕教師的工作負(fù)擔(dān),提高批閱的準(zhǔn)確性和效率。同時(shí),它還可以應(yīng)用于各種考試場(chǎng)景和研究領(lǐng)域,為教育改革和教學(xué)改進(jìn)提供科學(xué)依據(jù)。因此,研究和開(kāi)發(fā)基于計(jì)算機(jī)視覺(jué)的答題卡識(shí)別系統(tǒng)具有重要的實(shí)際應(yīng)用價(jià)值和研究意義。
2.圖片演示
3.視頻演示
基于計(jì)算機(jī)視覺(jué)OpenCV的答題卡識(shí)別系統(tǒng)_嗶哩嗶哩_bilibili
4.系統(tǒng)流程圖
系統(tǒng)實(shí)現(xiàn)的整體流程分為用戶登錄階段、錄入標(biāo)準(zhǔn)答案階段、答卷識(shí)別階段、成績(jī)分析階段這四個(gè)階段,主要對(duì)以下三個(gè)階段進(jìn)行介紹。
(1)錄入標(biāo)準(zhǔn)答案階段
首先,教師將標(biāo)準(zhǔn)答題卡用普通打印機(jī)打印出來(lái),進(jìn)行標(biāo)準(zhǔn)答案的填涂;然后通過(guò)硬件設(shè)備對(duì)該答題卡圖像進(jìn)行采集;其次,錄入單選多選的題目數(shù)和每題分值,并且對(duì)采集后的圖像進(jìn)行圖像預(yù)處理和圖像識(shí)別;最后,將每一題的識(shí)別結(jié)果、每題的分值、題號(hào)一起存到數(shù)據(jù)庫(kù)(本地txt)中。
(2)答卷識(shí)別階段
在答題卡識(shí)別階段,對(duì)待閱答題卡進(jìn)行圖像的采集、圖像的預(yù)處理、圖像的識(shí)別等處理步驟,在這個(gè)過(guò)程中,本文將待閱答題卡圖像進(jìn)行縮放,使其和答題卡標(biāo)準(zhǔn)模板圖像大小相同,以保證最好的圖像識(shí)別效果。識(shí)別后,得出了該考生的答題卡填涂的識(shí)別結(jié)果,將該考生的答題卡填涂的識(shí)別結(jié)果與數(shù)據(jù)庫(kù)中的標(biāo)準(zhǔn)答案進(jìn)行一一對(duì)比,然后將該考生的總得分、每題的得分、填涂結(jié)果輸出并且存入數(shù)據(jù)庫(kù)中。
(3)成績(jī)分析階段
在成績(jī)分析階段,主要是針對(duì)識(shí)別后的學(xué)生成績(jī)進(jìn)行得分統(tǒng)計(jì)和錯(cuò)題數(shù)的分析,從而了解到學(xué)生的知識(shí)的掌握程度,對(duì)教師進(jìn)行后續(xù)的教學(xué)起指導(dǎo)和借鑒作用。
綜上所述,系統(tǒng)實(shí)現(xiàn)流程如圖所示。
5.核心代碼講解
5.1 excel.py
封裝為類的代碼如下:
class ExcelWriter:
def __init__(self, data):
self.data = data
def set_style(self, name, height, bold=False):
# 初始化樣式
style = xlwt.XFStyle()
# 創(chuàng)建字體
font = xlwt.Font()
font.bold = bold
font.colour_index = 4
font.height = height
font.name = name
style.font = font
return style
def write_excel(self):
if os.path.exists("data.xls"):
os.remove("data.xls")
book = xlwt.Workbook(encoding='utf-8') # 創(chuàng)建Workbook,相當(dāng)于創(chuàng)建Excel
# 創(chuàng)建sheet,Sheet1為表的名字,cell_overwrite_ok為是否覆蓋單元格
sheet1 = book.add_sheet(u'Sheet1', cell_overwrite_ok=True)
r = 0
for i, j in self.data.items(): # i表示data中的key,j表示data中的value
le = len(j) # values返回的列表長(zhǎng)度
if r == 0:
sheet1.write(r, 0, i, self.set_style("Time New Roman", 220, True)) # 添加第 0 行 0 列數(shù)據(jù)單元格背景設(shè)為黃色
else:
sheet1.write(r, 0, i, self.set_style("Time New Roman", 220, True)) # 添加第 1 列的數(shù)據(jù)
for c in range(1, le + 1): # values列表中索引
if r == 0:
sheet1.write(r, c, j[c - 1], self.set_style("Time New Roman", 220, True)) # 添加第 0 行,2 列到第 5 列的數(shù)據(jù)單元格背景設(shè)為黃色
else:
sheet1.write(r, c, j[c - 1], self.set_style("Time New Roman", 220, True))
r += 1 # 行數(shù)
# sheet_merge() 合并單元格
book.save('data.xls')
print("已導(dǎo)出至:data.xls")
使用方法:
data1 = {
"序號(hào)": ["姓名", "語(yǔ)文", "數(shù)學(xué)", "英語(yǔ)"],
"1": ["張三", 130, 120, 100],
"2": ["李四", 100, 110, 120],
"3": ["王五", 125, 135, 135]
}
data2 = {'序號(hào)': ['學(xué)院', '班級(jí)', '學(xué)號(hào)', '成績(jī)', '錯(cuò)題'],
1: [21, 21, 160, 82,
"{35: 'C', 36: 'B', 37: 'C', 38: 'D', 39: 'D', 46: 'B', 47: 'C', 48: 'D', 49: 'B'}"],
2: [21, 21, 159, 90, "{46: 'B', 47: 'C', 48: 'D', 49: 'A', 50: 'B'}"]}
excel_writer = ExcelWriter(data1)
excel_writer.write_excel()
該程序文件名為excel.py,主要功能是使用xlwt庫(kù)將數(shù)據(jù)寫(xiě)入Excel文件。程序中定義了一個(gè)set_style函數(shù),用于設(shè)置單元格樣式。然后定義了兩個(gè)數(shù)據(jù)字典data1和data2,分別表示兩個(gè)表格的數(shù)據(jù)。接下來(lái)定義了一個(gè)write_excel函數(shù),用于將數(shù)據(jù)寫(xiě)入Excel文件。函數(shù)首先判斷是否存在名為"data.xls"的文件,如果存在則刪除。然后創(chuàng)建一個(gè)Workbook對(duì)象book,并創(chuàng)建一個(gè)名為"Sheet1"的sheet對(duì)象sheet1。接著使用循環(huán)遍歷數(shù)據(jù)字典,將數(shù)據(jù)寫(xiě)入Excel文件中。最后調(diào)用save方法保存Excel文件,并打印導(dǎo)出成功的提示信息。
5.2 get_answer.py
class AnswerSheetScanner:
def __init__(self, image_path):
self.image_path = image_path
self.ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}
def order_points(self, pts):
rect = np.zeros((4, 2), dtype="float32")
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 four_point_transform(self, image, pts):
rect = self.order_points(pts)
(tl, tr, br, bl) = rect
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")
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
return warped
def sort_contours(self, cnts, method="left-to-right"):
reverse = False
i = 0
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b: b[1][i], reverse=reverse))
return cnts, boundingBoxes
def scan(self):
image = cv2.imread(self.image_path)
contours_img = image.copy()
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)[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)
if len(approx) == 4:
docCnt = approx
break
warped = self.four_point_transform(gray, docCnt.reshape(4, 2))
thresh = cv2.threshold(warped, 0, 255,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
thresh_Contours = thresh.copy()
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
questionCnts = []
for c in cnts:
(x, y, w, h) = cv2.boundingRect(c)
ar = w / float(h)
if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:
questionCnts.append(c)
questionCnts = self.sort_contours(questionCnts,
method="top-to-bottom")[0]
correct = 0
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
cnts = self.sort_contours(questionCnts[i:i + 5])[0]
bubbled = None
for (j, c) in enumerate(cnts):
mask = np.zeros(thresh.shape, dtype="uint8")
cv2.drawContours(mask, [c], -1, 255, -1)
mask = cv2.bitwise_and(thresh, thresh, mask=mask)
total = cv2.countNonZero(mask)
if bubbled is None or total > bubbled[0]:
bubbled = (total, j)
color = (0, 0, 255)
k = self.ANSWER_KEY[q]
if k == bubbled[1]:
color = (0, 255, 0)
correct += 1
cv2.drawContours(warped, [cnts[k]], -1, color, 3)
score = (correct / 5.0) * 100
......
這個(gè)程序文件名為get_answer.py,它的功能是讀取一張圖片,進(jìn)行圖像處理和透視變換,然后根據(jù)圖片中的選擇題答案和正確答案進(jìn)行對(duì)比,計(jì)算得分并顯示在圖片上。
程序首先導(dǎo)入所需的工具包,并設(shè)置了一個(gè)參數(shù)解析器,用于接收輸入圖片的路徑。
接下來(lái)定義了一個(gè)字典ANSWER_KEY,用于存儲(chǔ)正確答案。
然后定義了兩個(gè)函數(shù),order_points用于按順序找到坐標(biāo)點(diǎn),four_point_transform用于執(zhí)行透視變換。
接下來(lái)定義了一個(gè)輔助函數(shù)sort_contours,用于對(duì)輪廓進(jìn)行排序,以及一個(gè)輔助函數(shù)cv_show,用于顯示圖像。
然后進(jìn)行預(yù)處理,包括讀取圖片、灰度化、高斯濾波、邊緣檢測(cè)等。
接下來(lái)進(jìn)行輪廓檢測(cè),找到最大的輪廓并進(jìn)行近似處理,得到透視變換的坐標(biāo)點(diǎn)。
然后執(zhí)行透視變換,得到變換后的圖像。
接下來(lái)進(jìn)行閾值處理,找到每個(gè)圓圈輪廓。
然后遍歷每一排的選項(xiàng),對(duì)每個(gè)選項(xiàng)進(jìn)行處理,通過(guò)計(jì)算非零點(diǎn)數(shù)量來(lái)判斷是否選擇了該答案。
最后根據(jù)正確答案和選擇的答案進(jìn)行對(duì)比,計(jì)算得分,并在圖像上顯示得分。
最后顯示原始圖片和處理后的圖片,并等待按鍵退出程序。
5.3 iidd.py
class ExamPaper:
def __init__(self, image_name):
self.image_name = image_name
self.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 order_points(self, pts):
rect = np.zeros((4, 2), dtype="float32")
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(self, image, pts):
rect = self.order_points(pts)
(tl, tr, br, bl) = rect
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))
......
該程序文件名為iidd.py,主要功能是通過(guò)圖像處理識(shí)別答題卡上的選擇題答案和學(xué)生信息。程序包含以下幾個(gè)函數(shù):
-
order_points(pts):根據(jù)輸入的四個(gè)坐標(biāo)點(diǎn),按照左上、右上、右下、左下的順序返回四個(gè)點(diǎn)的坐標(biāo)。
-
toushi_transform(image, pts):根據(jù)輸入的圖像和四個(gè)坐標(biāo)點(diǎn),進(jìn)行透視變換,將圖像中的答題卡部分變換為標(biāo)準(zhǔn)大小。
-
judge(x, y):根據(jù)輸入的坐標(biāo)點(diǎn),判斷其所在的題目位置。
-
judgey0(y):根據(jù)輸入的y坐標(biāo),判斷其所在的題目行數(shù)。
-
judgex0(x):根據(jù)輸入的x坐標(biāo),判斷其所在的題目列數(shù)。
-
judge0(x, y):根據(jù)輸入的坐標(biāo)點(diǎn),判斷其所在的題目位置,并返回行數(shù)和列數(shù)。
-
cv_show(name, img):顯示圖像。
-
get_postion(image_name):根據(jù)輸入的圖像文件名,讀取圖像并進(jìn)行圖像處理,找到答題卡的位置和題目的位置。
-
explain(Info):根據(jù)輸入的題目位置信息,解析出學(xué)生的學(xué)號(hào)、班級(jí)和學(xué)號(hào)。
-
calculate(Answer):根據(jù)輸入的答案位置信息,計(jì)算出學(xué)生的答案。
-
sumall(image_name, true_ans):根據(jù)輸入的圖像文件名和正確答案,調(diào)用上述函數(shù),計(jì)算出學(xué)生的得分和錯(cuò)誤答案。
該程序主要用于自動(dòng)批改選擇題答題卡,并提取學(xué)生的學(xué)號(hào)、班級(jí)和學(xué)號(hào)信息。
5.4 MainUI.py
class CardRecognitionSystem:
def __init__(self):
self.data = {
"序號(hào)": ["學(xué)院", "班級(jí)", "學(xué)號(hào)", "成績(jī)", "錯(cuò)題"]
}
self.cnt = 0
self.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'
}
self.window = tk.Tk()
self.window.title('答題卡識(shí)別系統(tǒng)')
self.window.geometry('550x400')
self.menubar = tk.Menu(self.window)
self.filemenu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label='設(shè)置', menu=self.filemenu)
self.filemenu.add_cascade(label='初始化試卷', command=self.set_ans)
self.l_score = tk.Label(self.window, text='成績(jī):')
self.l_score.place(x=250, y=350)
self.l_info1 = tk.Label(self.window, text='學(xué)院: 班級(jí): ')
self.l_info1.place(x=250, y=250)
self.l_info2 = tk.Label(self.window, text='姓名: 學(xué)號(hào): ')
self.l_info2.place(x=250, y=300)
self.l_info3 = tk.Label(self.window, text='錯(cuò)題: ')
self.l_info3.place(x=330, y=350)
self.var_img_name = tk.StringVar()
self.var_img_name.set("new2.jpg")
self.l_en = tk.Label(self.window, text='輸出圖片地址')
self.l_en.place(x=25, y=225)
self.entry_img_name = tk.Entry(self.window, textvariable=self.var_img_name)
self.entry_img_name.place(x=30, y=250)
self.btn_test = tk.Button(self.window, text='識(shí)別', command=self.discern)
self.btn_test.place(x=40, y=300)
self.btn_excel = tk.Button(self.window, text='導(dǎo)出', command=self.write)
self.btn_excel.place(x=40, y=350)
self.imLabel = tk.Label(self.window, text='結(jié)果:')
self.imLabel.place(x=270, y=20)
self.tell = tk.Label(self.window, text='歡迎進(jìn)入機(jī)讀卡識(shí)別系統(tǒng)')
self.tell.place(x=30, y=70)
self.window.config(menu=self.menubar)
def walk(self, 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) # 路徑和文件名連接構(gòu)成完整路徑
files.append(file)
return files
......
該程序文件名為MainUI.py,主要功能是實(shí)現(xiàn)一個(gè)答題卡識(shí)別系統(tǒng)的圖形用戶界面。程序使用了tkinter庫(kù)來(lái)創(chuàng)建GUI界面,使用了filedialog庫(kù)來(lái)選擇文件和文件夾,使用了PIL庫(kù)來(lái)處理圖片,使用了cv2庫(kù)來(lái)進(jìn)行圖像處理,使用了excel庫(kù)來(lái)寫(xiě)入Excel文件。
程序的主要功能包括:
- 導(dǎo)入所需的庫(kù)文件。
- 定義了一個(gè)數(shù)據(jù)字典data,用于存儲(chǔ)識(shí)別結(jié)果。
- 定義了一個(gè)函數(shù)walk,用于遍歷指定文件夾下的所有文件。
- 定義了一個(gè)函數(shù)discern,用于識(shí)別答題卡圖片,并將識(shí)別結(jié)果展示在界面上。
- 定義了一個(gè)函數(shù)set_ans,用于設(shè)置正確答案。
- 定義了一個(gè)函數(shù)write,用于將識(shí)別結(jié)果寫(xiě)入Excel文件。
- 創(chuàng)建了一個(gè)窗口,并設(shè)置了窗口的標(biāo)題和大小。
- 創(chuàng)建了一個(gè)菜單欄,并添加了一個(gè)菜單項(xiàng)"初始化試卷",點(diǎn)擊該菜單項(xiàng)會(huì)彈出一個(gè)新窗口,用于設(shè)置正確答案。
- 創(chuàng)建了一些標(biāo)簽和輸入框,用于顯示和輸入相關(guān)信息。
- 創(chuàng)建了一些按鈕,用于觸發(fā)相應(yīng)的功能。
- 最后,通過(guò)調(diào)用window.mainloop()來(lái)啟動(dòng)窗口的事件循環(huán)。
總體來(lái)說(shuō),該程序?qū)崿F(xiàn)了一個(gè)簡(jiǎn)單的答題卡識(shí)別系統(tǒng)的圖形用戶界面,用戶可以選擇單個(gè)文件或批量處理文件夾中的答題卡圖片,并將識(shí)別結(jié)果展示在界面上,還可以設(shè)置正確答案并將識(shí)別結(jié)果導(dǎo)出到Excel文件中。
5.5 ooctest.py
class OCR:
def __init__(self, access_token):
self.access_token = access_token
self.headers = {'content-type': 'application/x-www-form-urlencoded'}
self.base_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/"
def get_text(self, image_path):
request_url = self.base_url + "handwriting" + "?access_token=" + self.access_token
image = open(image_path, 'rb')
image_data = base64.b64encode(image.read())
params = {"image": image_data}
response = requests.post(request_url, data=params, headers=self.headers)
if response:
return response.json()['words_result'][0]['words']
else:
return None
def get_number(self, image_path):
request_url = self.base_url + "numbers" + "?access_token=" + self.access_token
image = open(image_path, 'rb')
image_data = base64.b64encode(image.read())
params = {"image": image_data}
response = requests.post(request_url, data=params, headers=self.headers)
if response:
return response.json()['words_result'][0]['words']
else:
return None
這個(gè)程序文件名為ooctest.py,它的功能是通過(guò)百度OCR接口識(shí)別手寫(xiě)文字。程序首先導(dǎo)入了requests和base64兩個(gè)模塊。然后定義了一個(gè)名為getinfo的函數(shù)。
在getinfo函數(shù)中,首先設(shè)置了請(qǐng)求的URL為百度OCR接口的手寫(xiě)文字識(shí)別API。然后使用二進(jìn)制方式打開(kāi)了兩張圖片文件,分別是school.jpg和name.jpg,并將它們轉(zhuǎn)換成base64編碼的字符串。接下來(lái),將圖片的base64編碼作為參數(shù),構(gòu)造了兩個(gè)請(qǐng)求參數(shù)params_s和params_n。
接著,定義了一個(gè)access_token變量,該變量是百度OCR接口的訪問(wèn)令牌。然后將access_token拼接到請(qǐng)求URL中。設(shè)置了請(qǐng)求頭部的content-type為application/x-www-form-urlencoded。
然后,使用requests.post方法發(fā)送了兩個(gè)POST請(qǐng)求,分別是對(duì)school_img和name_img進(jìn)行手寫(xiě)文字識(shí)別。將識(shí)別結(jié)果打印出來(lái),并將結(jié)果存入一個(gè)名為dict的字典中。
接下來(lái),程序進(jìn)行了數(shù)字識(shí)別。同樣使用二進(jìn)制方式打開(kāi)了兩張圖片文件,分別是cls.jpg和id.jpg,并將它們轉(zhuǎn)換成base64編碼的字符串。構(gòu)造了兩個(gè)請(qǐng)求參數(shù)params_c和params_i。
然后,定義了一個(gè)名為ru的變量,該變量是百度OCR接口的數(shù)字識(shí)別API的請(qǐng)求URL。將access_token拼接到ru中。
再次使用requests.post方法發(fā)送了兩個(gè)POST請(qǐng)求,分別是對(duì)cls_img和id_img進(jìn)行數(shù)字識(shí)別。將識(shí)別結(jié)果打印出來(lái),并將結(jié)果存入dict字典中。
最后,函數(shù)返回了dict字典。
5.6 ui.py
class SetAnsDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('初始化試卷')
self.setGeometry(100, 100, 350, 200)
self.initUI()
def initUI(self):
layout = QVBoxLayout()
self.new_ans = QLineEdit(self)
self.new_ans.setText(str(self.parent().true_ans))
layout.addWidget(self.new_ans)
btn_confirm = QPushButton('確定', self)
btn_confirm.clicked.connect(self.confirm)
layout.addWidget(btn_confirm)
self.setLayout(layout)
def confirm(self):
ans_str = self.new_ans.text()
self.parent().true_ans = eval(ans_str)
self.close()
......
這個(gè)程序文件是一個(gè)使用PyQt5編寫(xiě)的答題卡識(shí)別系統(tǒng)。程序主要包括以下幾個(gè)部分:
- 導(dǎo)入必要的模塊和庫(kù),包括sys、os、PyQt5、PIL、cv2等。
- 定義了一個(gè)全局變量data,用于存儲(chǔ)識(shí)別結(jié)果。
- 定義了一個(gè)函數(shù)walk,用于遍歷指定路徑下的所有文件。
- 定義了一個(gè)SetAnsDialog類,用于初始化試卷答案。
- 定義了一個(gè)App類,繼承自QMainWindow,用于創(chuàng)建主窗口。
- 在App類的initUI方法中,創(chuàng)建了主窗口的布局和控件,并設(shè)置了背景圖片。
- 在App類中定義了一些按鈕的點(diǎn)擊事件,包括識(shí)別按鈕、導(dǎo)出按鈕、初始化試卷按鈕、選擇文件按鈕和批量處理按鈕。
- 在App類中定義了識(shí)別方法discern,用于識(shí)別答題卡圖片并將結(jié)果顯示在表格中。
- 在App類中定義了選擇文件方法choose_file,用于選擇要識(shí)別的答題卡圖片。
- 在App類中定義了批量處理方法getall,用于批量處理指定文件夾下的答題卡圖片。
- 在App類中定義了導(dǎo)出方法write,用于將識(shí)別結(jié)果寫(xiě)入Excel文件。
- 在主程序中創(chuàng)建了一個(gè)QApplication對(duì)象和一個(gè)App對(duì)象,并啟動(dòng)了主程序。
總體來(lái)說(shuō),這個(gè)程序是一個(gè)簡(jiǎn)單的答題卡識(shí)別系統(tǒng),可以識(shí)別單張答題卡圖片或批量處理答題卡圖片,并將識(shí)別結(jié)果顯示在表格中,并可以導(dǎo)出到Excel文件中。
6.系統(tǒng)整體結(jié)構(gòu)
整體功能概述:
該答題卡識(shí)別系統(tǒng)的整體功能是通過(guò)圖像處理和OCR技術(shù),實(shí)現(xiàn)對(duì)答題卡圖片的識(shí)別和批改,并將識(shí)別結(jié)果展示在圖形用戶界面上。系統(tǒng)可以單張識(shí)別和批量處理答題卡圖片,支持設(shè)置正確答案并導(dǎo)出識(shí)別結(jié)果到Excel文件。
文件功能整理:
文件名 | 功能概述 |
---|---|
excel.py | 將數(shù)據(jù)寫(xiě)入Excel文件的功能 |
get_answer.py | 識(shí)別答題卡圖片并計(jì)算得分的功能 |
iidd.py | 通過(guò)百度OCR接口識(shí)別手寫(xiě)文字和數(shù)字的功能 |
MainUI.py | 答題卡識(shí)別系統(tǒng)的圖形用戶界面的功能 |
ooctest.py | 通過(guò)百度OCR接口識(shí)別手寫(xiě)文字和數(shù)字的功能 |
ui.py | 答題卡識(shí)別系統(tǒng)的圖形用戶界面的功能 |
7.圖像的預(yù)處理
概述
圖像預(yù)處理是指在圖像分析中,對(duì)采集的圖像識(shí)別之前所進(jìn)行的一系列處理。由于采集圖像環(huán)境的不同,例如,光照的明暗、攝像頭性能不一、攝像的角度、紙張的薄厚、光源的顏色和打光方式、圖像的傾斜等多種環(huán)境因素的影響。
因此,為了盡可能減少這些環(huán)境因素對(duì)圖像識(shí)別結(jié)果的影響,去除一些無(wú)關(guān)信息,所以,必須對(duì)圖像進(jìn)行預(yù)處理。其目的是利用計(jì)算機(jī)信息技術(shù)盡可能去掉圖像中的一些非緊要信息,恢復(fù)并且使緊要信息的可檢測(cè)性增強(qiáng),從而提升圖像識(shí)別的準(zhǔn)確度。
圖像灰度化
目前,攝像頭采集到的答題卡圖像是彩色的。其每個(gè)像素都是由紅?、綠(G)、藍(lán)(B)三個(gè)分量組成的,像素點(diǎn)的取值范圍為0~16581375l18]。由于存一幅彩色圖像需要很大的存儲(chǔ)空間,而且增加后續(xù)的圖像處理的計(jì)算量。另一方面,灰度圖像和彩色圖像可用來(lái)反映圖像的色度和亮度的特征是一樣的。所以,必須對(duì)圖像進(jìn)行灰度化處理。完全可以用灰度圖像代替彩色圖像。
圖像灰度化處理就是將待閱答題卡圖像轉(zhuǎn)換成灰度圖像的過(guò)程,在圖像處理進(jìn)程中,這樣可以減少的計(jì)算量、圖像的復(fù)雜程度和信息處理速度。常用的圖像灰度化的方法有以下幾種方式:
(1)單分量法
取灰度圖像的灰度值為待閱答題卡圖像R、G、B三個(gè)分量中的任意一個(gè)分量的值,見(jiàn)式。
(2)平均值法
在待閱答題卡圖像中,取某像素點(diǎn)的R、G、B三個(gè)分量的值,求這三個(gè)值的平均值,即圖像的灰度值,見(jiàn)式。
(3)最大值法
在待閱答題卡圖像中,取某像素點(diǎn)的R、G、B三個(gè)分量中的最大值,即圖像的灰度值,見(jiàn)式。
(4)加權(quán)平均法
加權(quán)平均法是根據(jù)重要性以及其它指標(biāo),將R、G、B三個(gè)分量以不相同的權(quán)重進(jìn)行加權(quán)平均。根據(jù)轉(zhuǎn)換公式把RGB彩色模型轉(zhuǎn)換成YUV彩色模型,可得到各個(gè)分量的權(quán)重。其中,YUv,即一種顏色編碼方法。Y是明亮度:V、U是色度,是影像色彩及飽和度的描述,有確定像素顏色的用途[1]。
人眼對(duì)綠色的敏感最高,對(duì)藍(lán)色敏感最低,要想得到最符合人眼視覺(jué)效果的圖像,就得取R、G、B的權(quán)重分別約為0.3、0.59、0.11時(shí),這樣灰度化后的結(jié)果真實(shí)合理、符合實(shí)際的應(yīng)用。見(jiàn)式。
在灰度化處理過(guò)程中,由于目前最常用的方法就是加權(quán)平均法。因此,本系統(tǒng)采用加權(quán)平均法來(lái)實(shí)現(xiàn)對(duì)答題卡圖像的灰度化處理效果如圖。
8.圖像二值化
在答題卡圖像處理過(guò)程中,由于考生在填涂答題卡時(shí),填涂的面積和填涂的深淺等都存在一定的差異。因此,必須對(duì)灰度化后的答題卡圖像進(jìn)行閾值化處理.
圖像的二值化處理就是將灰度圖像轉(zhuǎn)換成只有黑白兩種取值的圖像。先給定一個(gè)灰度閾值T,圖像中某像素點(diǎn)的灰度值設(shè)為f(x, y),當(dāng)f(x,y)>T時(shí),則令f(x, y)=255:當(dāng)f(x,y)<=T時(shí),則令f(x,y)=0。這樣就得到了只有黑白兩色的灰度圖像,大大減少了圖像的數(shù)據(jù)量,并且簡(jiǎn)化了圖像的處理過(guò)程。閥值化處理的關(guān)鍵在于設(shè)定閾值,選取適當(dāng)?shù)拈撝悼梢员M量的減少圖像的干擾信息,突出圖像的主要信息,便于進(jìn)行后續(xù)進(jìn)行圖像識(shí)別。
在圖像處理過(guò)程中,選取閾值的方法有很多種,常見(jiàn)的有五種方法:簡(jiǎn)單閾值法、雙峰法、大津法、最佳閾值法。
(1)簡(jiǎn)單閾值法
簡(jiǎn)單閾值法是指在圖像閾值化處理過(guò)程中,通過(guò)人眼的識(shí)別,判斷該圖像中的像素點(diǎn)、并且分析該圖像,設(shè)T是我們?nèi)斯みx擇的全局閾值,圖像的各個(gè)像素點(diǎn)的灰度值g(x,y)與T比較,若g(x,y) >T ,則令g(x. y)=255:若g(x, y)<=T,則令g(x,y)=0:這種閾值選擇的方法簡(jiǎn)單,處理速度快:然而,其使用范圍比較窄,結(jié)果容易受人為影響[20]。
(2〉雙峰法
根據(jù)圖像的灰度直方圖可以用來(lái)實(shí)現(xiàn)雙峰法。在一些不復(fù)雜圖像中,其灰度分布很有規(guī)則,圖像背景與前景像素灰度值的分布呈山峰形狀,一個(gè)波谷由兩個(gè)波峰形成。因此,確定閾值為兩波峰之間波谷的灰度值。有兩個(gè)波峰的圖像適用這種方法[P]。不適用此方法的情況是直方圖曲線平緩或只有一個(gè)波峰的圖像。
(3)大津法
在二十世紀(jì)七十年代末,[日本學(xué)者大津提出了大津法],此方法可以自適應(yīng)確定閥值。其原理是基于圖像的灰度特征,整個(gè)圖像分為前景和背景,對(duì)這兩個(gè)部分的像素點(diǎn)總數(shù)和灰度平均值分別進(jìn)行計(jì)算,這樣就求得其類間方差,類間方差越大時(shí),伴隨著前景和背景的差別越大,因此,若類間方差最大時(shí),即是圖像的最佳閥值點(diǎn),二值化效果最好。該方法的主要實(shí)現(xiàn)步驟為:
(A)在一個(gè)圖像中,設(shè)w,是前景像素點(diǎn),u.是前景圖像的平均灰度;w是背景像素點(diǎn),u,是背景圖像的平均灰度;g是前景和背景圖像的方差,u是圖像的平均灰度:
(B)計(jì)算圖像的平均灰度,見(jiàn)式:
(C)計(jì)算圖像的方差g,見(jiàn)式:
(D)在(3.6)式中把(3.5)式代入得,見(jiàn)式:
當(dāng)g最大時(shí),得到最佳閾值T。該方法的優(yōu)點(diǎn)是算法簡(jiǎn)單,用時(shí)少,當(dāng)前景與背景的面積相差不大時(shí),能夠有效的分割圖像。但是,當(dāng)圖像的前景與背景的面積相差很大時(shí),則不能夠有效的使圖像分割,即其直方圖表現(xiàn)為雙峰不明顯或大小相差很大的雙峰,此時(shí)分割效果不佳?;趫D像的灰度特征的區(qū)分來(lái)使用的此方法,所以,對(duì)噪音和目標(biāo)圖像大小很敏感。因此,在實(shí)際應(yīng)用中,將該方法與其他方法結(jié)合起來(lái)用。
(4)最佳閾值法(迭代法)
最佳閾值法又稱迭代法,它選取閾值的核心是基于逼近的思想[P3l,首先選取灰度圖的平均值作為初始閾值,然后進(jìn)行闕值分割,產(chǎn)生子圖像,并根據(jù)子圖像的特征來(lái)選擇新的閾值,這樣幾次循環(huán),分割的圖像的像素點(diǎn)可以最大程度減少錯(cuò)誤。這樣做的成效比用初始閾值直接分割圖像好。以下是詳細(xì)的實(shí)現(xiàn)過(guò)程:
(A)計(jì)算圖像最小、最大灰度值分別為Zm和Z.,則初值閾值T=(Zmin+Z.)/2 :
(B)將圖像分為目標(biāo)和背景部分,根據(jù)新選取的閾值T,計(jì)算出兩部分的平均灰度值Z。和Z,,從而得出新閾值T=(Z+Z)/2 :
?如果T=T,則此時(shí)的閾值就是最佳閾值:否則將T的值賦予T。,轉(zhuǎn)向步驟(B)。
最佳閾值法可以準(zhǔn)確地區(qū)分圖像的目標(biāo)和背景,但是細(xì)節(jié)處區(qū)分不細(xì)致,總體的效果還是比較好的。
本文經(jīng)過(guò)實(shí)驗(yàn)對(duì)比了以上方法,發(fā)現(xiàn)采用最佳閾值法可以得到更好的答題卡圖像二值化的效果如圖。
9.圖像平移旋轉(zhuǎn)矯正
在答題卡圖像采集過(guò)程中,由于答題卡圖像放置的位置、支架的搭建、攝像頭的固定等人為因素,以及攝像頭的性能因素會(huì)造成一定角度的傾斜或者形變,采集到的圖像如果有一定角度的傾斜或者形變,那么會(huì)對(duì)識(shí)別的結(jié)果造成一定的影響,進(jìn)一步影響學(xué)生的成績(jī)的準(zhǔn)確性,考試的公正性,以及人才選拔的客觀性。因此,在答題卡圖像識(shí)別之前,判斷答題卡圖像是否傾斜并做相應(yīng)平移旋轉(zhuǎn)矯正處理,對(duì)后續(xù)答題卡識(shí)別具有十分重要的意義。
首先需要獲取答題卡圖像四個(gè)角的定位標(biāo)識(shí)即正方形黑塊,通常有以下三種方法:一是采用邊緣檢測(cè)或者輪廓區(qū)域檢測(cè)的相關(guān)算法,利用答題卡圖像邊緣的突變性質(zhì)或者邊緣點(diǎn)連接的層次差別來(lái)檢測(cè)并提取其邊緣信息,然后對(duì)答題卡圖像進(jìn)行相應(yīng)的矯正,這種方法只能處理沒(méi)有發(fā)生透視情況的圖像矯正,處理范圍比較局限24。二是采用角點(diǎn)檢測(cè)的方法,來(lái)獲取圖像的角點(diǎn)特征,然后進(jìn)行相應(yīng)的矯正處理,這種方法由于要遍歷整個(gè)圖像的每一個(gè)像素點(diǎn),其需處理的數(shù)據(jù)量較大、效率較低。三是采用模板匹配的方法,提取答題卡圖像四個(gè)角的定位標(biāo)識(shí),然后進(jìn)行幾何變換達(dá)到答題卡圖像的矯正效果。這種方法可以彌補(bǔ)方法一和方法二的不足,更適用答題卡圖像的識(shí)別。
根據(jù)答題卡圖像的矯正需求的分析,對(duì)以上幾種方法進(jìn)行分析實(shí)驗(yàn),本系統(tǒng)采用第三種方法即模板匹配的方法,獲取答題卡四個(gè)角的定位標(biāo)識(shí),然后根據(jù)各個(gè)角的定位信息對(duì)答題卡圖像進(jìn)行幾何變換,來(lái)實(shí)現(xiàn)對(duì)答題卡圖像的平移旋轉(zhuǎn)矯正。
模板匹配
模板匹配被認(rèn)為是在圖像識(shí)別中的一種最基本的模式識(shí)別方法。有以下三種常用的方法:
(1)基于特征的模板匹配算法[5]。其基本思想是提取圖像的特征,以生成的特征描述子的相似度為標(biāo)準(zhǔn),匹配這兩幅圖像的特征。其特征主要可以分為點(diǎn)、邊緣、區(qū)域或面等特征。經(jīng)實(shí)驗(yàn)驗(yàn)證,此算法最大的缺陷在于需要在圖像中提取出特征,需要比其它兩種算法多出一定的計(jì)算量和時(shí)間,不適用于本系統(tǒng)。
(2)基于形狀的模板匹配算法[6],其最佳匹配位置在模板圖像內(nèi),由像素的梯度向量?jī)?nèi)積總和,以及最小值決定,其優(yōu)點(diǎn)就是穩(wěn)定性和可靠性都比較優(yōu)越,但是運(yùn)算量相比較而言較大,處理時(shí)間也較長(zhǎng),不適用于本系統(tǒng),為了提高答題卡識(shí)別的效率,需要找到更快速更高效的方法。
(3)基于灰度值的模板匹配算法[7],即相似度是通過(guò)計(jì)算模板圖像與圖像之間灰度值來(lái)計(jì)算的,若以圖像的形式表示模板圖像塊時(shí),根據(jù)模板圖像塊與圖像中各個(gè)部分的相似度,去判斷該模板圖像塊是否存在于這幅圖像中,并求其位置的操作。由于在答題卡設(shè)計(jì)的時(shí)候,制定的答題卡的四個(gè)角的黑色方塊比較顯著,并且進(jìn)行模板匹配的圖像是二值圖像,因此答題卡的定位信息的特征變得很明顯很簡(jiǎn)單。經(jīng)過(guò)試驗(yàn),發(fā)現(xiàn)基于灰度值的模板匹配算法配合答題卡圖像的定位信息的特征,能夠取得相當(dāng)不錯(cuò)的效果。
在本系統(tǒng)中,答題卡圖像四個(gè)角的定位標(biāo)識(shí)顯著地分布在答題卡的四個(gè)邊角位置,所以,為了提高模板匹配的效率,先將答題卡圖像分為四個(gè)部分,分別是左上部分、右上部分、左下部分、右下部分;其次定義一個(gè)模板圖像塊;然后將模板圖像塊分別在這四個(gè)部分的圖像上,從上至下,從左至右以像素點(diǎn)為單位進(jìn)行滑動(dòng),將兩個(gè)圖像的像素值進(jìn)行對(duì)比,選擇相似度最高的部分標(biāo)記當(dāng)遇到相似度更高的部分時(shí),更換標(biāo)記部分;最后,掃描完畢,將四個(gè)部分相似度最高的部分標(biāo)記出來(lái)并進(jìn)行輸出操作。
基于灰度值的模板匹配算法的整個(gè)具體流程:
(1)設(shè)答題卡圖像目標(biāo)函數(shù)為﹐答題卡圖像大小為24803508像素,把答題卡圖像分成四個(gè)部分:①左上部分、②右上部分、③左下部分、④右下部分,每個(gè)部分大小為12401754像素如圖。
10.幾何變換
圖像的幾何變換是指一個(gè)圖像的新坐標(biāo)位置由另一個(gè)圖像的坐標(biāo)位置映射而來(lái)的。其特點(diǎn)就是使圖像像素的空間位置改變,而不是對(duì)其像素的灰度值改變,這可以消除圖像采集時(shí)出現(xiàn)的幾何形變。它是圖像處理與分析的基礎(chǔ)28]。設(shè)標(biāo)準(zhǔn)圖像函數(shù)f(x,y),實(shí)際圖像函數(shù)g(x,y),把原圖像素點(diǎn)(x,y%)的坐標(biāo)與目標(biāo)圖像新像素點(diǎn)(x ‘, y’)的映射關(guān)系可表示為見(jiàn)式:
其中,f(x。,y,)和g(x,y%)是坐標(biāo)變換函數(shù),利用標(biāo)準(zhǔn)圖像和實(shí)際圖像中的已知的對(duì)應(yīng)像素點(diǎn)來(lái)推算出圖像間的幾何變換。
考慮到圖像可能會(huì)在采集時(shí),產(chǎn)生形變或者傾斜。因此,答題卡圖像的平移旋轉(zhuǎn)矯正處理必須進(jìn)行。幾何變換主要有坐標(biāo)映射、仿射變換等。
(1)坐標(biāo)映射
圖像的坐標(biāo)映射是建立一種映射關(guān)系在原圖像與目標(biāo)圖像之間,這種映射關(guān)系有兩種,一種是計(jì)算變換后圖像像素點(diǎn)反映射在原圖像的坐標(biāo)位置,另一種是計(jì)算原圖像像素點(diǎn)在映射后圖像的坐標(biāo)位置[2%]。由于這種映射關(guān)系并不能達(dá)到矯正答題卡圖像的效果,所以不適用于本系統(tǒng)的答題卡圖像矯正。
(2)透視變換
透視變換就是二維坐標(biāo)到三維坐標(biāo)再到另一個(gè)二維坐標(biāo)空間的映射。透視變換過(guò)程就是已知標(biāo)準(zhǔn)答題卡和待閱答題卡角定位點(diǎn)坐標(biāo),通過(guò)透視變換見(jiàn)式,計(jì)算出透視變換矩陣,根據(jù)映射關(guān)系可以得出透視變換后的圖像的坐標(biāo)點(diǎn),這樣就實(shí)現(xiàn)對(duì)答題卡圖像的矯正。
在公式中,(x ‘, y’,w’)表示原圖像,(u, v, w)表示待閱答題卡圖像,用于圖像透視變換的實(shí)現(xiàn),[as,as]表示平移圖像,透視變換矩陣即相對(duì)于仿射變換,透視變換具有很高的靈活性。但是由于它是三維坐標(biāo)之間的變換,故不適合本系統(tǒng)。
(3)仿射變換
圖像的仿射變換是空間直角坐標(biāo)系中二維坐標(biāo)之間的線性變換[30l。它主要實(shí)現(xiàn)平移、縮放、旋轉(zhuǎn)等相關(guān)幾何操作,操作之后,依然保持其“平直性”和“平行性”的特點(diǎn)。
在保證攝像頭的光軸要與答題卡所在平面垂直、光照、攝像頭的性能等環(huán)境因素達(dá)到最佳的情況下,通過(guò)攝像頭采集圖像時(shí),圖像絕大部分程度上都有發(fā)生一定的平移旋轉(zhuǎn),這屬于平面上的平移旋轉(zhuǎn),而仿射變換正好是發(fā)生在平面內(nèi)的二維坐標(biāo)之間的變換,即可以這樣理解,圖像仿射變換的過(guò)程基本就是圖像平移旋轉(zhuǎn)矯正的過(guò)程;因此,采用仿射變換實(shí)現(xiàn)對(duì)答題卡圖像的平移旋轉(zhuǎn)矯正,更適用于本系統(tǒng)。
要實(shí)現(xiàn)答題卡圖像的平移旋轉(zhuǎn)矯正,必須先提取答題卡模板圖像和待閱答題卡圖像四個(gè)角定位點(diǎn)坐標(biāo)信息,這可以通過(guò)模板匹配獲取;由于答題卡模板圖像的每個(gè)角的定位點(diǎn)坐標(biāo)和實(shí)際答題卡圖像的每個(gè)角的定位點(diǎn)坐標(biāo)一一對(duì)應(yīng),并且三個(gè)點(diǎn)就可確定一個(gè)面,所以可以只需要三對(duì)角定位點(diǎn)坐標(biāo),根據(jù)三對(duì)角定位點(diǎn)坐標(biāo)之間的映射關(guān)系來(lái)實(shí)現(xiàn)答題卡圖像的矯正。
11.填涂信息識(shí)別
通過(guò)對(duì)答題卡圖像的涂點(diǎn)定位,獲取并標(biāo)記了每個(gè)矩形定位點(diǎn)信息的左上角坐標(biāo),接下來(lái)就可對(duì)每個(gè)矩形定位點(diǎn)進(jìn)行填涂信息識(shí)別。填涂信息識(shí)別就是將考生的準(zhǔn)考證號(hào)或?qū)W號(hào)和填涂的答案進(jìn)行標(biāo)記并且輸出的過(guò)程。常用的填涂信息識(shí)別算法有以下4種:
(1)基于支持向量機(jī)的填涂信息識(shí)別
基于支持向量機(jī)的填涂信息識(shí)別其基本步驟如下,第一,對(duì)各個(gè)矩形定位信息點(diǎn)與水平定位信息的相對(duì)坐標(biāo)模板進(jìn)行定義;第二,對(duì)水平定位信息區(qū)域進(jìn)行圖像分割;第三,提取各個(gè)水平定位信息點(diǎn)重心;第四,根據(jù)各個(gè)矩形定位信息點(diǎn)與水平定位信息的相對(duì)坐標(biāo)模板,提取各個(gè)矩形定位信息點(diǎn)初步識(shí)別的范圍;第五,向量集根據(jù)各個(gè)矩形定位信息點(diǎn)最初識(shí)別的范圍及定義的環(huán)境因子來(lái)構(gòu)造;第六,輸入向量機(jī),采用支持向量機(jī)對(duì)其進(jìn)行訓(xùn)練與識(shí)別,獲得結(jié)果。
(2)基于決策樹(shù)的填涂信息識(shí)別
基于決策樹(shù)的填涂信息識(shí)別其基本步驟是:首先采用人工標(biāo)注的形式從答題卡中抽取矩形定位信息點(diǎn)構(gòu)建訓(xùn)練集和測(cè)試集,在訓(xùn)練集和測(cè)試集中,分別有未填涂與填涂矩形定位信息點(diǎn)兩類,其次,設(shè)定其離散化閾值T,把訓(xùn)練集中答題卡的矩形定位信息點(diǎn)分割成m個(gè)大小相同的小矩形,計(jì)算所有小矩形的占空比,根據(jù)T將其離散成信息特征,然后,將m+1個(gè)特征構(gòu)成特征向量的結(jié)構(gòu),來(lái)構(gòu)建矩形定位信息點(diǎn)的決策樹(shù),最后,使用測(cè)試集測(cè)試決策樹(shù)的速度和準(zhǔn)確度[1]。
(3)基于模板匹配的填涂信息識(shí)別
模板匹配是指將答題卡的矩形定位信息點(diǎn)作為模板圖像,將一個(gè)題中的一組選項(xiàng)作為實(shí)際圖像,在實(shí)際圖像中,從上至下,從左至右以像素點(diǎn)為單位進(jìn)行滑動(dòng),將兩幅圖像的像素值進(jìn)行對(duì)比,選擇相似度最高的部分標(biāo)記并輸出,根據(jù)匹配的量化結(jié)果得出矩形定位信息點(diǎn)是否被填涂。
(4)基于平均灰度值的填涂信息識(shí)別
基于平均灰度值的填涂信息識(shí)別的基本思想是通過(guò)計(jì)算矩形定位信息點(diǎn)的像素的平均灰度值來(lái)判斷該點(diǎn)是否被填涂。如果一道題目中的某個(gè)矩形定位信息點(diǎn)的平均灰度值最大,則表示該點(diǎn)被填涂。因此,設(shè)sum為矩形定位信息點(diǎn)的像素點(diǎn)總數(shù),A[i,j]表示坐標(biāo)[i,j]處的像素點(diǎn)的灰度值,則計(jì)算每一道題的矩形定位信息點(diǎn)的像素的平均灰度值 erog。見(jiàn)式:
12.系統(tǒng)整合
下圖[完整源碼&環(huán)境部署視頻教程&自定義UI界面]
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-857697.html
參考博客《基于計(jì)算機(jī)視覺(jué)OpenCV的答題卡識(shí)別系統(tǒng)》文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-857697.html
到了這里,關(guān)于【實(shí)戰(zhàn)精選】基于計(jì)算機(jī)視覺(jué)OpenCV的答題卡識(shí)別系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!