python_基于KNN算法的筆跡識(shí)別

需要用到:

  • Numpy庫
  • Pandas庫
  • 手寫識(shí)別數(shù)據(jù) 下載地址

數(shù)據(jù)說明:

數(shù)據(jù)共有785列圣蝎,第一列為label椒舵,剩下的784列數(shù)據(jù)存儲(chǔ)的是灰度圖像(0~255)的像素值 28*28=784

KNN(K近鄰算法):

從訓(xùn)練集中找到和新數(shù)據(jù)最接近的K條記錄,根據(jù)他們的主要分類來決定新數(shù)據(jù)的類型疫萤。
這里的主要分類芝囤,可以有不同的判別依據(jù),比如“最多”关贵,“最近鄰”遇骑,或者是“距離加權(quán)”。

整個(gè)程序的幾個(gè)部分:

1.數(shù)據(jù)的歸一化處理(normalization)
2.(重要)找出與test數(shù)據(jù)最接近的train數(shù)據(jù)的編號(hào)揖曾,根據(jù)編號(hào)查找到對(duì)應(yīng)的label落萎,將label賦給test數(shù)據(jù)的預(yù)測值
3.統(tǒng)計(jì)知道的test的label值與test的預(yù)測label值得正確率

Step 1

導(dǎo)入Numpy與Pandas庫

import numpy as np
import pandas as pd
Step 2

對(duì)數(shù)據(jù)進(jìn)行歸一化
對(duì)數(shù)據(jù)歸一化的方法很多,比如:
一炭剪、max-Min標(biāo)準(zhǔn)化
max - Min標(biāo)準(zhǔn)化方法是對(duì)原始數(shù)據(jù)進(jìn)行線性變換练链。設(shè)minA和maxA分別為屬性A的最小值和最大值,將A的一個(gè)原始值x通過max-Min標(biāo)準(zhǔn)化映射成在區(qū)間[0,1]中的值x'奴拦,其公式為:
新數(shù)據(jù)=(原數(shù)據(jù)-極小值)/(極大值-極小值)
二媒鼓、
新數(shù)據(jù)=原數(shù)據(jù)/(原數(shù)據(jù)的平方和開根號(hào))
三、
y = ( x - min )/( max - min ) 其中min為x的最小值错妖,max為x的最大值绿鸣,輸入向量為x,歸一化后的輸出向量為y 暂氯。上式將數(shù)據(jù)歸一化到 [ 0 , 1 ]區(qū)間潮模,當(dāng)激活函數(shù)采用S形函數(shù)時(shí)(值域?yàn)?0,1))時(shí)這條式子適用

在這里采用方法二

def normalize(x):
    norms = np.apply_along_axis(np.linalg.norm,1,x)
    return x / np.expand_dims(norms,-1)

調(diào)用np中的linalg.norm(x)和 apply_along_axis(func, axis, x)函數(shù)
linalg.norm(x)函數(shù)的作用是 return sum(abs(xi)**2)**0.5,
apply_along_axis(func, axis, x)函數(shù)的作用是將x按axis方向執(zhí)行func函數(shù),axis=0表示做列方向上的運(yùn)算株旷,axis=1表示做行方向上的運(yùn)算

step 3

找出與test數(shù)據(jù)最接近的train數(shù)據(jù)再登,這步是最關(guān)鍵的一步。
在這里晾剖,test數(shù)據(jù)與train數(shù)據(jù)就是空間的兩個(gè)向量锉矢,問題就變成了如何計(jì)算這兩個(gè)向量的相似程度。
我們可以把它們想象成空間中的兩條線段齿尽,都是從原點(diǎn)([0, 0, ...])出發(fā)沽损,指向不同的方向。兩條線段之間形成一個(gè)夾角循头,如果夾角為0度绵估,意味著方向相同炎疆、線段重合;如果夾角為90度国裳,意味著形成直角形入,方向完全不相似;如果夾角為180度缝左,意味著方向正好相反亿遂。因此,我們可以通過夾角的大小渺杉,來判斷向量的相似程度蛇数。夾角越小,就代表越相似是越。
假定a向量是[x1, y1]耳舅,b向量是[x2, y2],那么可以將余弦定理改寫成下面的形式:

余玄定理
def nearest_neighbor(norm_func,train_data,train_label,test_data):
    train_data = norm_func(train_data)
    test_data = norm_func(test_data)
    cos = np.dot(train_data,np.transpose(test_data))#np.transpose為求轉(zhuǎn)置倚评,dot為矩陣的乘積浦徊,結(jié)果為cos的一列值為test與train的相似度
    max_cos = np.argmax(cos,axis=0)#np.argmax為cos中一列上方的最大值
    test_pred = train_label[max_cos]#train_label為一列,max_cos為一個(gè)數(shù)組蔓纠,train_label[max_cos]會(huì)讀出train_label中max_cos數(shù)組編號(hào)的元素
    return test_pred#返回test的預(yù)測值
step 4

統(tǒng)計(jì)預(yù)測值的正確率

def validate(test_pred,test_label):
    c=len(test_pred)#在數(shù)組里面套數(shù)組的時(shí)候辑畦,len得到的是大數(shù)組里數(shù)組的個(gè)數(shù),在只有一層數(shù)組的時(shí)候腿倚,得到的是數(shù)組中元素的個(gè)數(shù)
    correct=(test_pred == test_label).sum()#統(tǒng)計(jì)兩個(gè)數(shù)組中有多少個(gè)元素相同
    return float(correct)/c#必須轉(zhuǎn)變成浮點(diǎn)數(shù)再做除法纯出,之前使用correct/c得到0

測試代碼:

if __name__ == '__main__':
    train_num = 200
    test_num = 300#測試數(shù)據(jù)起始是test_num-train_num
    x = pd.read_csv('train.csv')
    x_train = x.values[0:train_num,1:]#讀取pandas中讀取出來的數(shù)據(jù),需要用data.values[]
    x_train_label = x.values[0:train_num,0]#第一列是label,每幅圖的數(shù)據(jù)是一行
    x_test = x.values[train_num:test_num,1:]
    x_test_label = x.values[train_num:test_num,0]
    test_pred=nearest_neighbor(normalize,x_train,x_train_label,x_test)
    prec=validate(test_pred,x_test_label)
    print u"正確率為%.2f"%(prec)#浮點(diǎn)數(shù)是%f

完整代碼下載

注解:
上面部分主要是講解KNN算法敷燎,運(yùn)用到的是現(xiàn)成的28*28的數(shù)據(jù)暂筝,而在實(shí)際做筆跡分析的時(shí)候,首先需要將圖像轉(zhuǎn)化成矩陣數(shù)據(jù)硬贯。
現(xiàn)在介紹一下焕襟,圖像轉(zhuǎn)化成矩陣與矩陣轉(zhuǎn)化成圖像的方法

矩陣轉(zhuǎn)化成圖像

需要用到的庫是圖像處理庫Python Imaging Library (PIL)
在Windows下使用pip install PIL安裝失敗,采取了下載PIL.exe雙擊安裝的方法
下載地址:
PIL官方下載地址

import pandas as pd
import numpy as np
from PIL import Image

# load data
train = pd.read_csv('train.csv')

# now draw the numbers
for ind, row in train.iloc[0:3].iterrows():#iloc方法(介紹見后)來獲得前3行數(shù)據(jù)
    i = row[0]#[0]為標(biāo)簽項(xiàng)
    arr = np.array(row[1:], dtype=np.uint8)#1-784列組成一幅圖饭豹,鸵赖,uint8為8位無符號(hào)整數(shù)
   #arr = np.array(255 - row[1:], dtype=np.uint8)#如果需要顏色取反,用255減去當(dāng)前每個(gè)像素點(diǎn)的值
    arr.resize((28, 28))#把它變成28*28的矩陣
    #save to file
    im = Image.fromarray(arr)
    im.save("./train_pics/%s-%s.png" % (ind, i))#第一個(gè)%s(ind)表示它是第幾幅圖像拄衰,第二個(gè)%s表示這個(gè)圖像里面數(shù)字是幾 ,注意該語句不能產(chǎn)生文件夾它褪,需要現(xiàn)在指定目錄建一個(gè)文件夾

.iloc()方法

iloc[行位置,列位置]
df.iloc[1,1]#選取第二行,第二列的值翘悉,返回的為單個(gè)值
df.iloc[0,2],:]#選取第一行及第三行的數(shù)據(jù)
圖像轉(zhuǎn)化成矩陣

需要用到的庫是opencv(open source computer vision)茫打,下載安裝方式請(qǐng)參照python_OpenCV安裝
這里主要講它的幾個(gè)簡單功能
1.靜態(tài)圖像的輸入,輸出

cv2.imread('xxx.png')#輸入,#這里輸入image的維度image.shape = (w,h,3)老赤,w*h是圖片的長寬轮洋,3是BGR等三種顏色的channel值,每個(gè)值為0~255
cv2.imwrite('xxx.jpg', image)#輸出

2.將圖片轉(zhuǎn)化為灰度圖片

#灰度圖片的顏色channel只有一個(gè)抬旺,0~255表示灰度值
grayImage = cv2.imread('xxx.png',cv2.CV_LOAD_IMAGE_GRAYSCALE)

3.改變圖像的大小

print grayImage.shape#查看圖像的shape弊予,shape為(137,301),如果查看的是圖像的size嚷狞,則為42137(41237=137*301)
res=cv2.resize(grayImage,(28,28),interpolation=cv2.INTER_CUBIC)#將圖片grayImage以cv2.INTER_CUBIC方式變化為(28,28)大小的圖片

變換的方法:

  • CV_INTER_NN - 最近鄰插值,
  • CV_INTER_LINEAR - 雙線性插值 (缺省使用)
  • CV_INTER_AREA - 使用象素關(guān)系重采樣块促。當(dāng)圖像縮小時(shí)候,該方法可以避免波紋出現(xiàn)床未。當(dāng)圖像放大時(shí),類似于 CV_INTER_NN 方法..
  • CV_INTER_CUBIC -立方插值.

下面是有關(guān)輸入振坚,輸出薇搁,改變成灰度圖,改變圖像大小渡八,顯示的完整程序啃洋,注意圖像在窗口中的顯示

import cv2
image = cv2.imread('111.png')#讀
cv2.imwrite('111.jpg', image)#寫
grayImage = cv2.imread('111.png',cv2.CV_LOAD_IMAGE_GRAYSCALE)
print grayImage.shape
res=cv2.resize(grayImage,(28,28),interpolation=cv2.INTER_CUBIC)
#顯示圖像
cv2.imshow('test',grayImage)#顯示灰度圖
cv2.imshow('change',res)#顯示改變了大小的圖
#捕獲鍵盤輸入
k=cv2.waitKey(0)
if k==27:#27表示ESC鍵
    cv2.destroyWindow()

cv2.imshow()用于將圖片顯示在窗口中,后面必須跟個(gè)cv2.waitKey()函數(shù)屎鳍,才能讓顯示持續(xù)宏娄,不然顯示出來程序就中止了,窗口就會(huì)被關(guān)閉逮壁。cv2.waitKey()函數(shù)是捕獲鍵盤的輸入孵坚,cv2.destroyWindow()是釋放窗口。

在學(xué)習(xí)了如果讀取窥淆,輸出圖片后卖宠,我們就可以用寫好的KNN算法識(shí)別我們的筆跡了。

問題:

我使用了很多手寫的數(shù)據(jù)去驗(yàn)證識(shí)別是否準(zhǔn)確忧饭,發(fā)現(xiàn)準(zhǔn)確率還不夠高扛伍。主要存在的問題是
1.圖片大小問題,大小的調(diào)節(jié)不應(yīng)該把整張圖片變?yōu)?8*28的圖词裤,而應(yīng)該識(shí)別出寫有數(shù)字的中心圖片刺洒,把旁邊的白邊去掉
2.手寫的數(shù)字照片,不能保證寫字的地方為黑(像素值為255)
解決方式:需要使用一個(gè)濾波器吼砂,把因紙張逆航,拍攝問題出現(xiàn)的像素值降。再?zèng)]有使用濾波器的條件下帅刊,我把照片換成了在畫圖板上寫的數(shù)字纸泡。
3.寫字的粗細(xì)會(huì)影響判斷
解決辦法:這個(gè)可能是訓(xùn)練樣本不夠多,整體訓(xùn)練樣本的字跡偏粗,在輸入很細(xì)的筆跡時(shí)女揭,不能識(shí)別出來蚤假。還有就是應(yīng)該監(jiān)測輸入字體的粗細(xì),對(duì)輸入的很細(xì)的筆跡做膨脹處理吧兔,對(duì)很粗的筆跡做腐蝕處理

歡迎有經(jīng)驗(yàn)的朋友提出寶貴的意見磷仰,交流學(xué)習(xí)

微信二維碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市境蔼,隨后出現(xiàn)的幾起案子灶平,更是在濱河造成了極大的恐慌,老刑警劉巖箍土,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逢享,死亡現(xiàn)場離奇詭異,居然都是意外死亡吴藻,警方通過查閱死者的電腦和手機(jī)瞒爬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沟堡,“玉大人侧但,你說我怎么就攤上這事『铰蓿” “怎么了禀横?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長粥血。 經(jīng)常有香客問我柏锄,道長,這世上最難降的妖魔是什么立莉? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任绢彤,我火速辦了婚禮,結(jié)果婚禮上蜓耻,老公的妹妹穿的比我還像新娘茫舶。我一直安慰自己,他們只是感情好刹淌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布饶氏。 她就那樣靜靜地躺著,像睡著了一般有勾。 火紅的嫁衣襯著肌膚如雪疹启。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天蔼卡,我揣著相機(jī)與錄音喊崖,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛荤懂,可吹牛的內(nèi)容都是我干的茁裙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼节仿,長吁一口氣:“原來是場噩夢啊……” “哼晤锥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起廊宪,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤矾瘾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后箭启,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體壕翩,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年册烈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了戈泼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赏僧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扭倾,到底是詐尸還是另有隱情淀零,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布膛壹,位于F島的核電站驾中,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏模聋。R本人自食惡果不足惜肩民,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望链方。 院中可真熱鬧持痰,春花似錦、人聲如沸祟蚀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽前酿。三九已至患雏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間罢维,已是汗流浹背淹仑。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匀借。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓颜阐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親怀吻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瞬浓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容