欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Opencv圖像識別實現(xiàn)答題卡識別示例詳解

 更新時間:2021年12月20日 14:06:43   作者:Hello World怎么寫  
這篇文章主要為大家詳細介紹了基于OpenCV如何實現(xiàn)答題卡識別,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

在觀看唐宇迪老師圖像處理的課程中,其中有一個答題卡識別的小項目,在此結(jié)合自己理解做一個簡單的總結(jié)。

1. 項目分析

首先在拿到項目時候,分析項目目的是什么,要達到什么樣的目標,有哪些需要注意的事項,同時構(gòu)思實驗的大體流程。

圖1. 答題卡測試圖像

比如在答題卡識別的項目中,針對測試圖片如圖1 ,首先應當實現(xiàn)的功能是:

能夠捕獲答題卡中的每個填涂選項。

將獲取的填涂選項與正確選項做對比計算其答題正確率。

2.項目實驗

在對測試圖像進行形態(tài)學操作中,首先轉(zhuǎn)換為灰度圖像,其次是進行減噪的高斯濾波操作。

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
cv_show('blurred',blurred)

在得到高斯濾波結(jié)果后,對其進行邊緣檢測以及輪廓檢測,用以提取答題卡所有內(nèi)容的邊界。

edged = cv2.Canny(blurred, 75, 200)
cv_show('edged',edged)

# 輪廓檢測
cnts, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
	cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(contours_img,cnts,-1,(0,0,255),3) 
cv_show('contours_img',contours_img)
docCnt = None

圖2. 高斯濾波圖

圖3. 邊緣檢測圖

在得到邊緣檢測圖像后,進行外輪廓檢測以及進行透視變換。

# 輪廓檢測
cnts, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
	cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(contours_img,cnts,-1,(0,0,255),3) 
cv_show('contours_img',contours_img)
def four_point_transform(image, pts):
	# 獲取輸入坐標點
	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")

	# 計算變換矩陣
	M = cv2.getPerspectiveTransform(rect, dst)
	warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

	# 返回變換后結(jié)果
	return warped
# 執(zhí)行透視變換

warped = four_point_transform(gray, docCnt.reshape(4, 2))
cv_show('warped',warped)

在透視變換之后,需要再進行二值轉(zhuǎn)換,為了找到ROI圓圈輪廓,采用二次輪廓檢測執(zhí)行遍歷循環(huán)以及 if 判斷找到所有符合篩選條件的圓圈輪廓。此處不使用霍夫變換的原因是在填涂答題卡的過程中,難免會有填涂超過圓圈區(qū)域的情況,使用霍夫變換的直線檢測方式會影響實驗結(jié)果的準確性。

# 找到每一個圓圈輪廓
cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
	cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(thresh_Contours,cnts,-1,(0,0,255),3) 
cv_show('thresh_Contours',thresh_Contours)
questionCnts = []
# 遍歷
for c in cnts:
	# 計算比例和大小
	(x, y, w, h) = cv2.boundingRect(c)
	ar = w / float(h)

	# 根據(jù)實際情況指定標準
	if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:
		questionCnts.append(c)

# 按照從上到下進行排序
questionCnts = sort_contours(questionCnts,
	method="top-to-bottom")[0]
correct = 0

圖4. 輪廓檢測圖

圖5. 透視變換圖

圖6. 二值轉(zhuǎn)換圖

圖7. 輪廓篩選圖

在得到每個圓圈輪廓后,需要將其進行排序,排序方式為從左到右,從上到下,以圖7為例,答題卡分布為五行五列,在每一列中,每行A選項的橫坐標x值是相近的,而在每一行中,A、B、C、D、E的縱坐標y是相近的,因此利用這一特性來對所得到的圓圈輪廓進行排序,代碼如下:

def sort_contours(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

在得到每一個具體輪廓后,便是判斷每道題所填涂的答案是否為正確答案,使用的方法為通過雙層循環(huán)遍歷每一個具體圓圈輪廓,通過mask圖像計算非零點數(shù)量來判斷答案是否正確。

# 每排有5個選項
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
	# 排序
	cnts = sort_contours(questionCnts[i:i + 5])[0]     #從左到右排列,保持順序:A B C D E
	bubbled = None

	# 遍歷每一個結(jié)果
	for (j, c) in enumerate(cnts):
		# 使用mask來判斷結(jié)果
		mask = np.zeros(thresh.shape, dtype="uint8")
		cv2.drawContours(mask, [c], -1, 255, -1) #-1表示填充
		cv_show('mask',mask)
		# 通過計算非零點數(shù)量來算是否選擇這個答案
		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 = ANSWER_KEY[q]

	# 判斷正確
	if k == bubbled[1]:
		color = (0, 255, 0)
		correct += 1
	# 繪圖
	cv2.drawContours(warped, [cnts[k]], -1, color, 3)

圖8. 圓圈輪廓遍歷圖

3.項目結(jié)果

在實驗完成后,輸出實驗結(jié)果

score = (correct / 5.0) * 100
print("[INFO] score: {:.2f}%".format(score))
cv2.putText(warped, "{:.2f}%".format(score), (10, 30),
	cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
cv2.imshow("Exam", warped)
cv2.waitKey(0)
Connected to pydev debugger (build 201.6668.115)
[INFO] score: 100.00%

Process finished with exit code 0

圖9. 答題卡識別結(jié)果圖

總結(jié)

在處理答題卡識別小項目中,個人覺得重點有以下幾個方面:

  1. 圖像的形態(tài)學操作,處理的每一步都應該預先思考,選擇最合適的處理方式,如:未采用霍夫變換而使用了二次輪廓檢測。
  2. 利用mask圖像對比答案正確與否,通過判斷非零像素值的數(shù)量來進行抉擇。
  3. 巧妙利用雙層 for 循環(huán)以及 if 語句遍歷所有圓圈輪廓,排序之后進行答案比對。?

以上就是基于Opencv圖像識別實現(xiàn)答題卡識別示例詳解的詳細內(nèi)容,更多關(guān)于Opencv答題卡識別的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論