日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > ChatGpt >内容正文

ChatGpt

AI应用开发实战系列之三:手写识别应用入门

發(fā)布時間:2024/7/23 ChatGpt 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AI应用开发实战系列之三:手写识别应用入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

AI應用開發(fā)實戰(zhàn) - 手寫識別應用入門

手寫體識別的應用已經(jīng)非常流行了,如輸入法,圖片中的文字識別等。但對于大多數(shù)開發(fā)人員來說,如何實現(xiàn)這樣的一個應用,還是會感覺無從下手。本文從簡單的MNIST訓練出來的模型開始,和大家一起入門手寫體識別。

在本教程結(jié)束后,會得到一個能用的AI應用,也許是你的第一個AI應用。雖然離實際使用還有較大的距離(具體差距在文章后面會分析),但會讓你對AI應用有一個初步的認識,有能力逐步搭建出能夠?qū)嶋H應用的模型。

建議和反饋,請發(fā)送到
https://github.com/Microsoft/vs-tools-for-ai/issues

聯(lián)系我們
OpenmindChina@microsoft.com

準備工作

  • 使用win10 64位操作系統(tǒng)的計算機
  • 參考上一篇博客AI應用開發(fā)實戰(zhàn) - 從零開始配置環(huán)境。在電腦上訓練并導出MNIST模型。

一、 思路

通過上一篇文章搭建環(huán)境的介紹后,就能得到一個能識別單個手寫數(shù)字的模型了,并且識別的準確度會在98%,甚至99%以上了。那么我們要怎么使用這個模型來搭建應用呢?

大致的步驟如下:

  • 實現(xiàn)簡單的界面,將用戶用鼠標或者觸屏的輸入變成圖片。
  • 將生成的模型包裝起來,成為有公開數(shù)據(jù)接口的類。
  • 將輸入的圖片進行規(guī)范化,成為數(shù)據(jù)接口能夠使用的格式。
  • 最后通過模型來推理(inference)出圖片應該是哪個數(shù)字,并顯示出來。
  • 是不是很簡單?

    二、動手

    步驟一:獲取手寫的數(shù)字

    提問:那我們要怎么獲取手寫的數(shù)字呢?

    回答:我們可以寫一個簡單的WinForm畫圖程序,讓我們可以用鼠標手寫數(shù)字,然后把圖片保存下來。

    首先,我們打開Visual Studio,選擇文件->新建->項目。

    在彈出的窗口里選擇Visual C#->Windows窗體應用,項目名稱不妨叫做DrawDigit,解決方案名稱不妨叫做MnistForm,點擊確定。

    此時,Visual Studio也自動彈出了一個窗口的設(shè)計圖。

    在DrawDigit項目上點擊右鍵,選擇屬性,在生成一欄將平臺目標從Any CPU改為x64。

    否則,DrawDigit(首選32位)與它引用的MnistForm(64位)的編譯平臺不一致會引發(fā)System.BadImageFormatException的異常。

    然后我們對這個窗口做一些簡單的修改:

    首先我們打開VS窗口左側(cè)的工具箱,這個窗口程序需要以下三種組件:
    1. PictureBox:用來手寫數(shù)字,并且把數(shù)字保存成圖片
    2. Label:用來顯示模型的識別結(jié)果
    3. Button:用來清理PictureBox的手寫結(jié)果

    那經(jīng)過一些簡單的選擇與拖動還有調(diào)整大小,這個窗口現(xiàn)在是這樣的:

    一些注意事項

  • 這些組件都可以通過右鍵->查看屬性,在屬性里修改它們的設(shè)置
  • 為了方便把PictureBox里的圖片轉(zhuǎn)化成Mnist能識別的格式,PictureBox的需要是正方形
  • 可以給這些控件起上有意義的名稱。
  • 可以調(diào)整一下label控件大小、字體等,讓它更美觀。
  • 經(jīng)過一些簡單的調(diào)整,這個窗口現(xiàn)在是這樣的:

    現(xiàn)在來讓我們愉快地給這些組件添加事件!

    還是在屬性窗口,我們選擇某個組件,右鍵->查看屬性,點擊閃電符號,給組件綁定對應的事件。每次綁定后,會跳到代碼部分,生成一個空函數(shù)。點回設(shè)計視圖繼續(xù)操作即可。

    組件類型事件
    pictureBox1在Mouse下雙擊MouseDown、MouseUp、MouseMove來生成對應的響應事件函數(shù)。
    button1如上,在Action下雙擊Click。
    Form1如上,在Behavior下雙擊Load。

    然后我們開始補全對應的函數(shù)體內(nèi)容。

    注意,如果在上面改變了控件的名稱,下面的代碼需要做對應的更改。

    廢話少說上代碼!

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D;//用于優(yōu)化繪制的結(jié)果 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;//用來保存手寫數(shù)字private Point startPoint;//用于繪制線段,作為線段的初始端點坐標private Mnist model;//用于識別手寫數(shù)字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){//當鼠標在移動,且當前處于繪制狀態(tài)時,根據(jù)鼠標的實時位置與記錄的起始坐標繪制線段,同時更新需要繪制的線段的起始坐標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,點擊確定,于是我們又多了一個項目,

    然后自己配置好這個項目的名稱、位置,點擊確定。

    然后彈出一個模型推理類庫創(chuàng)建向?qū)?#xff0c;這個時候就需要我們選擇自己之前訓練好的模型了~

    首先在模型路徑里選擇保存的模型文件的路徑。這里我們使用在AI應用開發(fā)實戰(zhàn) - 從零開始配置環(huán)境博客中訓練并導出的模型

    note:模型可在/samples-for-ai/examples/tensorflow/MNIST目錄下找到,其中output文件夾保存了檢查點文件,export文件夾保存了模型文件。

    對于TensorFlow,我們可以選擇檢查點的.meta文件,或者是保存的模型的.pb文件

    這里我們選擇在AI應用開發(fā)實戰(zhàn) - 從零開始配置環(huán)境這篇博客最后生成的export目錄下的檢查點的SavedModel.pb文件,這時程序?qū)⒆詣优渲煤门渲猛评斫涌?#xff0c;見下圖:

    類名可以自己定義,因為我們用的是MNIST,那么類名就叫Mnist好了,然后點擊確定。

    這樣,在解決方案資源管理器里,在解決方案MnistForm下,就多了一個MnistModel:

    雙擊Mnist.cs,我們可以看到項目自動把模型進行了封裝,生成了一個公開的infer函數(shù)。

    然后我們在MnistModel上右擊,再選擇生成,等待一會,這個項目就可以使用了~

    步驟三:連接兩個部分

    這一步差不多就是這么個感覺:

    I have an apple , I have a pen. AH~ , Applepen

    首先,我們來給DrawDigit添加引用,讓它能使用MnistModel。在DrawDigit項目的引用上點擊鼠標右鍵,點擊添加引用,在彈出的窗口中選擇MnistModel,點擊確定。

    然后,由于MNIST的模型的輸入是一個28×28的白字黑底的灰度圖,因此我們首先要對圖片進行一些處理。
    首先將圖片轉(zhuǎn)為28×28的大小。
    然后將RGB圖片轉(zhuǎn)化為灰階圖,將灰階標準化到[-0.5,0.5]區(qū)間內(nèi),轉(zhuǎn)換為黑底白字。
    最后將圖片用mnist模型要求的格式包裝起來,并傳送給它進行推理。
    于是,我們在pictureBox1_MouseUp中添加上這些代碼,并且在文件最初添加上using MnistModel;:

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e){//當鼠標左鍵釋放時//開始處理圖片進行推理if (e.Button == MouseButtons.Left){Bitmap digitTmp = (Bitmap)digitImage.Clone();//復制digitImage//調(diào)整圖片大小為Mnist模型可接收的大小:28×28using (Graphics g = Graphics.FromImage(digitTmp)){g.InterpolationMode = InterpolationMode.HighQualityBicubic;g.DrawImage(digitTmp, 0, 0, MnistImageSize, MnistImageSize);}//將圖片轉(zhuǎn)為灰階圖,并將圖片的像素信息保存在list中var image = new List<float>(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模型規(guī)定的輸入格式var batch = new List<IEnumerable<float>>();batch.Add(image);//將圖片傳送給mnist模型進行推理var result = model.Infer(batch);//將推理結(jié)果輸出label1.Text = result.First().First().ToString();}}

    最后讓我們嘗試一下運行~

    三、效果展示

    現(xiàn)在我們就有了一個簡單的小程序,可以識別手寫的數(shù)字了。

    趕緊試試效果怎么樣~

    注意

  • 路徑中不能有中文字符,否則可能找不到模型。
  • 進階

    那么,如果要識別多個連寫的數(shù)字,或支持字母該怎么做呢?大家多用用也會發(fā)現(xiàn),如果數(shù)字寫得很小,或者沒寫到正中,識別起來正確率也會不高。要解決這些問題,做成真正的產(chǎn)品,就不止這一個模型了。比如在多個數(shù)字識別中,可能要根據(jù)經(jīng)驗來切分圖,或者訓練另一個模型來檢測并分割數(shù)字。要支持字母,則需要重新訓練一個包含手寫字母的模型,并準備更多的字母的數(shù)據(jù)。要解決字太小的問題,還要檢測一下字的大小,做合適的放大等等。

    我們可以看到,一個訓練出來的模型本身到一個實際的應用之間還有不少的功能要實現(xiàn)。希望我們這一系列的介紹,能夠幫助大家將機器學習的概念帶入到傳統(tǒng)的編程領(lǐng)域中,做出更聰明的產(chǎn)品。

    總結(jié)

    以上是生活随笔為你收集整理的AI应用开发实战系列之三:手写识别应用入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。