步驟一:收集資料集
資料集來自于Character Recognition in Natural Images網站。
具體的檔案連結為:link 中的EnglishHnd.tgz檔案。
在該檔案夾中,Img檔案内含有Sample001—Sample062等62個檔案,每個檔案中含有55張900*1200像素的圖檔。其中Sample001—Sample010檔案中是0-9數字的圖像;其中Sample011—Sample036檔案中是26個大寫英文字母的圖像;Sample037—Sample062檔案中是26個小寫英文字母的圖像。
本文中,隻使用Sample011—Sample036檔案,處理大寫英文字母圖像。
步驟二:批量處理圖像
1.由于每一幅圖像像素點都為900 * 1200,每一個檔案夾中含有55幅圖檔,26個英文字母有26個檔案夾,則最終訓練的0,1資料量将要達到
z = 900 ∗ 1200 ∗ 55 ∗ 26 = 1544400000 z = 900*1200*55*26=1544400000\, z=900∗1200∗55∗26=1544400000
處理這麼大的資料量,在pycharm環境中,用python處理這些資料時,如果不用GPU加速,可能會提示memory error錯誤。
是以,需要把檔案夾中的圖檔像素按比例處理到大小為75*100。
2.用Photoshop批量處理圖像(CS5.1版本)的具體步驟如下:
① 在ps中打開Sample011檔案夾中的圖像img011-001.png。
② 按下‘Alt+F9’,出現動作欄:
③ 建立動作,并點選記錄(動作名稱自取)。
④ 點選:圖像——圖像大小——修改像素點大小,并限制比例——确定
⑤ 點選:檔案——儲存——檔案——關閉
⑥點選下圖所示按鈕停止動作:
⑦動作錄入結束。之後可以點選檔案——自動——批處理來處理檔案夾中的所有圖像,但是我一打開PS批處理就會自動彈出,不知道什麼原因。是以,我使用另外一種方法,打開到Sample011檔案夾,把所有的圖像都一起拖到PS面闆中:
⑧拖到PS面闆後,對每一副圖像都點選如下按鈕。記得光标要讓移動到自己命名的動作上。就可以對每一副圖像進行處理。(笨辦法,但是很有效,每2分鐘大約能處理55張圖檔)
這樣,就可以依次處理Sample011—Sample036等26個檔案中的圖像。處理後,這些檔案夾中圖檔的像素大小都變為了75*100。
步驟三:批量處理圖像,轉化為二進制‘txt’檔案
用MATLAB處理,把這26個檔案夾中的每一副圖像處理為一個1*7500的數組并儲存在另一個檔案夾中,轉換為相應的txt檔案。
此時,我的Sample檔案路徑在:
E:\Machinelearning\MachineLearninginAction\DEMO\machinelearninginaction\Ch02\EnglishHnd\Img
轉換後的TXT檔案名稱為’0_0’到’0_54’,再到’25_54’。’ _ ‘之前的數為26個英文字母的序列,如0對應A,1對應B,以此類推;’_'之後的數為55張照片轉換成的對應的檔案。
批量轉換為相應txt檔案的MATLAB代碼為:
%識别26個大寫字母
for i=11:36 %i為檔案夾Sample011—Sample036,如果需要識别小寫字母的,則改成i=37:62
Jia_numble=int2str(i); %i轉化為字元串形式
Wenjianjia_name=strcat('Sample0',strcat(Jia_numble,'\')); %把兩字元串結合在一起
file_pathshort = 'E:\Machine learning\MachineLearninginAction\DEMO\machinelearninginaction\Ch02\EnglishHnd\Img\'; %存儲圖像的檔案夾路徑
file_path=strcat(file_pathshort,Wenjianjia_name)
img_path_list = dir(strcat(file_path,'*.png')); %擷取該檔案夾中所有'png'格式的圖像名稱
img_num = length(img_path_list); %擷取圖像總數量
Matrix=zeros(55,7500); %55幅圖檔,像素點為75*100
if img_num > 0 %有滿足條件的圖像
for j = 1:img_num %逐一讀取圖像
image_name = img_path_list(j).name; % 圖像名,如‘img011-041.png’
I = imread(strcat(file_path,image_name));
fprintf('%d %d %s\n',j,img_num,strcat(file_path,image_name)) % 顯示正在處理的圖像名
i1=rgb2gray(I); %i1灰階圖像
i2=im2bw(i1); % i2是二值圖像,不需要求門檻值
%圖像處理過程
N=size(i2) %求圖像維數
%轉換為一維數組
re=reshape(i2,1,prod(N)); % prod是累乘,prod(N)=75*100=7500
re=~re; %數組取反
%放在矩陣裡
Matrix(j,:)=re; %Matrix每一行中為檔案中圖像的
end
end
str1=int2str(i-11) %str1是從0開始,一直到26的整數,為txt檔案夾的名字
str2=strcat(str1,'_')
for N = 1:img_num
chr = int2str(N-1) %N轉化為字元串形式
file_retrit='E:\Machine learning\MachineLearninginAction\DEMO\machinelearninginaction\Ch02\EnglishHnd\txt\';
str=strcat(file_retrit,strcat(strcat(str2,chr),'.txt'))
fid=fopen(str,'wt'); %寫的方式打開檔案(若不存在,建立檔案);
fprintf(fid,'%d',Matrix(N,:)); % d 表示以整數形式寫入資料,這正是我想要的;
fclose(fid); %關閉檔案
end
end
代碼運作結束後,可以在txt檔案夾中找到各種txt檔案,如下圖:
為了便于了解,把該檔案夾改名為:training_A_TO_Z(訓練集資料檔案)。
步驟四:用手機拍照并把二值化後的像素矩陣存為txt檔案
①在紙上寫一個大寫的B,并用手機拍照:
②用手機自行剪輯的小一點:
③然後,用 link 中用PS處理數字2的方法,處理該圖檔,改成75*100像素大小。
再用MATLAB處理該圖像,得到一組測試集文本檔案:test_b_recognise.txt
MATLAB代碼如下:
%單個圖檔轉化為txt檔案
i=imread('E:\Machine learning\MachineLearninginAction\DEMO\machinelearninginaction\Ch02\B.jpg'); %圖檔的存儲路徑
i1=rgb2gray(i); %i1灰階圖像
i2=im2bw(i1); %i2是二值圖像,不需要求門檻值
for j=1:75
for k=1:100
if i2(j,k)==0
i2(j,k)=1;
else
i2(j,k)=0;
end
end
end
fid=fopen('E:\Machine learning\MachineLearninginAction\DEMO\machinelearninginaction\Ch02\test_b_recognise.txt','wt'); %寫的方式打開檔案(若不存在,建立檔案);
fprintf(fid,'%d',i2); %d 表示以整數形式寫入資料,這正是我想要的;
fclose(fid); %關閉檔案
步驟五:用KNN算法識别大寫字母
所用到的Python代碼及其解釋如下:
from numpy import *
import operator
from os import listdir
def classify0(inX, dataSet, labels, k): #對于該函數的解釋,見後面圖中
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1) #every hang add together
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort()
classCount={}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
def img_myself_A_TO_Z(filename): #該函數是針對文本中為1*7500的數組進行處理,傳回一個1*7500的數組
returnVect=zeros((1,7500))
fr=open(filename)
lineStr=fr.readline() #讀取一行,即1*7500個字元
for i in range(7500):
returnVect[0,i]=int(lineStr[i])
return returnVect
def handwriting_A_TO_Z(filename): #filename為待測試的txt檔案,本例中為'test_b_recognise.txt'檔案
hwLabels = []
trainingFileList = listdir('training_A_TO_Z') #儲存訓練集'training_A_TO_Z'檔案夾中所有的檔案名到清單trainingFileList中
m = len(trainingFileList)
trainingMat = zeros((m, 7500)) #每行儲存一個圖像
for i in range(m):
fileNameStr = trainingFileList[i] #第i個檔案的檔案名儲存在fileNameStr中,如‘0_0.txt’
fileStr = fileNameStr.split('.')[0] #把檔案名用‘.’分開成兩部分,取第一部分,如把‘0_0.txt’分開成‘0_0’與‘txt’兩部分,0代表取前一部分
classNumStr = int(fileStr.split('_')[0]) #同理,取‘0_0’中前一部分0,并轉換為int類型
hwLabels.append(classNumStr) #訓練集的标簽矩陣
trainingMat[i, :] = img2vector('training_A_TO_Z/%s' % fileNameStr) #打開training_A_TO_Z檔案夾下的檔案,讀取并轉化為1*7500的矩陣後,添加到trainingMat的對應行中,組成訓練集的矩陣
test_myself=img_myself(filename) #讀取filename檔案并轉化為1*7500的矩陣,組成測試集
test_myself_label=classify0(test_myself,trainingMat,hwLabels,5) #進行訓練并測試,把結果放到test_myself_label中
print("The test_myself_label is ",test_myself_label)
List1=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] #把結果轉化為對應的字母
print("The test_myself_label is ",List1[test_myself_label])
classify0()函數的解釋如下圖:
最後檢驗識别效果:
得到運作結果:
識别正确!