# 多媒体技术 **Repository Path**: che-mingliang/multimedia-technology ## Basic Information - **Project Name**: 多媒体技术 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-05-13 - **Last Updated**: 2025-04-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 手写字符识别 ### 目录 - [手写字符识别](#手写字符识别) - [目录](#目录) - [介绍](#介绍) - [模型](#模型) - [支持向量机(SVM)](#支持向量机svm) - [训练流程](#训练流程) - [预测流程](#预测流程) - [随机森林(RF)](#随机森林rf) - [优点](#优点) - [训练流程](#训练流程-1) - [预测流程](#预测流程-1) - [卷积神经网络(CNN)](#卷积神经网络cnn) - [训练流程](#训练流程-2) - [预测流程](#预测流程-2) - [数据集(EMNIST)](#数据集emnist) - [前端(PyQt5)](#前端pyqt5) - [优化](#优化) - [字符分割](#字符分割) - [手绘字符](#手绘字符) - [错误反馈](#错误反馈) - [运行](#运行) - [代码](#代码) - [代码结构](#代码结构) - [依赖](#依赖) - [运行](#运行-1) - [打包](#打包) - [识别](#识别) - [图片](#图片) - [结果](#结果) - [测试](#测试) - [快捷键](#快捷键) - [贡献](#贡献) ### 介绍 手写字符识别是指给定一系列的手写字符图片以及对应的字符标签,构建模型进行学习,目标是对于一张新的手写字符图片能够自动识别出对应的字符 本项目作为多媒体期末大作业,利用传统机器学习算法(支持向量机、随机森林)和卷积神经网络在数据集`EMNIST`上进行学习,利用学习到的模型进行离线识别,并利用`PyQt5`开发桌面识别程序 为优化桌面程序使用体验,程序内实现了: - 手写板,可以实时进行字符绘制 - 快捷键,方便使用键盘完成识别 - 字符分割算法,支持单张图片多字符识别 - 反馈系统,持久化学习模型 ### 模型 本项目使用机器学习算法训练模型,机器学习算法主要包括: - 传统机器学习 - 支持向量机 - 随机森林 - 卷积神经网络 #### 支持向量机([SVM](https://baike.baidu.com/item/%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA/9683835?fr=aladdin)) 标准形式的`SVM`是一类按监督学习方式对数据进行二元分类的广义线性分类器,其决策边界是对学习样本求解的最大边距超平面,但本项目目标是多分类问题,因此需要用到多`分类SVM`。利用标准`SVM`的计算流程有序地构建多个决策边界以实现样本的多分类,对m个分类建立m个决策边界,每个决策边界判定一个分类对其余所有分类的归属 本项目我们利用`sklearn.svm`包下的`SVC`分类器实现`多分类SVM` ##### 训练流程 - 将用于训练的图像分别展开为一维向量 - 将训练标签和训练数据一一匹配 - 利用`SVC`去训练数据 - 保存模型 ##### 预测流程 - 加载模型 - 将待识别图像展开为一维向量 - 利用模型进行预测标签 #### 随机森林([RF](https://baike.baidu.com/item/%E9%9A%8F%E6%9C%BA%E6%A3%AE%E6%9E%97/1974765?fr=aladdin)) `RF`是一个含有多个[决策树](https://baike.baidu.com/item/%E5%86%B3%E7%AD%96%E6%A0%91/10377049?fr=aladdin)的分类器,并且其输出的类别是由个别树输出的类别的众数而定 本项目我们利用`sklearn.ensemble`包下的`RandomForestClassifier`分类器实现`RF` ##### 优点 - 对于多分类问题,可以产生高准确率的分类器 - 可以处理大量地输入变量 - 学习过程快速 ##### 训练流程 - 将用于训练的图像分别展开为一维向量 - 将训练标签和训练数据一一匹配 - 利用`RandomForestClassifier`去训练数据 - 保存模型 ##### 预测流程 - 加载模型 - 将待识别图像展开为一维向量 - 利用模型进行预测标签 #### 卷积神经网络([CNN](https://baike.baidu.com/item/%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/17541100?fr=aladdin)) `CNN`是一类包含卷积计算且具有深度结构的前馈神经网络,是深度学习的代表算法之一。卷积神经网络具有表征学习能力,能够按其阶层结构对输入信息进行平移不变分类。主要网络结构如下: - 输入层 - 隐含层 - 卷积层 - 池化层 - 全连接层 - 输出层 本项目所用的网络结构如下图所示: ![](src/net.png) ##### 训练流程 - 利用`torchvision.datasets.EMNIST`加载用于训练的数据 - 利用`torch.utils.data.dataloader`包中的`DataLoader`将数据集划分成特定大小的`batch` - 创建模型,选择合适的优化器、损失函数 - 训练,利用损失反馈优化参数,循环若干次,直至模型损失平稳 - 保存模型参数 ##### 预测流程 - 加载模型参数 - 将待识别图片转为`tensor`对象 - 利用模型进行预测标签 ### 数据集([EMNIST](https://www.nist.gov/itl/products-and-services/emnist-dataset)) 普遍的手写数字识别是使用`MNIST`数据集进行训练,`MNIST`只包含数字`0-9`。但本项目需要在更大规模的字符集上实现手写字符识别,因此选用`EMNIST`数据集来代替`MNIST`数据集进行训练模型。 EMNIST即Extended MNIST,一个更具挑战的数据集。在数据集的处理方式上跟`MNIST`保持一致,但是有着特殊的分类方式,这里介绍我们需要使用的三种分类: - Balanced:共$131600$张,分为$47$类;每一类训练集$2400$张,测试集$400$张 - 包括数字`0-9`,字母`a-zA-Z`,但合并了某些大小写一样的字母 - Letters:共$145600$张,分为$26$类;每一类训练集$5600$张,测试集$800$张 - 包括字母`a-zA-Z`,大小写合并 - MNIST:共$70000$张,分为$10$类;每一类训练集$6000$张,测试集$1000$张 上面三种数据集分别用于:**混合识别**、**字母识别**、**数字识别** ### 前端([PyQt5](https://github.com/PyQt5)) 因为项目要求编写图形界面程序,因此使用基于`Python`语言的`PyQt5`前端框架进行桌面应用程序开发。主要用到组件包括: - `QMainWindow`:用于主界面 - `QPushButton`:用于各种按钮 - `QWidget`:用于显示图片、绘制字符 ### 优化 #### 字符分割 根据使用习惯和场景,我们经常会需要识别单张图片多个字符的情况,但我们训练集中都是单图片单字符的,因此需要将图片中的字符提取出来,对每个字符利用模型进行识别 出于这种需求,我们手写了字符分割算法,主要原理就是利用字符的连通性,使用搜索算法将整个字符搜索出来,算法基本步骤如下: - 图像增强,二值化,黑底白字,方便搜索过程中联通条件 - 遍历搜索每个字符,将每个字符保存到新的图片 - 图片标准化,每个字符不标准,根据字符特征先将其填充成正方形,在将图片放缩为$(28,28)$ - 对每个字符图片利用模型识别结果 具体算法逻辑已在代码中注释 #### 手绘字符 根据需求,我们提供的桌面程序支持实时绘制字符进行识别,利用`PyQt5`中的`QWidget`作为画板。为在程序中保存绘制字符(`PyQt5`暂未发现支持),我们模拟画笔绘画原理,将画笔移动轨迹保存到矩阵中,并赋予其一定宽度,作为绘制的字符。事实证明这种方法效果不错 #### 错误反馈 程序识别可能会出错基于两个事实: - 模型在测试集上的准确率没有达到$100%$ - 用户所需识别字符和训练集图片中字符书写风格不一致 反馈有效基于以下事实: - 通过用户自己提交的字符图片(默认书写风格一致),进行二次训练,模型会逐步学会用户的书写风格 从上述分析中,可以看出错误反馈的重要性,因此本项目实现了在识别后根据识别结果的正确与否来进行反馈,使模型逐渐学习到用户的书写风格 **需要注意的是**:由于传统机器学习模型的特殊性,不能简单地进行二次训练,需要将新数据与原数据混合后重新训练,如果每次反馈后重新训练会浪费大量时间。因此我们采用多次反馈后采集到较多的数据才重新混合数据进行训练。当然,卷积神经网络模型不存在这种问题。学过卷积神经网络的同学可能会有疑惑:如果进行二次训练,会发生**灾难性希望**。但事实上这种遗忘对于我们这个项目是有利的,因为一个人的书写风格时会发生变化的,我们只需要记住最近的就行了 ### 运行 #### 代码 有以下两种方式将代码下载到本地: - 下载`zip`代码包到本地 - 克隆仓库 ``` >>git clone git@gitee.com:che-mingliang/multimedia-technology.git ``` ##### 代码结构 ``` │ button.py // 按钮类 │ combox.py // 下拉框类 │ dataset.py // 数据集设置 用于svm和rf读取数据 │ drawboard.py // 绘画板类 │ feedback.py // 反馈函数 实现反馈功能 │ imageboard.py // 图片显示框类 │ imagesplit.py // 字符分割函数 实现单图片多字符识别 │ main.py // 主函数 │ mainwindow.py // 主窗口类 │ model.py // cnn模型 │ prediction.py // 识别函数 │ README.md // 项目介绍文档 │ testset.py // 对测试集进行预测 │ text.py // 文本框类 │ ├─data // 包含程序所需数据 训练数据 测试数据 │ ├─emnist_balanced // emnist_balanced 类数据 │ │ └─EMNIST │ │ ├─processed // 参数设置 标签与字符映射关系(下同) │ │ └─raw // 训练数据与测试数据(下同) │ │ │ ├─emnist_letters // emnist_letters 类数据 │ │ └─EMNIST │ │ ├─processed │ │ └─raw │ │ │ ├─emnist_mnist // emnist_mnist 类数据 │ │ └─EMNIST │ │ ├─processed │ │ └─raw │ │ │ ├─images // 测试图片 │ │ ├─balanced // 混合识别测试图片 │ │ ├─letters // 字母识别测试图片 │ │ └─mnist // 数字识别测试图片 │ │ │ └─mydata // 自己利用其它软件生成的一些字符图片 │ ├─icon // 各种图标资源 用于标题、程序封面等 │ ├─model // 各种机器学习模型 │ └─src // 需要用到的其它静态文件 ``` #### 依赖 完成项目过程中,使用较多的第三方库,因此需要安装相关依赖 - `torch`:基于`Python`的`Pytorch`框架,使用方法规范简洁,便于对模型进行扩展 - `sklearn`:具有广泛的可靠的机器学习算法,主要使用其中的`SVM`和`RF` - `joblib`:用于保存模型参数 - `PyQt5`:`Python`语言下的桌面应用开发框架 - `idx2numpy`:用于将文件从`idx`格式转换到`numpu.ndarray`格式,主要用于`SVM`和`RF`加载数据 - `numpy`:用于存储矩阵图像,快速处理图像变换 - `PIL`:图像处理库,用于加载图片 - `cv2`:基于`Python`的`OpenCV`框架,用于处理图片 - `pyinstaller`:用于将项目打包成`.exe`文件 #### 运行 在本项目根目录下,在控制台输入: ``` >>python main.py ``` 成功运行后,将会出现如下界面: ![](src/windows.jpg) #### 打包 通过如下命令将项目打包成`.exe`文件,主要有两种做法 - 打包到指定文件夹下 ``` >> cd 到指定文件夹下 >> pyinstaller -F -w -i 图标路径 py文件路径 ``` - 打包到项目根文件夹下 ``` >>cd 到本项目根文件夹下 >>pyinstaller -F -w -i icon/hander.ico main.py ``` ### 识别 可以通过运行`main.py`文件或打包后的`.exe`文件,打开桌面应用程序。下面将具体介绍其使用方法,如何去识别图片中的字符 #### 图片 产生字符图片的方式有两种: - 上传图片:识别本地现有图片,点击`上传图片`按钮,可以上传图片 - 手绘图片:允许实时绘制所需要的字符,点击`手绘字符`按钮后,可以在右侧画板中绘制字符 - 保存图片:可以将当前界面中展示的字符图片保存到本地,通过菜单栏或快捷键(下面即将介绍)可以打开保存图片窗口,选择图片存储位置和设置相应名称后即可成功保存 #### 结果 当图片框中存在图片时,可以点击`识别结果`按钮对当前图片进行识别,识别前需要根据需求通过下拉框确定相应的数据类别和所需的模型: 数据类别: - 数字识别 - 字母识别 - 混合识别 模型: - CNN - SVM - RF 之后需要根据识别结果的正确与否来进行反馈,通过反馈功能可以使模型更加符合使用者书写习惯,提高准确率。由于传统机器学习模型的特殊性,不能对模型进行二次训练,因此必须积累足够多的反馈才能进行模型的再次训练。神经网络不存在这种问题,因此可以在每次反馈后进行模型的二次训练 #### 测试 通过前面的介绍知道每种类别数据集中包含测试集,因此我们提供一键测试的功能对测试集进行预测,并告知其准确率,依次来显示模型的好与坏。可以通过点击`测试模型`按钮对测试集进行预测。因为测试集规模较大,因此测试过程中需要等待片刻,不要视为程序卡顿 #### 快捷键 - `Ctrl+O`:打开图片文件 - `Ctrl+S`:将当前界面中的字符保存到本地 - `Esc`:退出程序 - `Ctrl+A`:作者信息 - `Ctrl+I`:跳转到本项目仓库地址 ### 贡献 - 车明亮 10195102456 - 陈元庆 10195102441