好玩的計算機視覺 KNN演算法手寫數字識別

2021-07-13 06:54:34 字數 4434 閱讀 1927

ocr應用非常廣泛,而且有許多方法,今天用knn演算法實現簡單的0-9手寫數字識別。本程式使用opencv 3.0和python 3。

knn演算法是k近鄰分類演算法,屬於機器學習中的監督學習,需要一定量的帶標籤的輸入樣本資料進行「訓練」,然後就可以識別。我給「訓練」打引號是因為其實knn沒有明顯的前期訓練過程,它是要給乙個樣本x分類,就從資料集中在x附近找離它最近的k各資料點,這k個資料點中包含的y類別最多,那麼就把x的標籤標記為y,這就完成了分類識別的過程。

首先,利用opencv自帶的手寫數字樣本集digits.png來進行初始訓練:

updateknn是增加自己的訓練資料後更新knn的操作。

def findroi(frame, thresvalue):

rois =

gray = cv2.cvtcolor(frame, cv2.color_bgr2gray)

gray2 = cv2.dilate(gray,none,iterations=2)

gray2 = cv2.erode(gray2,none,iterations=2)

edges = cv2.absdiff(gray,gray2)

x = cv2.sobel(edges,cv2.cv_16s,1,0)

y = cv2.sobel(edges,cv2.cv_16s,0,1)

absx = cv2.convertscaleabs(x)

absy = cv2.convertscaleabs(y)

dst = cv2.addweighted(absx,0.5,absy,0.5,0)

ret, ddst = cv2.threshold(dst,thresvalue,255,cv2.thresh_binary)

for c in contours:

x, y, w, h = cv2.boundingrect(c)

if w > 10 and h > 20:

return rois, edges

findroi函式是找到每個數字的位置,用包裹其最小矩形的左上頂點的座標和該矩形長寬表示(x, y, w, h)。這裡還用到了sobel運算元。edges是原始影象形態變換之後的灰度圖,可以排除一些背景的影響,比如本子邊緣、紙面的格仔、手、筆以及影子等等,用edges來獲取數字影象效果比sobel獲取的邊界效果要好。

def finddigit(knn, roi, thresvalue):

ret, th = cv2.threshold(roi, thresvalue, 255, cv2.thresh_binary)

th = cv2.resize(th,(20,20))

out = th.reshape(-1,400).astype(np.float32)

ret, result, neighbours, dist = knn.findnearest(out, k=5)

return int(result[0][0]), th

finddigit函式是用knn來分類,並將結果返回。th是用來手動輸入訓練資料時顯示的。20x20pixel的尺寸是opencv自帶digits.png中影象尺寸,因為我是在其基礎上更新資料,所以沿用這個尺寸。

def concatenate(images):

n = len(images)

output = np.zeros(20*20*n).reshape(-1,20)

for i in range(n):

output[20*i:20*(i+1),:] = images[i]

return output

concatenate函式是拼接數字影象並顯示的,用來輸入訓練資料。

while true:

ret, frame = cap.read()

frame = frame[:,:426]

rois, edges = findroi(frame, 50)

digits =

for r in rois:

x, y, w, h = r

digit, th = finddigit(knn, edges[y:y+h,x:x+w], 50)

cv2.rectangle(frame, (x,y), (x+w,y+h), (153,153,0), 2)

cv2.puttext(frame, str(digit), (x,y), cv2.font_hershey_******x, 1, (127,0,255), 2)

newedges = cv2.cvtcolor(edges, cv2.color_gray2bgr)

newframe = np.hstack((frame,newedges))

cv2.imshow('frame', newframe)

videoframe.write(newframe)

key = cv2.waitkey(1) & 0xff

if key == ord(' '):

break

elif key == ord('x'):

nd = len(digits)

output = concatenate(digits)

showdigits = cv2.resize(output,(60,60*nd))

cv2.imshow('digits', showdigits)

cv2.imwrite(str(count)+'.png', showdigits)

count += 1

if cv2.waitkey(0) & 0xff == ord('e'):

pass

print('input the digits(separate by space):')

numbers = input().split(' ')

nn = len(numbers)

if nd != nn:

print('update knn fail!')

continue

try:

for i in range(nn):

numbers[i] = int(numbers[i])

except:

continue

knn, train, trainlabel = updateknn(knn, train, trainlabel, output, numbers)

print('update knn, done!')

這是主函式迴圈部分,按「x」鍵會暫停螢幕並顯示獲取的數字影象,按「e」鍵會提示輸入看到的數字,在終端輸入數字用空格隔開,按回車如果顯示「update knn, done!」則完成一次更新。下面是我用20多組0-9數字更新訓練後得到的結果:

完整**:

計算機視覺演算法

講了乙個最小二乘法問題 存在四個不在一條直線上點,擬合一條直線,使這條直線能夠 誤差最小的穿過這四個點 雖然還不知道具體怎麼解。引申到矩陣的最小二乘法 有三個矩陣a,b,c,a為4 2,c為4 1,a b c.求b矩陣 求b,a矩陣是乙個非奇異矩陣,不可逆,所以讓a轉置左乘a構成滿秩矩陣c,可得b等...

(計算機視覺)計算機視覺基礎

opencv cximage cimg freeimage opencv中vc庫的版本與visual studio版本的對應關係 vc8 2005 vc9 2008 vc10 2010 vc11 2012 vc12 2013 vc14 2015 vc15 2017 visual studio中的輔助...

計算機視覺

主講老師 曹洋 課程 視覺 基礎 底 層處理 影象處理 特徵提 取 中 層處理 影象分割 相機標 定 深度 估計 運 動估計 高層處 理 3d 重建 目 標識別 視 覺基 礎 底層 處理 圖 像處理 特徵提取 中層 處理 圖 像分割 相機標定 深度估 計 運動 估計 高層處理 3d重 建 目標 識別...