久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

自己動手做一個識別手寫數(shù)字的web應(yīng)用04

 Mixlab交叉學(xué)科 2020-11-07

接著往期的3篇繼續(xù),,一步步動手做:

自己動手做一個識別手寫數(shù)字的web應(yīng)用01

自己動手做一個識別手寫數(shù)字的web應(yīng)用02

自己動手做一個識別手寫數(shù)字的web應(yīng)用03

如果你練習(xí)里前面三篇,,相信你已經(jīng)熟悉了DockerKeras,以及Flask了,,接下來我們實現(xiàn)一個提供給用戶輸入手寫字的前端web頁面。

前端畫板我們可以自己用最基本的canvas寫,,也可以選擇封裝好的開源庫:

下面介紹2個比較好的模擬手寫效果的畫板庫:

1 signature_pad

https://github.com/szimek/signature_pad/

2 drawingboard.js

https://github.com/Leimi/drawingboard.js

這邊我選擇的是signature_pad,。

HTML代碼:

<!doctype html>
<html lang="zh"><head>  
<meta charset="utf-8">  
<title>mnist demo</title>  
<meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">  
<link rel="stylesheet" href="./static/css/main.css"></head>

<body onselectstart="return false">  
<div id="mnist-pad">

<div class="mnist-pad-body">      <canvas></canvas>
</div>    
<div class="mnist-pad-footer">      <div class="mnist-pad-result">        <h5>識別結(jié)果:</h5>        <h5 id="mnist-pad-result"></h5>      </div> 
<div class="mnist-pad-actions">   <button type="button" id="mnist-pad-clear">清除</button>   <button type="button" id="mnist-pad-save">識別</button>
</div>

</div></div>  
<script src="./static/js/signature_pad.js"></script>
<script src="./static/js/mnist.js"></script>  
<script src="./static/js/app.js"></script>

</body>

</html>

移動端注意要寫這句標(biāo)簽,把屏幕縮放設(shè)為no,,比例設(shè)為1:

<meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

CSS代碼:

body {  display: flex;  justify-content: center;  align-items: center;  height: 100vh;  width: 100%;  user-select: none;  margin: 0;  padding: 0; }
h5 {  margin: 0;  padding: 0

}
#mnist-pad {  position: relative;  display: flex;  flex-direction: column;  font-size: 1em;  width: 100%;  height: 100%;  background-color: #fff;  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.08) inset;  padding: 16px; }
.mnist-pad-body {  position: relative;  flex: 1;  border: 1px solid #f4f4f4; }
.mnist-pad-body canvas {  position: absolute;  left: 0;  top: 0;  width: 100%;  height: 100%;  border-radius: 4px;  box-shadow: 0 0 5px rgba(0, 0, 0, 0.02) inset; }
.mnist-pad-footer {  color: #C3C3C3;  font-size: 1.2em;  margin-top: 8px;  margin-bottom: 8px; }
.mnist-pad-result {  display: flex;  justify-content: center;  align-items: center;  margin-bottom: 8px; }
.mnist-pad-actions {  display: flex;  justify-content: space-between;  margin-bottom: 8px; }
#mnist-pad-clear {  height: 44px;  background-color: #eeeeee;  width: 98px;  border: none;  font-size: 16px;  color: #4a4a4a; }
#mnist-pad-save {  height: 44px;  background-color: #3b3b3b;  width: 98px;  border: none;  font-size: 16px;  color: #ffffff; }

CSS樣式都是一些常用的,,有興趣可以自己實現(xiàn)個簡單的UI。

JS代碼,,有3個文件:

signature_pad.js 這是引用的開源庫,;

mnist.js 這是我們給開源庫寫的一些擴展,下文會介紹,;

app.js主要是一些初始化,,事件綁定,請求后端接口的處理,。

先來看看app.js:

1 初始化畫板,,綁定按鈕事件;

var clearBtn = document.getElementById("mnist-pad-clear");
var saveBtn = document.getElementById("mnist-pad-save");

var
canvas = document.querySelector("canvas");

var
mnistPad = new SignaturePad(canvas, {
   backgroundColor: 'transparent',
   minWidth: 6,
   maxWidth: 8
});
   
clearBtn.addEventListener("click", function (event) {  mnistPad.clear(); });

saveBtn.addEventListener("click", function (event) {
     if (mnistPad.isEmpty()) {        alert("請書寫一個數(shù)字");    } else {         mnistPad.getMNISTGridBySize(true,28,img2text);    } });

注意minWidth及MaxWidth的設(shè)置,,我試驗下來,,比較好的數(shù)值是6跟8,識別效果較好,,也可以自行試驗修改,。

ministPad的方法,getMNISTGridBySize將把截取畫板上的手寫數(shù)字,,并縮放成28x28的尺寸,,然后調(diào)用img2text函數(shù)。

img2text主要是把28x28的圖片傳給后端,,獲取識別結(jié)果,,這邊由于canvas的數(shù)據(jù)是base64,需要用到轉(zhuǎn)化為blob的函數(shù),,dataURItoBlob(github上有寫好的),,轉(zhuǎn)化后通過構(gòu)造一個表單,,注意文件名predictImg一定要與后端flask接受函數(shù)里的寫的一致。調(diào)用XMLHttpRequest請求后端接口即可,。

這一步“如何把canvas生成的圖片上傳至后端”是個很典型的問題,。

function img2text(b64img){

 var formData = new FormData();
 var blob = dataURItoBlob(b64img);
   formData.append("predictImg", blob);
   var request = new XMLHttpRequest();
     request.onreadystatechange = function () {
      if (request.readyState == 4) {
         if ((request.status >= 200 && request.status < 300) || request.status == 304) {
         console.log(request.response)
         document.querySelector('#mnist-pad-result').innerHTML=request.response;            };        }    };  request.open("POST", "./predict");  request.send(formData); };

還有一個比較重要的函數(shù):

畫板根據(jù)屏幕尺寸自適應(yīng)的代碼(尤其是PC端,記得加):

function resizeCanvas() {
 var ratio =  Math.max(window.devicePixelRatio || 1, 1);  canvas.width = canvas.offsetWidth;  canvas.height = canvas.offsetHeight;
//  canvas.getContext("2d").scale(ratio, ratio);  mnistPad.clear(); },;
window.onresize = resizeCanvas; resizeCanvas();

到這一步可以試一下前端的輸入效果先:

接下來完成mnist.js

signature_pad有個方法是toData,,可以獲取所有手寫輸入的坐標(biāo)點。

var ps=mnistPad.toData()[0];
mnistPad._ctx.strokeStyle='red';
ps.forEach((p,i)=>{    mnistPad._ctx.beginPath();    mnistPad._ctx.arc(p.x, p.y, 4, 0, 2 * Math.PI);    mnistPad._ctx.stroke(); })

我們可以在chrome的控制臺直接試驗,。

紅色的圈圈就是所有的坐標(biāo)點,,只要求出如下圖所示的紫色框,第一步也就完成了,。

signature_pad擴展個getArea方法:

SignaturePad.prototype.getArea = function() {
var xs = [],    ys = [];

var
orign = this.toData();

for
(var i = 0; i < orign.length; i++) {
   var orignChild = orign[i];
   for (var j = 0; j < orignChild.length; j++) {        xs.push(orignChild[j].x);        ys.push(orignChild[j].y);      }    };

 var paddingNum = 30;
 var min_x = Math.min.apply(null, xs) - paddingNum;
 var min_y = Math.min.apply(null, ys) - paddingNum;
 var max_x = Math.max.apply(null, xs) + paddingNum;
 var max_y = Math.max.apply(null, ys) + paddingNum;
  
 var width = max_x - min_x,      height = max_y - min_y;
  
  var grid = {      x: min_x,      y: min_y,      w: width,      h: height    };
  
   return grid;
     };

測試下:

注意paddingNum,,我設(shè)置了個30的值,把邊框稍微放大了下,,原因見mnist手寫字訓(xùn)練集的圖片就知道啦,。

到這一步,我們的手寫字?jǐn)?shù)據(jù)集是下圖這樣的:

我們還需要把邊框變成方形,。

再寫個轉(zhuǎn)換函數(shù):

 SignaturePad.prototype.change2grid = function(area) {
     var w = area.w,      h = area.h,      x = area.x,      y = area.y;    var xc = x,      yc = y,      wc = w,      hc = h;    if (h >= w) {      xc = x - (h - w) * 0.5;      wc = h;    } else {      yc = y - (w - h) * 0.5;      hc = w;    };    return {      x: xc,      y: yc,      w: wc,      h: hc    }  }

原理如下圖,,判斷下長邊是哪個,然后計算出x,y,width,height即可,。

寫好代碼后,,試一下:

紅框是最后要提交的范圍。

這個時候,,還要處理下,,把圖片變成黑底白字的圖片,因為MNIST數(shù)據(jù)集是這樣的,。

主要代碼如下:

   ctx.fillStyle = "white";    ctx.fillRect(0, 0, grid.w, grid.h);    ctx.drawImage(img, grid.x, grid.y, grid.w, grid.h, 0, 0, size, size);
   
   var imgData = ctx.getImageData(0, 0, size, size);
   
   for (var i = 0; i < imgData.data.length; i += 4) {        imgData.data[i] = 255 - imgData.data[i];        imgData.data[i + 1] = 255 - imgData.data[i + 1];        imgData.data[i + 2] = 255 - imgData.data[i + 2];        imgData.data[i + 3] = 255;     }
        ctx.putImageData(imgData, 0, 0);

畫上背景,,遍歷像素,把顏色反色下就ok啦,。

最后都測試下:

ps:

今天我用上了Markdown Here美化了代碼塊的展示,,推薦下:

使用 Markdown Here 瀏覽器插件,能夠直接在微信公眾平臺的圖文編輯器中把 Markdown 轉(zhuǎn)換成帶樣式的文本,,從而避免拷貝引起的樣式丟失,,再對「代碼塊」的縮進、換行,、字號,、行間距進行微調(diào)即可。

https:///get.html

最后,注意下MNIST數(shù)據(jù)集里的數(shù)據(jù),,對應(yīng)的是灰度圖,,28x28的尺寸,黑底白字,,并且數(shù)字是像素的重心居中處理的。本文沒有介紹如何把web前端的手寫字根據(jù)重心居中處理這一內(nèi)容,,將會挑選合適時機介紹,,用上了可以提高識別率哦!

相關(guān)源代碼,,可以留言獲取,。

這個系列也基本上完成了,如果你有疑問可以留言,。

我要不要考慮開個面授課?。?strong style="white-space: normal;">如果有10個人以上在下方留言區(qū)留言,我就考慮開設(shè)了),,大家抱著電腦,,我們一起動手花個半天,親手實現(xiàn)一個識別手寫數(shù)字的web應(yīng)用,。

技術(shù)棧:

Docker+Keras+Flask+JS+HTML+CSS,。

涉及到的內(nèi)容都可以講解。

地點限于:上海,。

  近期熱文:

如何技術(shù)地識別雙十一的“騙”局

人工智能設(shè)計師之智能排版v0.0.3

全民刷軍裝背后的AI技術(shù)及簡單實現(xiàn)


碼字不易,,開啟新的打賞方式:


本公眾號定期更新關(guān)于

設(shè)計師、程序員發(fā)揮創(chuàng)意

互相融合的指南,、作品,。

主要技術(shù)棧:

nodejs、react native,、electron

Elasticsearch

Solidity

Keras

    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多