1. 程式人生 > >新手上手Tensorflow之手寫數字識別應用(3)

新手上手Tensorflow之手寫數字識別應用(3)

本系列為應用TensorFlow實現手寫數字識別應用的全過程的程式碼實現及細節討論。按照實現流程,分為如下幾部分:
1. 模型訓練並儲存模型
2. 通過滑鼠輸入數字並儲存
2. 影象預處理
4. 讀入模型對輸入的圖片進行識別
本文重點討論影象預處理的問題。
所謂的影象預處理,這裡是指對由滑鼠輸入數字的影象進行分割,並縮放到和樣本相同的尺寸。
這一塊沒有什麼難點,直接上程式碼,註釋寫的比較明確了。

'''
邊緣檢測,裁剪
'''

#  -*- coding: utf-8 -*
import cv2
import numpy as np
import os

#import the image
img = cv2.imread('./img/number.jpg',1) #cv2.imshow('img',img) #轉化為灰度圖 img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #高斯平滑除噪 #img_blur = cv2.GaussianBlur(img,(5,5),0) img_blur = cv2.medianBlur(img_gray,5) #cv2.imshow('Gaussian',img_blur) #canny運算元 邊緣檢測 img_canny = cv2.Canny(img_blur,200,100) #cv2.imshow('canny',img_canny)
#二值化處理 _, img_bin = cv2.threshold(img_canny, 80, 255, cv2.THRESH_BINARY ) #cv2.imshow('bin',img_bin) #積分運算 imgI = cv2.integral(img_bin) #######分塊 #定義分塊的尺寸 (xh,yw) = img_gray.shape p = int(xh / 10) #高度方向上等分的快數 q = int(yw / 10) #寬度方向上等分的快數 #分塊矩陣 sat = np.arange(p*q).reshape(p,q) #獲取原圖的尺寸 #計算每塊的寬和高; w = int(yw / q) h = int(xh / p) if
w <= 5: print('the image is too small to split!') os._exit(0) #print(w,h) #合併塊 sated = np.ones((p,q)) p = range(p) q = range(q) # 計算各塊的能量 sat[0][0] = imgI[h-1][w-1] for n in q[1:]: #先計算第0行的能量 sat[0][n] = imgI[h-1][w * (n+1) -1] - imgI[h-1][w * n -1] for m in p[1:]: #計算第0列的能量 sat[m][0] = imgI[h * (m+1) - 1][w-1] - imgI[h * m - 1][w-1] for m in p[1:]: #計算其餘的能量 for n in q[1:]: sat[m][n] = imgI[h * (m+1) - 1][w * (n+1) -1] - imgI[h * (m+1) - 1][w * n -1] -imgI[h * m - 1][w * (n+1) -1] + imgI[h * m - 1][w * n -1] #print(sat) #計算各塊的能量密度 sat = sat / (w * h) #選出能量密度較高的塊 print('to draw:') threshold1 = 10 ##8鄰域搜尋演算法合併區域 def eightSearch(sated, m, n,mleft,ntop,mright,nbottom): #sat_search = [sat[m-1][n-1],sat[m-1][n],sat[m-1][n+1],sat[m][n-1],sat[m][n+1],sat[m+1][n-1],sat[m+1][n],sat[m+1][n+1]] sat_search = [(m-1,n-1),(m-1,n),(m-1,n+1),(m,n-1),(m,n+1),(m+1,n-1),(m+1,n),(m+1,n+1)] for sati in sat_search: s0 = sati[0] s1 = sati[1] if sated[s0][s1] != -1: left = s1 * w -1 top = s0 * h -1 right = s1 * w + w -1 bottom = s0 * h + h -1 sated[s0][s1] = -1 if sat[s0][s1] > 10: #記錄邊界 if left < mleft: mleft = left elif right > mright: mright = right if top < ntop: ntop = top elif bottom > nbottom: nbottom = bottom #迴圈 sated,mleft,ntop,mright,nbottom = eightSearch(sated,s0,s1,mleft,ntop,mright,nbottom) return sated,mleft,ntop,mright,nbottom ##儲存框選出的區域 #@param img 原圖 #@param left, right ,top,bottom 裁切區域的上下左右座標 #@param pad 是否新增邊(新增20%的黑邊) #@param name 儲存圖片的名字,預設為None,則不儲存 def saveRect(img, mleft, ntop, mright, nbottom, pad = True, name = None): subimg = img[ntop:nbottom, mleft:mright] if pad is False: if name is not None: cv2.imwrite(name,subimg) return subimg else: subimgshape = subimg.shape addpad =(2*int(0.1 * subimgshape[0]),2*int(0.1 * subimgshape[1])) frame = np.zeros((addpad[0] + subimgshape[0], addpad[1] + subimgshape[1], 3), np.uint8) frame[int(addpad[0]/2):(int(addpad[0]/2)+subimgshape[0]),int(addpad[1]/2):(int(addpad[1]/2)+subimgshape[1])] = subimg if name is not None: cv2.imwrite(name,frame) return frame #返回裁切結果 count = 0;#圖中數字計數 for m in p[1:-2]: #因為8鄰域,所以排除 for n in q[1:-2]: if sated[m][n] != -1 and sat[m][n]> 1: print('has number!') sated[m][n] = -1 sated,mleft,ntop,mright,nbottom = eightSearch(sated,m,n,n*w-1,m*h-1,n*w-1+w,m*h-1+h) #cv2.rectangle(img,(mleft,ntop),(mright,nbottom),(0,0,255),1) saimg = saveRect(img,mleft,ntop,mright,nbottom) cv2.imshow('subimg' + str(count), saimg) res = cv2.resize(saimg,(28, 28), interpolation = cv2.INTER_AREA ) cv2.imwrite('./img/num1202' + str(count) + '.jpg',res) count = count + 1 cv2.waitKey() cv2.destroyAllWindows()