手写数字识别

手写数字识别

测试环境:python3.8 .5
pyqt5 5.15.4
算法原理:传统机器学习算法距离分类

参考文献:
书名:图像识别与项目实践:VC++、MATLAB技术实现
作者:杨淑莹

以及:
画板工具参考博客

手写数字的特征提取

(1)搜索数据区,找出手写数字的上、下、左、右边界。
(2)将数字区域平均分为5×5的小区域。
(3)计算5×5的每一个小区域中黑像素所占比例。第一行的5个比例值保存到特征的前5个,第二行对应着特征的6~10个,以此类推。
(4)若特征大于0.1(指定值,可以根据需求改变),则将对应的5×5区域置黑。(在画笔工具绘制图像时,画笔粗细将影响图像特征提取结果,程序能够根据画笔粗细程度更改参数以达到较好的提取效果。
在这里插入图片描述
基于模板匹配方法的手写数字识别

模板匹配方法将待分类样品与标准模板进行比较,看跟哪个模板匹配程度更好些,从而确定待测试样品的分类,属于近邻法则。它将训练样品集中的每个样品都作为模板,用测试样品与每个模板作比较,看与哪个模板最相似(即为近邻),就按最近似的模板的类别作为自己的类别。手写数字分10个类别,每个数字提取特征,为每个数字建立训练样品集,任何一个待测试样品在分类时与样品集里的每一个模板都算一算相似度,最相似的那一个样品的类别,就作为待测试样品的类别。因此,原理上说近邻法是最简单的,但是近邻法有一个明显的缺点,那就是计算量大,存储量大,要存储的模板很多,每个测试样品要对每个模板计算一次相似度,因此在模板数量很大时,计算量也是很大的。
本文实例采用模板匹配法。选取的特征数n为100维,特征库中每一类的样品数为1000个左右。考虑到计算复杂度及运算时间,采用模板匹配法进行手写数字的识别完全能够满足现实需要。样品与样品之间的距离计算采用欧氏距离法。

程序主要功能:

1. 初始化:

在这里插入图片描述
初始化,即对样本进行训练,获取手写数字图像的特征矩阵

2. 手写数字:
在这里插入图片描述
在这里插入图片描述

暂时可以较为准确地识别所写数字。

3.画板工具参考

画板工具参考博客

主要代码:

图像预处理:

"""
 -*- coding = utf-8 -*-
-------------------------------------------------
 @time:2021/5/18 13:17
 Author:CGG
 We chat:CGG19991224
-------------------------------------------------
"""
import numpy as np


class imgtreat:
    def __init__(self, Image):
        self.Image = Image
        self.shape = Image.shape
        (m, n) = self.shape
        self.bottom = m
        self.right = n
        self.left = 0
        self.top = 0
        self.temprow=100#缓存矩阵行数
        self.tempcol=100#缓存矩阵列数
        self.featurerow=10#特征矩阵行数
        self.featurecol=10#特征矩阵列数
        self.temp = np.zeros((self.temprow,self.tempcol))  # 设置缓存矩阵
        self.Feature = np.zeros((self.featurerow, self.featurecol))  # 设置特征提取矩阵

    def adapt(self):
        (m, n) = self.shape
        sumx = self.Image.sum(axis=1)  # 将数组横向求和
        sumy = self.Image.sum(axis=0)  # 将数组纵向求和
        # 获取图像左边界self.top
        i = 1
        while sumx[i - 1] <= 0:
            i = i + 1
        self.top = i
        # 获取图像右边界self.bottom
        i = m-1
        while sumx[i] <= 0:
            i = i - 1
        self.bottom = i
        # 获取图像上边界self.left
        i = 0
        while sumy[i] <= 0:
            i = i + 1
        self.left = i
        # 获取图像上下左右边界self.right
        i = n-1
        while sumy[i] <= 0:
            i = i - 1
        self.right = i
        for i in range(99):
            for j in range(99):
                self.temp[i, j] = self.Image[round((self.bottom-self.top)*i/99+self.top),round((self.right-self.left)*j/99+self.left)]


    def getfeature(self,thickness):
        (h, w) = self.temp.shape
        h = round(h / self.featurerow)
        w = round(w / self.featurecol)
        for p in range(self.featurerow):
            for q in range(self.featurecol):
                sum = 0
                for i in range(h):
                    for j in range(w):
                        sum = sum + self.temp[p*h+i, q*w+j]
                if sum / (w * h) > 0.1*thickness/10:
                    self.Feature[p, q] = 1

    def pretreatment(self,thickness):
        self.adapt()
        self.getfeature(thickness)
        return self.Feature

识别函数代码:

"""
"""
 -*- coding = utf-8 -*-
-------------------------------------------------
 @time:2021/5/17 12:32
 Author:CGG
 We chat:CGG19991224
-------------------------------------------------
"""
import operator
from os import listdir

import matplotlib
import numpy as  np
from PyQt5.QtCore import Qt

# Image=np.array()
import pandas as pd
import matplotlib.image
from PyQt5.QtWidgets import QProgressDialog, QMessageBox

import pretreat


# 识别图像类
class Recognize:
    def __init__(self):
        self.k = 100  # 分类过程中取出的最相近的个数
        self.featurerows=10
        self.featurecols=10

    # 训练函数
    def train(self, trainpath):
        self.trainpath = trainpath
        self.trainlist = listdir(self.trainpath)
        self.numlist = len(self.trainlist)  # 训练样本的数量
        print("训练集数量:", self.numlist)
        self.pd=QProgressDialog()
        self.pd.setWindowTitle("初始化进度")
        self.pd.setMinimumDuration(5)
        self.pd.setFixedSize(300,70)
        self.pd.setWindowModality(Qt.WindowModal)
        self.pd.setRange(0, self.numlist)
        FeatureMat = np.zeros((self.numlist, self.featurerows*self.featurecols))  # 设置特征矩阵来存储提取的特征矩阵
        labels = np.zeros((self.numlist, 1))  # 设置标签矩阵存储样本对应的数字
        for i in range(self.numlist):
            filename = self.trainlist[i]  # 获取文件名
            fileStr = filename.split('.')[0]  # 去掉文件后缀
            labels[i] = int(fileStr.split('_')[0])  # 取文件名第一位文件的标签
            trainmat = matplotlib.image.imread(self.trainpath + '/' + filename)
            trainmat = np.around(trainmat / 255)
            temp = pretreat.imgtreat(trainmat)
            FeatureMat[i, :] = temp.pretreatment(10).reshape((1, self.featurerows*self.featurecols))
            self.pd.setValue(i)
            if self.pd.wasCanceled():#判断我们是否按下取消按钮
                break
            # print("\r初始化进度:%.2f %% " % ((i + 1) * 100 / self.numlist), end="")
        df = pd.DataFrame(FeatureMat)
        lf = pd.DataFrame(labels)
        df.to_csv("test/FeatureMat.csv", index=False)  # 保存特征矩阵
        lf.to_csv("test/labels.csv", index=False)  # 保存标签

    # 识别函数
    def classify(self, testfile,thickness):
        mat = matplotlib.image.imread(testfile)  # 读取所写图像
        mat = 1 - (mat[:, :, 0]+mat[:, :, 1]+mat[:, :, 2])/3  # 将图像反转
        image = pretreat.imgtreat(mat)  # 实例化图像处理类
        self.testfeature = image.pretreatment(thickness)  # 图像预处理,提取进行识别的图像的特征矩阵
        c = pd.DataFrame(self.testfeature)
        c.to_csv("test/testpicture_feature.csv", index=False, header=False)  # 保存特征矩阵
        self.trainfeaturemat = pd.read_csv("test/FeatureMat.csv", header=1)  # 读取训练的特征矩阵
        labels = pd.read_csv("test/labels.csv")
        self.trainrows = self.trainfeaturemat.shape[0]  # 获取训练结果行数
        [m, n] = self.testfeature.shape
        self.testfeature = self.testfeature.reshape((1, m * n))
        distances = self.dis(self.testfeature, self.trainfeaturemat)
        q = distances.argsort()  # 按照距离从低到高排位,返回的是索引
        classCount = {}
        # 依次取出最近的样本数据
        for i in range(self.k):  # 根据我们的k来统计出现频率,样本类别
            votelabel = labels.loc[q[i]][0]  # q[i]是索引值,通过labels来获取对应标签
            classCount[votelabel] = classCount.get(votelabel, 0) + 1  # 统计每个标签的次数
        # 对类别出现的频率次数排序,从高到低
        sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
        # 返回频率次数出现最高的类别
        return sortedClassCount[0][0]

    def dis(self, testdata, traindata):
        difference = np.tile(testdata, (self.trainrows, 1)) - traindata  # 求差
        distances = np.sqrt(np.sum(np.square(difference),axis=1))  # 求横向欧式距离
        return distances

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.癮.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值