新手上手Tensorflow之手寫數字識別應用(3)
阿新 • • 發佈:2018-11-17
本系列為應用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()