网站建设实验的总结,西安企业网站建设价格,网站上做的图片不清晰是怎么回事,专业网站构建AI应用开发实战 - 手写识别应用入门
手写体识别的应用已经非常流行了#xff0c;如输入法#xff0c;图片中的文字识别等。但对于大多数开发人员来说#xff0c;如何实现这样的一个应用#xff0c;还是会感觉无从下手。本文从简单的MNIST训练出来的模型开始#xff0c;和…AI应用开发实战 - 手写识别应用入门
手写体识别的应用已经非常流行了如输入法图片中的文字识别等。但对于大多数开发人员来说如何实现这样的一个应用还是会感觉无从下手。本文从简单的MNIST训练出来的模型开始和大家一起入门手写体识别。
在本教程结束后会得到一个能用的AI应用也许是你的第一个AI应用。虽然离实际使用还有较大的距离具体差距在文章后面会分析但会让你对AI应用有一个初步的认识有能力逐步搭建出能够实际应用的模型。
建议和反馈请发送到 https://github.com/Microsoft/vs-tools-for-ai/issues
联系我们 OpenmindChinamicrosoft.com
准备工作
使用win10 64位操作系统的计算机参考上一篇博客AI应用开发实战 - 从零开始配置环境。在电脑上训练并导出MNIST模型。
一、 思路
通过上一篇文章搭建环境的介绍后就能得到一个能识别单个手写数字的模型了并且识别的准确度会在98%甚至99%以上了。那么我们要怎么使用这个模型来搭建应用呢
大致的步骤如下
实现简单的界面将用户用鼠标或者触屏的输入变成图片。将生成的模型包装起来成为有公开数据接口的类。将输入的图片进行规范化成为数据接口能够使用的格式。最后通过模型来推理(inference)出图片应该是哪个数字并显示出来。
是不是很简单
二、动手
步骤一获取手写的数字
提问那我们要怎么获取手写的数字呢 回答我们可以写一个简单的WinForm画图程序让我们可以用鼠标手写数字然后把图片保存下来。 首先我们打开Visual Studio选择文件-新建-项目。 在弹出的窗口里选择Visual C#-Windows窗体应用项目名称不妨叫做DrawDigit解决方案名称不妨叫做MnistForm点击确定。 此时Visual Studio也自动弹出了一个窗口的设计图。 在DrawDigit项目上点击右键选择属性在生成一栏将平台目标从Any CPU改为x64。 否则DrawDigit首选32位与它引用的MnistForm64位的编译平台不一致会引发System.BadImageFormatException的异常。
然后我们对这个窗口做一些简单的修改
首先我们打开VS窗口左侧的工具箱这个窗口程序需要以下三种组件 1. PictureBox用来手写数字并且把数字保存成图片 2. Label用来显示模型的识别结果 3. Button用来清理PictureBox的手写结果
那经过一些简单的选择与拖动还有调整大小这个窗口现在是这样的 一些注意事项
这些组件都可以通过右键-查看属性在属性里修改它们的设置为了方便把PictureBox里的图片转化成Mnist能识别的格式PictureBox的需要是正方形可以给这些控件起上有意义的名称。可以调整一下label控件大小、字体等让它更美观。
经过一些简单的调整这个窗口现在是这样的 现在来让我们愉快地给这些组件添加事件
还是在属性窗口我们选择某个组件右键-查看属性点击闪电符号给组件绑定对应的事件。每次绑定后会跳到代码部分生成一个空函数。点回设计视图继续操作即可。
组件类型事件pictureBox1在Mouse下双击MouseDown、MouseUp、MouseMove来生成对应的响应事件函数。button1如上在Action下双击Click。Form1如上在Behavior下双击Load。
然后我们开始补全对应的函数体内容。
注意如果在上面改变了控件的名称下面的代码需要做对应的更改。
废话少说上代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;//用于优化绘制的结果
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MnistModel;namespace DrawDigit
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private Bitmap digitImage;//用来保存手写数字private Point startPoint;//用于绘制线段作为线段的初始端点坐标private Mnist model;//用于识别手写数字private const int MnistImageSize 28;//Mnist模型所需的输入图片大小private void Form1_Load(object sender, EventArgs e){//当窗口加载时绘制一个白色方框model new Mnist();digitImage new Bitmap(pictureBox1.Width, pictureBox1.Height);Graphics g Graphics.FromImage(digitImage);g.Clear(Color.White);pictureBox1.Image digitImage;}private void clean_click(object sender, EventArgs e){//当点击清除时重新绘制一个白色方框同时清除label1显示的文本digitImage new Bitmap(pictureBox1.Width, pictureBox1.Height);Graphics g Graphics.FromImage(digitImage);g.Clear(Color.White);pictureBox1.Image digitImage;label1.Text ;}private void pictureBox1_MouseDown(object sender, MouseEventArgs e){//当鼠标左键被按下时记录下需要绘制的线段的起始坐标startPoint (e.Button MouseButtons.Left) ? e.Location : startPoint;}private void pictureBox1_MouseMove(object sender, MouseEventArgs e){//当鼠标在移动且当前处于绘制状态时根据鼠标的实时位置与记录的起始坐标绘制线段同时更新需要绘制的线段的起始坐标if (e.Button MouseButtons.Left){Graphics g Graphics.FromImage(digitImage);Pen myPen new Pen(Color.Black, 40);myPen.StartCap LineCap.Round;myPen.EndCap LineCap.Round;g.DrawLine(myPen,startPoint, e.Location);pictureBox1.Image digitImage;g.Dispose();startPoint e.Location;}}private void pictureBox1_MouseUp(object sender, MouseEventArgs e){//当鼠标左键释放时//同时开始处理图片进行推理//暂时不处理这里的代码}}
}步骤二把模型包装成一个类
将模型包装成一个C#是整个过程中比较麻烦的一步。所幸的是Tools for AI对此提供了很好的支持。进一步了解可以看这里。
首先我们在解决方案MnistForm下点击鼠标右键选择添加-新建项目在弹出的窗口里选择AI Tools-Inference-模型推理类库名称不妨叫做MnistModel点击确定于是我们又多了一个项目 然后自己配置好这个项目的名称、位置点击确定。
然后弹出一个模型推理类库创建向导这个时候就需要我们选择自己之前训练好的模型了~ 首先在模型路径里选择保存的模型文件的路径。这里我们使用在AI应用开发实战 - 从零开始配置环境博客中训练并导出的模型 note模型可在/samples-for-ai/examples/tensorflow/MNIST目录下找到其中output文件夹保存了检查点文件export文件夹保存了模型文件。 对于TensorFlow我们可以选择检查点的.meta文件或者是保存的模型的.pb文件
这里我们选择在AI应用开发实战 - 从零开始配置环境这篇博客最后生成的export目录下的检查点的SavedModel.pb文件这时程序将自动配置好配置推理接口见下图 类名可以自己定义因为我们用的是MNIST那么类名就叫Mnist好了然后点击确定。
这样在解决方案资源管理器里在解决方案MnistForm下就多了一个MnistModel 双击Mnist.cs我们可以看到项目自动把模型进行了封装生成了一个公开的infer函数。
然后我们在MnistModel上右击再选择生成等待一会这个项目就可以使用了~
步骤三连接两个部分
这一步差不多就是这么个感觉 I have an apple , I have a pen. AH~ , Applepen 首先我们来给DrawDigit添加引用让它能使用MnistModel。在DrawDigit项目的引用上点击鼠标右键点击添加引用在弹出的窗口中选择MnistModel点击确定。 然后由于MNIST的模型的输入是一个28×28的白字黑底的灰度图因此我们首先要对图片进行一些处理。 首先将图片转为28×28的大小。 然后将RGB图片转化为灰阶图将灰阶标准化到[-0.5,0.5]区间内转换为黑底白字。 最后将图片用mnist模型要求的格式包装起来并传送给它进行推理。 于是我们在pictureBox1_MouseUp中添加上这些代码并且在文件最初添加上using MnistModel; private void pictureBox1_MouseUp(object sender, MouseEventArgs e){//当鼠标左键释放时//开始处理图片进行推理if (e.Button MouseButtons.Left){Bitmap digitTmp (Bitmap)digitImage.Clone();//复制digitImage//调整图片大小为Mnist模型可接收的大小28×28using (Graphics g Graphics.FromImage(digitTmp)){g.InterpolationMode InterpolationMode.HighQualityBicubic;g.DrawImage(digitTmp, 0, 0, MnistImageSize, MnistImageSize);}//将图片转为灰阶图并将图片的像素信息保存在list中var image new Listfloat(MnistImageSize * MnistImageSize);for (var x 0; x MnistImageSize; x){for (var y 0; y MnistImageSize; y){var color digitTmp.GetPixel(y, x);var a (float)(0.5 - (color.R color.G color.B) / (3.0 * 255));image.Add(a);}}//将图片信息包装为mnist模型规定的输入格式var batch new ListIEnumerablefloat();batch.Add(image);//将图片传送给mnist模型进行推理var result model.Infer(batch);//将推理结果输出label1.Text result.First().First().ToString();}}最后让我们尝试一下运行~
三、效果展示
现在我们就有了一个简单的小程序可以识别手写的数字了。
赶紧试试效果怎么样~ 注意
路径中不能有中文字符否则可能找不到模型。
进阶
那么如果要识别多个连写的数字或支持字母该怎么做呢大家多用用也会发现如果数字写得很小或者没写到正中识别起来正确率也会不高。要解决这些问题做成真正的产品就不止这一个模型了。比如在多个数字识别中可能要根据经验来切分图或者训练另一个模型来检测并分割数字。要支持字母则需要重新训练一个包含手写字母的模型并准备更多的字母的数据。要解决字太小的问题还要检测一下字的大小做合适的放大等等。
我们可以看到一个训练出来的模型本身到一个实际的应用之间还有不少的功能要实现。希望我们这一系列的介绍能够帮助大家将机器学习的概念带入到传统的编程领域中做出更聪明的产品。