机器学习实战:K-近邻(KNN)算法识别26个大写英文字母(A到Z)(含拍照检验步骤详解)

步骤一:收集数据集

数据集来自于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=90012005526=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()函数的解释如下图:
在这里插入图片描述
最后检验识别效果:

handwriting_A_TO_Z('test_b_recognise.txt')

得到运行结果:
在这里插入图片描述
识别正确!

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值