日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

python基于OpenCV模板匹配識別圖片中的數(shù)字

瀏覽:215日期:2022-06-23 16:54:32
前言

本博客主要實現(xiàn)利用OpenCV的模板匹配識別圖像中的數(shù)字,然后把識別出來的數(shù)字輸出到txt文件中,如果識別失敗則輸出“讀取失敗”。

操作環(huán)境:

OpenCV - 4.1.0 Python 3.8.1 程序目標

單個數(shù)字模板:(這些單個模板是我自己直接從圖片上截取下來的)

python基于OpenCV模板匹配識別圖片中的數(shù)字

要處理的圖片:

python基于OpenCV模板匹配識別圖片中的數(shù)字

終端輸出:

python基于OpenCV模板匹配識別圖片中的數(shù)字

文本輸出:

python基于OpenCV模板匹配識別圖片中的數(shù)字

思路講解

python基于OpenCV模板匹配識別圖片中的數(shù)字

代碼講解

首先定義兩個會用到的函數(shù)

第一個是顯示圖片的函數(shù),這樣的話在顯示圖片的時候就比較方便了

def cv_show(name, img): cv2.imshow(name, img) cv2.waitKey(0) cv2.destroyAllWindows()

第二個是圖片縮放的函數(shù)

def resize(image, width=None, height=None, inter=cv2.INTER_AREA): dim = None (h, w) = image.shape[:2] if width is None and height is None: return image if width is None: r = height / float(h) dim = (int(w * r), height) else: r = width / float(w) dim = (width, int(h * r)) resized = cv2.resize(image, dim, interpolation=inter) return resized

先把這個代碼貼出來,方便后面單個函數(shù)代碼的理解。

if __name__ == '__main__': # 存放數(shù)字模板列表 digits = [] # 當前運行目錄 now_dir = os.getcwd() print('當前運行目錄:' + now_dir) numbers_address = now_dir + 'numbers' load_digits() times = input('請輸入程序運行次數(shù):') for i in range(1, int(times) + 1): demo(i) print('輸出成功,請檢查本地temp.txt文件') while True: if input('輸入小寫‘q’并回車退出') == ’q’: break

接下來是第一個主要函數(shù),功能是加載數(shù)字模板并進行處理。

這個函數(shù)使用到了os模塊,所以需要在開頭import os

def load_digits(): # 加載數(shù)字模板 path = numbers_address # 這個地方就是獲取當前運行目錄 獲取函數(shù)在主函數(shù)里面 filename = os.listdir(path) # 獲取文件夾文件 for file in filename: img = cv2.imread(numbers_address + '' + file) # 讀取圖片 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度處理 # 自動閾值二值化 把圖片處理成黑底白字 img_temp = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] # 尋找數(shù)字輪廓 cnt = cv2.findContours(img_temp, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # 獲取數(shù)字矩形輪廓 x, y, w, h = cv2.boundingRect(cnt[0]) # 將單個數(shù)字區(qū)域進行縮放并存到列表中以備后面使用 digit_roi = cv2.resize(img_temp[y:y+h, x:x+w], (57, 88)) digits.append(digit_roi)

最后一個函數(shù)是程序的重點,實現(xiàn)功能就是識別出數(shù)字并輸出。

不過這里把這個大函數(shù)分開兩部分來講解。

第一部分是對圖片進行處理,最終把圖片中的數(shù)字區(qū)域圈出來。

# 這兩個都是核,參數(shù)可以改變 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 這個就是讀取圖片的,可以暫時不理解 target_path = now_dir + '' + 'demo_' + str(index) + '.png' img_origin = cv2.imread(target_path) # 對圖片進行縮放處理 img_origin = resize(img_origin, width=300) # 灰度圖 img_gray = cv2.cvtColor(img_origin, cv2.COLOR_BGR2GRAY) # 高斯濾波 參數(shù)可以改變,選擇效果最好的就可以 gaussian = cv2.GaussianBlur(img_gray, (5, 5), 1)、 # 自動二值化處理,黑底白字 img_temp = cv2.threshold( gaussian, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] # 頂帽操作 img_top = cv2.morphologyEx(img_temp, cv2.MORPH_TOPHAT, rectKernel) # sobel操作 img_sobel_x = cv2.Sobel(img_top, cv2.CV_64F, 1, 0, ksize=7) img_sobel_x = cv2.convertScaleAbs(img_sobel_x) img_sobel_y = cv2.Sobel(img_top, cv2.CV_64F, 0, 1, ksize=7) img_sobel_y = cv2.convertScaleAbs(img_sobel_y) img_sobel_xy = cv2.addWeighted(img_sobel_x, 1, img_sobel_y, 1, 0) # 閉操作 img_closed = cv2.morphologyEx(img_sobel_xy, cv2.MORPH_CLOSE, rectKernel) # 自動二值化 thresh = cv2.threshold( img_closed, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 閉操作 img_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) # 尋找數(shù)字輪廓 cnts = cv2.findContours( img_closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # 輪廓排序 (cnts, boundingBoxes) = contours.sort_contours(cnts, 'top-to-bottom') # 存放正確數(shù)字序列(包含逗號)的輪廓,即過濾掉不需要的輪廓 right_loc = [] # 下面這個循環(huán)是對輪廓進行篩選,只有長寬比例大于2的才可以被添加到列表中 # 這個比例可以根據(jù)具體情況來改變。除此之外,還可以通過輪廓周長和輪廓面積等對輪廓進行篩選 for c in cnts: x, y, w, h = cv2.boundingRect(c) ar = w/float(h) if ar > 2: right_loc.append((x, y, w, h))

部分步驟的效果圖:

python基于OpenCV模板匹配識別圖片中的數(shù)字

可以看到在進行完最后一次閉操作后,一串數(shù)字全部變成白色區(qū)域,這樣再進行輪廓檢測就可以框出每一行數(shù)字的大致范圍,這樣就可以縮小數(shù)字處理的范圍,可以在這些具體的區(qū)域內(nèi)部對單個數(shù)字進行處理。

輪廓效果:

python基于OpenCV模板匹配識別圖片中的數(shù)字

在這樣進行以上步驟之后,就可以確定一行數(shù)字的范圍了,下面就進行輪廓篩選把符合條件的輪廓存入列表。

注意:在代碼中使用了(cnts, boundingBoxes) = contours.sort_contours(cnts, 'top-to-bottom')

這個函數(shù)的使用需要導入imutils,這個模塊具體使用方法可以瀏覽我的另一篇博客OpenCV學習筆記

函數(shù)的最后一部分就是對每個數(shù)字輪廓進行分割,取出單個數(shù)字的區(qū)域然后進行模板匹配。

for (gx, gy, gw, gh) in right_loc: # 用于存放識別到的數(shù)字 digit_out = [] # 下面兩個判斷主要是防止出現(xiàn)越界的情況發(fā)生,如果發(fā)生的話圖片讀取會出錯 if (gy-10 < 0): now_gy = gy else: now_gy = gy-10 if (gx - 10 < 0): now_gx = gx else: now_gx = gx-10 # 選擇圖片興趣區(qū)域 img_digit = gaussian[now_gy:gy+gh+10, now_gx:gx+gw+10] # 二值化處理 img_thresh = cv2.threshold( img_digit, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] # 尋找所有輪廓 找出每個數(shù)字的輪廓(包含逗號) 正確的話應該有9個輪廓 digitCnts = cv2.findContours( img_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # 從左到右排列輪廓 # 這樣排列的好處是,正常情況下可以確定逗號的位置方便后面刪除逗號 (cnts, boundingBoxes) = contours.sort_contours(digitCnts, 'left-to-right') # cnts是元組,需要先轉(zhuǎn)換成列表,因為后面會對元素進行刪除處理 cnts = list(cnts) flag = 0 # 判斷輪廓數(shù)量是否有9個 if len(cnts) == 9: # 刪除逗號位置 del cnts[1] del cnts[2] del cnts[3] del cnts[4] # 可以在轉(zhuǎn)成元組 cnts = tuple(cnts) # 存放單個數(shù)字的矩形區(qū)域 num_roi = [] for c in cnts: x, y, w, h = cv2.boundingRect(c) num_roi.append((x, y, w, h)) # 對數(shù)字區(qū)域進行處理,把尺寸縮放到與數(shù)字模板相同 # 對其進行簡單處理,方便與模板匹配,增加匹配率 for (rx, ry, rw, rh) in num_roi: roi = img_digit[ry:ry+rh, rx:rx+rw] roi = cv2.resize(roi, (57, 88)) # 高斯濾波 roi = cv2.GaussianBlur(roi, (5, 5), 1) # 二值化 roi = cv2.threshold( roi, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] # 用于存放匹配率 source = [] # 遍歷數(shù)字模板 for digitROI in digits: # 進行模板匹配 res = cv2.matchTemplate( roi, digitROI, cv2.TM_CCOEFF_NORMED) max_val = cv2.minMaxLoc(res)[1] source.append(max_val) # 這個需要仔細理解 這個就是把0-9數(shù)字中匹配度最高的數(shù)字存放到列表中 digit_out.append(str(source.index(max(source)))) # 打印最終輸出值 print(digit_out) else: print('讀取失敗') flag = 1 # 將數(shù)字輸出到txt文本中 t = ’’ with open(now_dir + 'temp.txt', ’a+’) as q: if flag == 0: for content in digit_out: t = t + str(content) + ' ' q.write(t.strip(' ')) q.write(’n’) t = ’’ else: q.write('讀取失敗') q.write(’n’)

注意理解:digit_out.append(str(source.index(max(source))))

這個是很重要的,列表source存放模板匹配的每個數(shù)字的匹配率,求出其中最大值的索引值,因為數(shù)字模板是按照0-9排列的,索引source的匹配率也是按照0-9排列的,所以每個元素的索引值就與相匹配的數(shù)字相同。這樣的話,取得最大值的索引值就相當于取到了匹配率最高的數(shù)字。

完整代碼

from imutils import contoursimport cv2import osdef cv_show(name, img): cv2.imshow(name, img) cv2.waitKey(0) cv2.destroyAllWindows()def resize(image, width=None, height=None, inter=cv2.INTER_AREA): dim = None (h, w) = image.shape[:2] if width is None and height is None: return image if width is None: r = height / float(h) dim = (int(w * r), height) else: r = width / float(w) dim = (width, int(h * r)) resized = cv2.resize(image, dim, interpolation=inter) return resizeddef load_digits(): # 加載數(shù)字模板 path = numbers_address filename = os.listdir(path) for file in filename: # print(file) img = cv2.imread( numbers_address + '' + file) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_temp = cv2.threshold( img_gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] cnt = cv2.findContours(img_temp, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)[0] x, y, w, h = cv2.boundingRect(cnt[0]) digit_roi = cv2.resize(img_temp[y:y+h, x:x+w], (57, 88)) # 將數(shù)字模板存到列表中 digits.append(digit_roi)def demo(index): rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) target_path = now_dir + '' + 'demo_' + str(index) + '.png' img_origin = cv2.imread(target_path) img_origin = resize(img_origin, width=300) img_gray = cv2.cvtColor(img_origin, cv2.COLOR_BGR2GRAY) gaussian = cv2.GaussianBlur(img_gray, (5, 5), 1) img_temp = cv2.threshold( gaussian, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] img_top = cv2.morphologyEx(img_temp, cv2.MORPH_TOPHAT, rectKernel) img_sobel_x = cv2.Sobel(img_top, cv2.CV_64F, 1, 0, ksize=7) img_sobel_x = cv2.convertScaleAbs(img_sobel_x) img_sobel_y = cv2.Sobel(img_top, cv2.CV_64F, 0, 1, ksize=7) img_sobel_y = cv2.convertScaleAbs(img_sobel_y) img_sobel_xy = cv2.addWeighted(img_sobel_x, 1, img_sobel_y, 1, 0) img_closed = cv2.morphologyEx(img_sobel_xy, cv2.MORPH_CLOSE, rectKernel) thresh = cv2.threshold( img_closed, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] img_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) cnts = cv2.findContours( img_closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] (cnts, boundingBoxes) = contours.sort_contours(cnts, 'top-to-bottom') draw_img = img_origin.copy() draw_img = cv2.drawContours(draw_img, cnts, -1, (0, 0, 255), 1) cv_show('666', draw_img) # 存放正確數(shù)字序列(包含逗號)的輪廓,即過濾掉不需要的輪廓 right_loc = [] for c in cnts: x, y, w, h = cv2.boundingRect(c) ar = w/float(h) if ar > 2: right_loc.append((x, y, w, h)) for (gx, gy, gw, gh) in right_loc: # 用于存放識別到的數(shù)字 digit_out = [] if (gy-10 < 0): now_gy = gy else: now_gy = gy-10 if (gx - 10 < 0): now_gx = gx else: now_gx = gx-10 img_digit = gaussian[now_gy:gy+gh+10, now_gx:gx+gw+10] # 二值化處理 img_thresh = cv2.threshold( img_digit, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] # 尋找輪廓 找出每個數(shù)字的輪廓(包含逗號) 正確的話應該有9個輪廓 digitCnts = cv2.findContours( img_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # 從左到右排列 (cnts, boundingBoxes) = contours.sort_contours(digitCnts, 'left-to-right') cnts = list(cnts) flag = 0 if len(cnts) == 9: del cnts[1] del cnts[2] del cnts[3] del cnts[4] cnts = tuple(cnts) num_roi = [] for c in cnts: x, y, w, h = cv2.boundingRect(c) num_roi.append((x, y, w, h)) for (rx, ry, rw, rh) in num_roi: roi = img_digit[ry:ry+rh, rx:rx+rw] roi = cv2.resize(roi, (57, 88)) roi = cv2.GaussianBlur(roi, (5, 5), 1) roi = cv2.threshold( roi, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] source = [] for digitROI in digits: res = cv2.matchTemplate( roi, digitROI, cv2.TM_CCOEFF_NORMED) max_val = cv2.minMaxLoc(res)[1] source.append(max_val) digit_out.append(str(source.index(max(source)))) cv2.rectangle(img_origin, (gx-5, gy-5), (gx+gw+5, gy+gh+5), (0, 0, 255), 1) print(digit_out) else: print('讀取失敗') flag = 1 t = ’’ with open(now_dir + 'temp.txt', ’a+’) as q: if flag == 0: for content in digit_out: t = t + str(content) + ' ' q.write(t.strip(' ')) q.write(’n’) t = ’’ else: q.write('讀取失敗') q.write(’n’)if __name__ == '__main__': # 存放數(shù)字模板列表 digits = [] # 當前運行目錄 now_dir = os.getcwd() print('當前運行目錄:' + now_dir) numbers_address = now_dir + 'numbers' load_digits() times = input('請輸入程序運行次數(shù):') for i in range(1, int(times) + 1): demo(i) print('輸出成功,請檢查本地temp.txt文件') cv2.waitKey(0) cv2.destroyAllWindows() while True: if input('輸入小寫‘q’并回車退出') == ’q’: break

整個文件下載地址:https://wwe.lanzous.com/iLSDunf850b

注意:如果想同時識別多個圖片話,需要將圖片統(tǒng)一改名為“demo_ + 數(shù)字序號.png” 例如:demo_1.png demo_2.png 同時在運行代碼時輸入圖片個數(shù)即可。

總結(jié)

這個程序代碼相對來說不算復雜,主要是對圖像的一些基礎處理需要注意。因為不同的圖像想要識別成功需要進行不同程度的基礎處理,所以在做的時候可以多輸出幾張圖片檢查一下那一步效果不太好并及時進行修改調(diào)整,這樣才能達到最終比較好的效果。

以上就是python基于OpenCV模板匹配識別圖片中的數(shù)字的詳細內(nèi)容,更多關(guān)于python 識別圖片中的數(shù)字的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標簽: Python 編程
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
神马午夜在线视频| av高清一区| 先锋亚洲精品| 日韩中文字幕区一区有砖一区| 香蕉久久99| 一区二区自拍| 蜜桃视频第一区免费观看| 啪啪国产精品| 婷婷亚洲综合| 蜜桃av一区二区| 亚洲精品伊人| 欧美视频一区| 精品国产一区二区三区av片| 麻豆国产一区| 91综合网人人| 欧美日韩激情在线一区二区三区| 日韩午夜免费| 日韩精品91亚洲二区在线观看| 国产乱码精品一区二区亚洲| 美女视频黄久久| 久久理论电影| 亚洲精品美女91| 国产亚洲字幕| 日本久久精品| 亚洲欧美日本国产专区一区| 欧美天堂一区二区| 免费高潮视频95在线观看网站| 九九久久婷婷| 日韩精品高清不卡| 91一区二区| 综合激情视频| 久久久久久色 | 久久婷婷一区| 午夜在线一区二区| 久久99久久久精品欧美| 色老板在线视频一区二区| 在线国产精品一区| 麻豆一区二区在线| 欧美在线资源| 国产精品激情电影| 亚洲欧美日韩高清在线| 日本欧美韩国一区三区| 欧美少妇精品| 亚洲激情另类| 美女尤物国产一区| 亚洲欧美日韩视频二区| 精品久久中文| 蜜臀a∨国产成人精品| 国产激情综合| 亚洲欧美日韩国产一区| 久久久久亚洲精品中文字幕| 亚洲免费中文| 日韩一区欧美| 久久国产视频网| 免费观看不卡av| 麻豆精品视频在线| 国产精品日本| 91日韩免费| 亚洲乱亚洲高清| 久久香蕉国产| 国语对白精品一区二区| 亚洲精品人人| 久久久久美女| 国产aⅴ精品一区二区四区| 日韩欧乱色一区二区三区在线| 日韩电影在线视频| 国产欧美自拍一区| 亚洲丝袜啪啪| 激情欧美一区二区三区| 高清久久一区| 久久精品一区| 69堂精品视频在线播放| 亚洲一区二区三区无吗| av高清不卡| 精品资源在线| 国产伦理一区| 日本a级不卡| 性一交一乱一区二区洋洋av| 精品欧美一区二区三区在线观看| 国产精品99久久免费| 日韩中文av| 欧美日韩国产高清电影| 日韩视频网站在线观看| 成人精品高清在线视频| 另类欧美日韩国产在线| 国产欧美高清视频在线| 日韩黄色在线观看| 亚洲一级淫片| 午夜精品一区二区三区国产| 日韩精品专区| 92国产精品| 日韩理论视频| 98精品视频| 高清av一区| 日产精品一区二区| 久久精品欧洲| 久久精品国产999大香线蕉| 国产欧美日韩一级| 久久国内精品视频| 青青伊人久久| 国产精品一区二区免费福利视频| 国产亚洲欧美日韩精品一区二区三区| 日韩 欧美一区二区三区| 在线综合亚洲| 蜜臀av国产精品久久久久| 中文字幕日本一区二区| 亚洲专区视频| 青草国产精品| 久久99青青| 黄毛片在线观看| 黄色亚洲在线| 亚洲色图网站| 国产欧美久久一区二区三区| 精品视频97| 91精品综合| 亚洲专区视频| 麻豆视频一区二区| 欧美久久精品| 精品视频91| 在线亚洲人成| 一区免费在线| 日韩av资源网| 国产黄色精品| 欧洲av一区二区| 亚洲一二三区视频| 卡一卡二国产精品| 国产一区日韩欧美| 婷婷成人av| 久久国产生活片100| 日韩av成人高清| 精品国产乱码久久久| 麻豆中文一区二区| 日本久久成人网| 国产精品精品国产一区二区| 欧美激情网址| 国产日产精品_国产精品毛片| 国产精品黑丝在线播放| 日韩中文在线电影| 久久久成人网| 国产亚洲毛片在线| 亚州欧美在线| 欧美日韩黄网站| 久久久亚洲欧洲日产| 久久免费精品| 国产婷婷精品| 日韩精品视频在线看| 午夜精品免费| 国产精品日本一区二区三区在线| 国产日本亚洲| 日产精品一区二区| 亚洲欧美日韩高清在线| 日韩在线麻豆| 日韩国产激情| 国产手机视频一区二区| 婷婷综合一区| 精品视频91| 激情综合亚洲| 中文久久精品| 色婷婷亚洲mv天堂mv在影片| 91精品电影| 日韩国产欧美三级| 亚洲美女久久精品| 国产一区福利| 亚洲免费观看| 国产欧美一级| 激情欧美一区二区三区| 日韩精品欧美成人高清一区二区| 日韩欧美综合| 日韩三级精品| 日韩久久精品| 日韩欧美2区| av在线日韩| 老牛国内精品亚洲成av人片 | 国产精品国产三级国产在线观看| www成人在线视频| 综合激情视频| 亚洲欧洲日韩精品在线| 亚洲v在线看| 97成人在线| 欧美日韩一二三四| 国产精品一卡| 好吊视频一区二区三区四区| 成人精品久久| 日韩高清在线不卡| 亚洲国产影院| 精品资源在线| 精品国产精品久久一区免费式| 亚洲久久一区| 久久裸体视频| 国产激情一区| 欧美女激情福利| 日本成人在线不卡视频| 另类激情亚洲| zzzwww在线看片免费| 日韩精品电影一区亚洲| 国产精品av久久久久久麻豆网| 国产精品一区二区三区美女| 日韩精品午夜视频| 女人av一区| 日韩欧美午夜|