步骤一:收集数据集
数据集来自于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:62Jia_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*100if 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=7500re=~re; %数组取反%放在矩阵里Matrix(j,:)=re; %Matrix每一行中为文件中图像的endendstr1=int2str(i-11) %str1是从0开始,一直到26的整数,为txt文件夹的名字str2=strcat(str1,'_')for N = 1:img_numchr = 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); %关闭文件endend
代码运行结束后,可以在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:75for k=1:100if i2(j,k)==0i2(j,k)=1;elsei2(j,k)=0;endend
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 listdirdef classify0(inX, dataSet, labels, k): #对于该函数的解释,见后面图中dataSetSize = dataSet.shape[0]diffMat = tile(inX, (dataSetSize,1)) - dataSetsqDiffMat = diffMat**2sqDistances = sqDiffMat.sum(axis=1) #every hang add togetherdistances = sqDistances**0.5sortedDistIndicies = distances.argsort()classCount={} for i in range(k):voteIlabel = labels[sortedDistIndicies[i]]classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1sortedClassCount = 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 returnVectdef 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()函数的解释如下图:
最后检验识别效果:
handwriting_A_TO_Z('test_b_recognise.txt')
得到运行结果:
识别正确!