利用Python进行数字识别

思路

通过Python实现KNN算法。而KNN算法就是K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别。详情可在上一篇文章开头有介绍:
https://www.jianshu.com/p/bddf84a60efc
转载请注明出处:Michael孟良

准备

在Java项目里写了一个RGBUtils的class,将32x32像素的图片全部数字化输出:

package com.yml.common;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class RGBUtils {

    public static void main(String[]args){
        try {
            BufferedImage bi = ImageIO.read(new File("D:\\workspace\\Utils\\src\\com\\yml\\common\\9_1.png"));
            String picString = "";
            for (int i = 0; i < 32; i++) {
                for (int j = 0; j < 32; j++) {
                    picString += getRGB(bi, j, i);
                }
                picString += "\r\r\n";
            }
            System.out.println(picString);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static int getRGB(BufferedImage image, int x, int y) {
        int[] rgb = null;
        if (image != null && x < image.getWidth() && y < image.getHeight()) {
            rgb = new int[3];
            int pixel = image.getRGB(x, y);
            rgb[0] = (pixel & 0xff0000) >> 16;
            rgb[1] = (pixel & 0xff00) >> 8;
            rgb[2] = (pixel & 0xff);
        }
        if(null!=rgb&&255==rgb[0]&&255==rgb[1]&&255==rgb[2]){
            return 0;
        }else{
            return 1;
        }
    }
}

这是我在PS新建的32x32像素的数字9:

数字9

黑色是1白色是0,执行上述java类后得到
数字9

JAVA代码:https://github.com/MichaelYipInGitHub/PythonTest/blob/master/com/test/knn/JavaUtils/RGBUtils.java
要放到java项目里跑
如此这般我写了三个字一个5两个9,将他们变成TXT文件再TestData文件夹下

代码(Python)

# coding:utf-8

import os
import numpy as np

# 此方法将每个文件中32*32的矩阵数据,转换到1*1024一行中
from com.test.knn.KNNArcheyTest import classify


def img2vector(filename):
    # 创建一个1行1024列的矩阵
    returnVect = np.zeros((1, 1024))
    # 打开当前的文件
    fr = open(filename, "rb")
    # 每个文件中有32行,每行有32列数据,遍历32个行,将32个列数据放入1024的列中
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0, 32 * i + j] = int(lineStr[j])
    return returnVect


def IdentifImg():
    labels = []
    # 读取训练集 TrainData目录下所有的文件和文件夹
    trainingFileList = os.listdir('TrainData')
    m = len(trainingFileList)
    # zeros((m,1024)) 返回一个m行 ,1024列的矩阵,默认是浮点型的
    trainingMat = np.zeros((m, 1024))
    for i in range(m):
        # 获取文件名称  0_0.txt
        fileNameStr = trainingFileList[i]
        # 获取文件除了后缀的名称
        fileStr = fileNameStr.split('.')[0]
        # 获取文件"数字"的类别
        classNumStr = int(fileStr.split('_')[0])
        labels.append(classNumStr)
        # 构建训练集, img2vector  每个文件返回一行数据 1024列
        trainingMat[i, :] = img2vector('TrainData/%s' % fileNameStr)
    # 读取测试集数据
    testFileList = os.listdir('TestData')
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i] #0_0.txt
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('TestData/%s' % fileNameStr)
        classifierResult = classify(vectorUnderTest, trainingMat, labels, 5)
        print("识别出的数字是: %d, 真实数字是: %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr):
            errorCount += 1.0
    print("\n识别错误次数 %d" % errorCount)
    errorRate = errorCount / float(mTest)
    print("\n正确率: %f" % (1 - errorRate))


if __name__ == '__main__':
    IdentifImg()

思路

首先将32x32像素的图片转变成一行1024(=32x32)空间坐标,其实就相当于一个1024维的空间。TainData 里面有两千条数据就相当于有两千个点。
我们新建一个方法叫classify,就是把我们要测试的点放到训练数据空间里,看离他最近的k个点是什么值,这里我们K设置为5

# normData 测试数据集的某行,  dataSet 训练数据集 ,labels 训练数据集的类别,k k的值
def classify(normData, dataSet, labels, k):
    # 计算行数
    dataSetSize = dataSet.shape[0]
    #     print ('dataSetSize 长度 =%d'%dataSetSi  ;                  vzvz ze)
    # 当前点到所有点的坐标差值  ,np.tile(x,(y,1)) 复制x 共y行 1列
    diffMat = np.tile(normData, (dataSetSize, 1)) - dataSet
    # 对每个坐标差值平方
    sqDiffMat = diffMat ** 2
    # 对于二维数组 sqDiffMat.sum(axis=0)指 对向量每列求和,sqDiffMat.sum(axis=1)是对向量每行求和,返回一个长度为行数的数组
    # 例如:narr = array([[ 1.,  4.,  6.],
    #                   [ 2.,  5.,  3.]])
    #    narr.sum(axis=1) = array([ 11.,  10.])
    #    narr.sum(axis=0) = array([ 3.,  9.,  9.])
    sqDistances = sqDiffMat.sum(axis=1)
    # 欧式距离 最后开方
    distance = sqDistances ** 0.5
    # x.argsort() 将x中的元素从小到大排序,提取其对应的index 索引,返回数组
    # 例:   tsum = array([ 11.,  10.])    ----  tsum.argsort() = array([1, 0])
    sortedDistIndicies = distance.argsort()
    #     classCount保存的K是魅力类型   V:在K个近邻中某一个类型的次数
    classCount = {}
    for i in range(k):
        # 获取对应的下标的类别
        voteLabel = labels[sortedDistIndicies[i]]
        # 给相同的类别次数计数
        classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
    # sorted 排序 返回新的list
    #     sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    sortedClassCount = sorted(classCount.items(), key=lambda x: x[1], reverse=True)
    return sortedClassCount[0][0]

我之前写的3的数字也变成1024维空间的点,选择最近的五个点进行判断。

输出结果


原来图片


代码

https://github.com/MichaelYipInGitHub/PythonTest/blob/master/com/test/knn/IdentifImg.py

总结

1.Python没用封装KNN 算法, 因为太简单,可以直接手写。
2.从图片上看, 我用粗笔写的数字能识别到,细笔写的就识别不到,这可能与我的训练数据多为粗笔字体。
3.数字识别可以引申到动物识别,人物识别,不过他们用的像素不只是0和1,数据会更加庞大, 算法更加复杂。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容