主頁(yè) > 知識(shí)庫(kù) > Python+Opencv實(shí)現(xiàn)數(shù)字識(shí)別的示例代碼

Python+Opencv實(shí)現(xiàn)數(shù)字識(shí)別的示例代碼

熱門標(biāo)簽:n400電話申請(qǐng)多少錢 ai地圖標(biāo)注 廈門crm外呼系統(tǒng)如何 百應(yīng)ai電銷機(jī)器人鄭州 西藏快速地圖標(biāo)注地點(diǎn) 長(zhǎng)春人工智能電銷機(jī)器人官網(wǎng) 如何在地圖標(biāo)注文字 地圖標(biāo)注推廣單頁(yè) 女王谷地圖標(biāo)注

一、什么是數(shù)字識(shí)別?

  所謂的數(shù)字識(shí)別,就是使用算法自動(dòng)識(shí)別出圖片中的數(shù)字。具體的效果如下圖所示:


上圖展示了算法的處理效果,算法能夠自動(dòng)的識(shí)別到LCD屏幕上面的數(shù)字,這在現(xiàn)實(shí)場(chǎng)景中具有很大的實(shí)際應(yīng)用價(jià)值。下面我們將對(duì)它的實(shí)現(xiàn)細(xì)節(jié)進(jìn)行詳細(xì)解析。

二、如何實(shí)現(xiàn)數(shù)字識(shí)別?

  對(duì)于數(shù)字識(shí)別這個(gè)任務(wù)而言,它并不是一個(gè)新的研究方向,很久之前就有很多的學(xué)者們?cè)陉P(guān)注這個(gè)問題,并提出了一些可行的解決方案,本小節(jié)我們將對(duì)這些方案進(jìn)行簡(jiǎn)單的總結(jié)。

方案一:使用現(xiàn)成的OCR技術(shù)。 OCR,即文字識(shí)別,它是一個(gè)比較成熟的技術(shù),當(dāng)前已經(jīng)具有很多性能優(yōu)異的開源工具包可以供大家使用,即我們僅僅需要關(guān)注的是如何調(diào)用這些接口即可,如何你想要了解它們的實(shí)現(xiàn)細(xì)節(jié),那么你就需要去詳細(xì)的理解源碼啦。除此之外,當(dāng)前的OCR算法已經(jīng)可以很好的識(shí)別圖像中的簡(jiǎn)單文字和數(shù)字等,當(dāng)前研究的一個(gè)熱點(diǎn)是如何準(zhǔn)確快速的識(shí)別出圖片中的傾斜文本和不同語(yǔ)言的文字等,下圖展示了一個(gè)簡(jiǎn)單的識(shí)別樣例,即識(shí)別筆筒上面的文字。

方案二:使用深度神經(jīng)網(wǎng)絡(luò)。 隨著深度學(xué)習(xí)技術(shù)的快速發(fā)展,神經(jīng)網(wǎng)絡(luò)被引入到計(jì)算機(jī)視覺當(dāng)中的多個(gè)領(lǐng)域中,對(duì)于數(shù)字識(shí)別這個(gè)簡(jiǎn)單的任務(wù)而言,神經(jīng)網(wǎng)絡(luò)可以獲得準(zhǔn)確的識(shí)別結(jié)果,比較有名的是mnist數(shù)據(jù)集。但是這種方法首先需要用戶收集大量的數(shù)據(jù)集;然后需要進(jìn)行模型訓(xùn)練和參數(shù)調(diào)節(jié);通常需要花費(fèi)較大的人力和物力。

方案三:使用本文的思路,即根據(jù)七段數(shù)碼管的知識(shí)識(shí)別LCD上的數(shù)字。 這種方法適用于識(shí)別LCD屏幕上的數(shù)字,當(dāng)然通過合理的擴(kuò)展,也可以用來識(shí)別LCD上面的文字;該算法不僅具有較快的識(shí)別速度,而且可以取得較高的識(shí)別精度。

三、識(shí)別LCD屏幕上面的數(shù)字的原理詳解

  在現(xiàn)實(shí)生活中,我們經(jīng)常會(huì)看到各種各樣的LCD屏幕,小到我們的MP3,大到廣場(chǎng)中的電視等,隨著各種應(yīng)用的不斷出現(xiàn),LCD屏幕頻繁的出現(xiàn)在我們現(xiàn)實(shí)生活中的多個(gè)場(chǎng)景中,而快速、準(zhǔn)確的識(shí)別出LCD上面的數(shù)字就成為了一個(gè)新的剛需,這樣可以極大的節(jié)約人力和物力成本,下面將對(duì)LCD屏幕數(shù)字識(shí)別的原理進(jìn)行說明,知其然不許知其所以然。


上圖展示的是一個(gè)七段數(shù)碼管我們常見的LCD屏幕其實(shí)就是通過七段數(shù)碼管組合而成的,因而了解它的構(gòu)成至關(guān)重要。通過上圖我們可以觀察到這個(gè)數(shù)碼管中含有7段,并用0-6分別標(biāo)出,其實(shí)還有一個(gè)小數(shù)點(diǎn)表示8,這些段下面都有相應(yīng)的led燈,當(dāng)我們需要顯示不同的數(shù)字時(shí)只需要點(diǎn)亮不同段的LED燈即可,這個(gè)原理是不是很簡(jiǎn)單!通過組合不同段,我們可以獲得128種組合(即2的7次方),具體的組合結(jié)果如下圖所示,對(duì)于這128種組合而言,我們只對(duì)其中的0-9這10個(gè)數(shù)字比較感興趣,其它的組合并不是我們關(guān)注的目標(biāo)。



即,我們只對(duì)0-9這10個(gè)數(shù)字的組合比較感興趣,這其實(shí)就是我們常用的數(shù)字,我們可以通過它們組合成任意一個(gè)數(shù)字?。?!通過上圖我們可以觀察到當(dāng)我們點(diǎn)亮特定段的LED等之后,LCD就能顯示出特定的數(shù)字,那么我們可不可以通過判斷不同段的特征來判斷當(dāng)前的數(shù)字呢,這其實(shí)就是本文的實(shí)現(xiàn)思路?。?!

四、算法實(shí)現(xiàn)步驟

  為了完成LCD上面的數(shù)字識(shí)別,我們需要按照如下的步驟進(jìn)行實(shí)現(xiàn)該算法。

  • 步驟1-定位面板上面的LCD的位置。由于LCD屏幕和面板具有較大的亮度差異,我們可以使用邊緣檢測(cè)算法獲得LCD的位置。
  • 步驟2-獲取LCD屏幕。通過上一步我們可以獲得一個(gè)邊緣map;接著我們需要在這個(gè)邊緣map中尋找輪廓;最后最大的矩形區(qū)域即是我們需要的LCD。
  • 步驟3-定位LCD上面的數(shù)字。在獲取到LCD之后,我們感興趣的是LCD上面的數(shù)字,那么我們就需要對(duì)這些數(shù)字進(jìn)行定位,即輸出它們的位置信息。由于LCD上面的數(shù)字和周圍的區(qū)域之間具有較大的差異,因而使用閾值和形態(tài)學(xué)操作就可以很好的完成這個(gè)任務(wù)。
  • 步驟4-進(jìn)行數(shù)字識(shí)別。在獲取到數(shù)字的位置信息后,我們將使用opencv中內(nèi)置的算法對(duì)這些數(shù)字進(jìn)行識(shí)別,從而獲得我們需要的結(jié)果。

五、算法代碼實(shí)現(xiàn)

# coding=utf-8
# 導(dǎo)入一些python包
from imutils.perspective import four_point_transform
from imutils import contours
import imutils
import cv2

# 定義每一個(gè)數(shù)字對(duì)應(yīng)的字段
DIGITS_LOOKUP = {
	(1, 1, 1, 0, 1, 1, 1): 0,
	(0, 0, 1, 0, 0, 1, 0): 1,
	(1, 0, 1, 1, 1, 1, 0): 2,
	(1, 0, 1, 1, 0, 1, 1): 3,
	(0, 1, 1, 1, 0, 1, 0): 4,
	(1, 1, 0, 1, 0, 1, 1): 5,
	(1, 1, 0, 1, 1, 1, 1): 6,
	(1, 0, 1, 0, 0, 1, 0): 7,
	(1, 1, 1, 1, 1, 1, 1): 8,
	(1, 1, 1, 1, 0, 1, 1): 9
}

# 讀取輸入圖片
image = cv2.imread("example.jpg")

# 將輸入圖片裁剪到固定大小
image = imutils.resize(image, height=500)
# 將輸入轉(zhuǎn)換為灰度圖片
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 進(jìn)行高斯模糊操作
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 執(zhí)行邊緣檢測(cè)
edged = cv2.Canny(blurred, 50, 200, 255)
cv2.imwrite('edge.png', edged)

# 在邊緣檢測(cè)map中發(fā)現(xiàn)輪廓
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# 根據(jù)大小對(duì)這些輪廓進(jìn)行排序
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None

# 循環(huán)遍歷所有的輪廓
for c in cnts:
	# 對(duì)輪廓進(jìn)行近似
	peri = cv2.arcLength(c, True)
	approx = cv2.approxPolyDP(c, 0.02 * peri, True)

	# 如果當(dāng)前的輪廓有4個(gè)頂點(diǎn),我們返回這個(gè)結(jié)果,即LCD所在的位置
	if len(approx) == 4:
		displayCnt = approx
		break

# 應(yīng)用視角變換到LCD屏幕上
warped = four_point_transform(gray, displayCnt.reshape(4, 2))
cv2.imwrite('warped.png', warped)
output = four_point_transform(image, displayCnt.reshape(4, 2))

# 使用閾值進(jìn)行二值化
thresh = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv2.imwrite('thresh1.png', thresh)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1, 5))
# 使用形態(tài)學(xué)操作進(jìn)行處理
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
cv2.imwrite('thresh2.png', thresh)

# 在閾值圖像中查找輪廓,然后初始化數(shù)字輪廓列表
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
digitCnts = []

# 循環(huán)遍歷所有的候選區(qū)域
for c in cnts:
	# 計(jì)算輪廓的邊界框
	(x, y, w, h) = cv2.boundingRect(c)

	# 如果當(dāng)前的這個(gè)輪廓區(qū)域足夠大,它一定是一個(gè)數(shù)字區(qū)域
	if w >= 15 and (h >= 30 and h = 40):
		digitCnts.append(c)

# 從左到右對(duì)這些輪廓進(jìn)行排序
digitCnts = contours.sort_contours(digitCnts, method="left-to-right")[0]
digits = []

# 循環(huán)處理每一個(gè)數(shù)字
i = 0
for c in digitCnts:
	# 獲取ROI區(qū)域
	(x, y, w, h) = cv2.boundingRect(c)
	roi = thresh[y:y + h, x:x + w]

	# 分別計(jì)算每一段的寬度和高度
	(roiH, roiW) = roi.shape
	(dW, dH) = (int(roiW * 0.25), int(roiH * 0.15))
	dHC = int(roiH * 0.05)

	# 定義一個(gè)7段數(shù)碼管的集合
	segments = [
		((0, 0), (w, dH)),	             # 上
		((0, 0), (dW, h // 2)),           # 左上
		((w - dW, 0), (w, h // 2)),	         # 右上
		((0, (h // 2) - dHC) , (w, (h // 2) + dHC)), # 中間
		((0, h // 2), (dW, h)),	           # 左下
		((w - dW, h // 2), (w, h)),	         # 右下
		((0, h - dH), (w, h))	           # 下
	]
	on = [0] * len(segments)

	# 循環(huán)遍歷數(shù)碼管中的每一段
	for (i, ((xA, yA), (xB, yB))) in enumerate(segments): # 檢測(cè)分割后的ROI區(qū)域,并統(tǒng)計(jì)分割圖中的閾值像素點(diǎn)
		segROI = roi[yA:yB, xA:xB]
		total = cv2.countNonZero(segROI)
		area = (xB - xA) * (yB - yA)

		# 如果非零區(qū)域的個(gè)數(shù)大于整個(gè)區(qū)域的一半,則認(rèn)為該段是亮的
		if total / float(area) > 0.5:
			on[i]= 1

	# 進(jìn)行數(shù)字查詢并顯示結(jié)果
	digit = DIGITS_LOOKUP[tuple(on)]
	digits.append(digit)
	cv2.rectangle(output, (x, y), (x + w, y + h), (0, 255, 0), 1)
	cv2.putText(output, str(digit), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 255, 0), 2)

# 顯示最終的輸出結(jié)果
print(u"{}{}.{} \u00b0C".format(*digits))
cv2.imshow("Input", image)
cv2.imshow("Output", output)
cv2.waitKey(0)

六、效果展示和分析

 上圖展示了該算法的運(yùn)行結(jié)果和一些中間結(jié)果。第1行第1列表示的是原始的輸入圖片,它和代碼中的image對(duì)應(yīng),我們需要識(shí)別的是LCD面板上面的34.5;第1行第2列表示的是Canny邊緣檢測(cè)算法的檢測(cè)結(jié)果,它對(duì)應(yīng)于代碼中的edged,通過該圖我們可以發(fā)現(xiàn)Canny邊緣檢測(cè)的結(jié)果中含有我們感興趣的目標(biāo),即中間的LCD;第1行第3列表示的是對(duì)輸入的灰度圖片應(yīng)用視角變換后的結(jié)果,即獲得了LCD屏幕所在的位置,它和代碼中的warped相互對(duì)應(yīng);第2行第1列表示的是對(duì)獲取到的LCD屏幕進(jìn)行二值化后的結(jié)果,它和代碼中的thresh 相互對(duì)應(yīng),由于LCD上面的數(shù)字和背景之間具有較大的差異,因而通過簡(jiǎn)單的二值化我們就可以獲得我們感興趣的目標(biāo)-數(shù)字;第2行第2列表示的是對(duì)二值化結(jié)果進(jìn)行形態(tài)學(xué)操作之后的結(jié)果,它和代碼中的thresh 相互對(duì)應(yīng),我們可以發(fā)現(xiàn)執(zhí)行了形態(tài)學(xué)操作之后的結(jié)果更多平滑,同時(shí)過濾掉很多的噪聲,有利于后續(xù)的識(shí)別。


  上圖展示了本算法獲取到的LCD屏幕中的數(shù)字,通過上圖我們可以發(fā)現(xiàn)該算法準(zhǔn)確的獲得了這些數(shù)字的位置信息,有利于后續(xù)的識(shí)別操作。


  上圖展示了算法進(jìn)行數(shù)字識(shí)別的實(shí)現(xiàn)細(xì)節(jié)。即通過遍歷每一個(gè)數(shù)字中的7個(gè)段,并統(tǒng)計(jì)該段中非零像素的個(gè)數(shù),當(dāng)其統(tǒng)計(jì)值大于整個(gè)區(qū)域的一半時(shí),認(rèn)為該段是亮的,當(dāng)統(tǒng)計(jì)完所有的這7個(gè)段之后,在預(yù)定義的數(shù)字詞典中進(jìn)行查找,并輸出最終的結(jié)果即可。


  上圖展示了算法最終的輸出結(jié)果,我們可以觀察到算法快速、準(zhǔn)確的獲得了我們需要的結(jié)果,滿足了我們的預(yù)期。

七、問題擴(kuò)展與延伸

  通過上面的解析你可能已經(jīng)知道了如何來很好的解決上面這個(gè)問題。細(xì)心的你也許會(huì)發(fā)現(xiàn)上述結(jié)果中輸出的點(diǎn)號(hào)是人為添加上去的,并不是算法自動(dòng)獲取的,而在現(xiàn)實(shí)場(chǎng)景中我們經(jīng)常會(huì)遇到小數(shù)點(diǎn),比如溫度、濕度等,那么我的問題來啦,如何利用算法自動(dòng)獲取圖中的小數(shù)點(diǎn),使得算法最終自動(dòng)輸出34.5的結(jié)果呢,這個(gè)問題留給聰明的你進(jìn)行思考吧?。。。ㄆ鋵?shí)數(shù)碼管是有八段的,第八段就是小數(shù)點(diǎn)的?。。。?/p>

參考資料

1、參考鏈接1

到此這篇關(guān)于Python+Opencv實(shí)現(xiàn)數(shù)字識(shí)別的示例代碼的文章就介紹到這了,更多相關(guān)Opencv 數(shù)字識(shí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 詳解Python OpenCV數(shù)字識(shí)別案例
  • python opencv人臉識(shí)別考勤系統(tǒng)的完整源碼
  • Python基于Opencv識(shí)別兩張相似圖片
  • python基于OpenCV模板匹配識(shí)別圖片中的數(shù)字
  • Python OpenCV招商銀行信用卡卡號(hào)識(shí)別的方法
  • Opencv+Python識(shí)別PCB板圖片的步驟
  • python基于opencv實(shí)現(xiàn)人臉識(shí)別
  • python+opencv實(shí)現(xiàn)文字顏色識(shí)別與標(biāo)定功能

標(biāo)簽:亳州 渭南 拉薩 黔東 興安盟 內(nèi)江 綿陽(yáng) 廊坊

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Python+Opencv實(shí)現(xiàn)數(shù)字識(shí)別的示例代碼》,本文關(guān)鍵詞  Python+Opencv,實(shí)現(xiàn),數(shù)字,識(shí),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Python+Opencv實(shí)現(xiàn)數(shù)字識(shí)別的示例代碼》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于Python+Opencv實(shí)現(xiàn)數(shù)字識(shí)別的示例代碼的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章