1. 程式人生 > >【好玩的計算機視覺】KNN演算法手寫數字識別

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

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

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

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


def initKnn():
    knn = cv2.ml.KNearest_create()
    img = cv2.imread('digits.png')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
    train = np.array(cells).reshape(-1,400).astype(np.float32)
    trainLabel = np.repeat(np.arange(10),500)
    return knn, train, trainLabel
這是總共5000個數據,0-9各500個,我們讀入圖片後整理資料,這樣得到的train和trainLabel依次對應,影象資料和標籤。
def updateKnn(knn, train, trainLabel, newData=None, newDataLabel=None):
    if newData != None and newDataLabel != None:
        print(train.shape, newData.shape)
        newData = newData.reshape(-1,400).astype(np.float32)
        train = np.vstack((train,newData))
        trainLabel = np.hstack((trainLabel,newDataLabel))
    knn.train(train,cv2.ml.ROW_SAMPLE,trainLabel)
    return knn, train, trainLabel
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)
    im, contours, hierarchy = cv2.findContours(ddst,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for c in contours:
        x, y, w, h = cv2.boundingRect(c)
        if w > 10 and h > 20:
            rois.append((x,y,w,h))
    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)
        digits.append(cv2.resize(th,(20,20)))
        cv2.rectangle(frame, (x,y), (x+w,y+h), (153,153,0), 2)
        cv2.putText(frame, str(digit), (x,y), cv2.FONT_HERSHEY_SIMPLEX, 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數字更新訓練後得到的結果:





相關推薦

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

OCR應用非常廣泛,而且有許多方法,今天用KNN演算法實現簡單的0-9手寫數字識別。本程式使用OpenCV 3.0和Python 3。 KNN演算法是K近鄰分類演算法,屬於機器學習中的監督學習,需要一定量的帶標籤的輸入樣本資料進行“訓練”,然後就可以識別。我給“訓練”打引

機器學習實戰knn演算法

首先初始化資料 def createDataSet(): group = np.array([[1.0, 1.1], [1.0, 1.0], [0.0,0.0], [0.0,0.1]]) labels = ['A', 'A', 'B', 'B']

機器學習實戰——KNN演算法數字識別

資料來源 我們的文字是形如這樣的,每個數字都有很多txt檔案,TXT裡面是01數字,表示手寫數字的灰度圖。 現在我們要用knn演算法實現數字識別。 資料處理 每個txt檔案都是32*32的0,1矩陣,如果要使用knn,那麼還得考慮行列關係,如果能把它拉開,只有一行,就可以不必考慮數字

機器學習 使用python+OpenCV實現knn演算法數字識別

基本上照搬了http://lib.csdn.net/article/opencv/30167的程式碼,只是改了一點bug和增加了一點功能輸入就是直接在一個512*512大小的白色畫布上畫黑線,然後轉化為01矩陣,用knn演算法找訓練資料中最相近的k個,現在應該是可以對所有字元

Python實現knn演算法數字識別

KNN實現手寫數字識別 1 - 匯入模組 import numpy as np import matplotlib.pyplot as plt from PIL import Image %matplotlib inline 2 - 匯入資

機器學習演算法實現kNN演算法 識別——基於Python和NumPy函式庫

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

基於KNN分類演算法數字識別的實現(二)——構建KD樹

上一篇已經簡單粗暴的建立了一個KNN模型對手寫圖片進行了識別,所以本篇文章採用構造KD樹的方法實現手寫數字的識別。 (一)構造KD樹 構造KD樹的基本原理網上都有介紹,所以廢話不多說,直接上程式碼。 #Knn KD_Tree演算法 import math from

學習KNN(二)KNN演算法數字識別的OpenCV實現

在OpenCV的安裝檔案路徑/opencv/sources/samples/data/digits.png下,有這樣一張圖: 圖片大小為1000*2000,有0-9的10個數字,每5行為一個數字,總共50行,共有5000個手寫數字,每個數字塊大小為20

KNN數字識別

用 KNN 做手寫數字識別 目錄 用 KNN 做手寫數字識別 1. KNN的原理 2. KNN實現手寫數字識別過程 作為一個小白,寫此文章主要是為了自己記錄,方便回過頭來查詢! 本文主要參考ApacheCN(專注於優秀專案維護的開源組織)中MachineL

KNN / SVM 數字識別-PCA降維

一.問題分析採用機器學習演算法對usps和mnist兩個資料集完成手寫數字識別任務。1.1.資料集介紹MNIST MNIST 資料集來自美國國家標準與技術研究所, National Institute of Standards and Technology (NIST)。訓練

kNN數字識別

answer style dataset 解析 所表 讀取 tile span k-近鄰 import numpy as np # listdir()列出給定目錄的文件名 from os import listdir import operator #

人工智慧利用C語言實現KNN演算法進行數字識別

KNN演算法稱為鄰近演算法,或者說K最近鄰(kNN,k-NearestNeighbor)分類演算法。所謂K最近鄰,就是k個最近的鄰居的意思,說的是每個樣本都可以用它最接近的k個鄰居來代表。kNN演算法的核心思想是如果一個樣本在特徵空間中的k個最相鄰的樣本中的大多數屬於某一個類

機器學習數字識別算法

alt gdi 數字識別 -1 轉換 error: erro files turn 1.數據準備 樣本數據獲取忽略,實際上就是將32*32的圖片上數字格式化成一個向量,如下: 本demo所有樣本數據都是基於這種格式的 訓練數據:將圖片數據轉成1*1024的數組,作為一

機器學習--opencv3.4.1版本基於Hog特徵描述子Svm對經典數字識別

 方向梯度直方圖(Histogram of Oriented Gradient, HOG)特徵是一種在計算機視覺和影象處理中用來進行物體檢測的特徵描述子。HOG特徵通過計算和統計影象區域性區域的梯度方向直方圖來構成特徵。 #include <iostream> #inc

AI實戰訓練第一個AI模型:MNIST數字識別模型

在上篇文章中,我們已經把AI的基礎環境搭建好了(見文章:Ubuntu + conda + tensorflow + GPU + pycharm搭建AI基礎環境),接下來將基於tensorflow訓練第一個AI模型:MNIST手寫數字識別模型。 MNIST是一個經典的手寫數字資料集,來自美國國家

Python例項第20講數字識別問題的K-Means聚類

機器學習訓練營——機器學習愛好者的自由交流空間(qq 群號:696721295) 在這個例子裡,我們在手寫數字識別資料集上,比較 K-means 聚類演算法對於不同的初始化策略對執行時間和結果質量的影響。我們也利用不同的聚類質量測度判別聚類標籤對於參考標籤的擬合優度。這裡使

機器學習--k-近鄰演算法kNN)實現數字識別

這裡的手寫數字以0,1的形式儲存在文字檔案中,大小是32x32.目錄trainingDigits有1934個樣本。0-9每個數字大約有200個樣本,命名規則如下: 下劃線前的數字代表是樣本0-9的

4caffe的python介面學習:mnist例項---數字識別

一、資料準備 官網提供的mnist資料並不是圖片,但我們以後做的實際專案可能是圖片。因此有些人並不知道該怎麼辦。在此我將mnist資料進行了轉化,變成了一張張的圖片,我們練習就從圖片開始。下面是轉化的程式碼。 import numpy as np import struc

機器學習 sklearn數字識別 SVM

執行結果: "D:\Program Files\Python27\python.exe" D:/PycharmProjects/sklearn/SVM.py (1797L, 64L) [[ 0. 0. 5. ..., 0. 0. 0.]