純手寫JavaScript手寫數字識別?
先貼個原始碼然後睡覺,有事後面再說吧! `<!DOCTYPE html>
<html lang="zh-cn">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>手寫體數字識別</title> <style> canvas { outline: 1px solid #000; } </style> </head>
<body> <div style="float:left;padding: 20px"> <!-- 手寫數字畫板 --> <canvas width="640" height="480" id="canvas"></canvas> <p> <button id="clear" style="float: left;">清空畫布</button> <button id="start_count" style="float: right;">開始計算</button> </p> </div> <div style="float: left;padding: 20px;width: 50%;"> <!-- 預處理後的圖片展示 --> <div> <canvas width="28" height="28" id="exhibition_booth" style="width: 256px;height:256px;"> </canvas> <span style="font-size: 300px;padding-left: 50px" id="result_box"></span> </div> <p> <div>預測結果:</div> <div id="result_box"></div> </p> <p> <p><input type="text" id="input"></p> <p><button id="btn">提交</button></p> </p> <p> <div>預測結果:</div> <div> <table> <thead> <tr> <th width="300">結果</th> <th width="500">概率</th> </tr> </thead> <tbody id="tb"> </tbody> </table> </div> </p> </div> </body> <script> //獲取手寫數字畫板 const canvas = document.getElementById('canvas'); const cact = canvas.getContext('2d'); const canvasWidth = 640; const canvasHeight = 480; cact.lineWidth = 30; cact.lineJoin = 'round'; cact.imageSmoothingEnabled = false;
//獲取與處理結果輸出畫板 const exhibition_booth = document.getElementById('exhibition_booth'); const ebct = exhibition_booth.getContext('2d'); ebct.imageSmoothingEnabled = false; const start_count = document.getElementById('start_count'); const data_box = document.getElementById('data_box'); const input = document.getElementById('input'); const btn = document.getElementById('btn'); const result_box = document.getElementById('result_box'); const tb = document.getElementById('tb'); let dataAggregation = {}; let studyCountAggregation = {}; let nowData = null; input.onfocus = function () { input.value = ''; } start_count.onclick = function () { result_box.innerText = ''; //清空小畫布 ebct.clearRect(0, 0, 28, 28); let { data } = cact.getImageData(0, 0, canvasWidth, canvasHeight); let minX = Infinity, minY = Infinity, maxX = 0, maxY = 0; //計算圖片四個邊沿的尺寸 for (let i = 0; i < data.length; i += 3) { let nowPixel = data[i]; if (nowPixel) { const nowX = (i + 1) / 4 % canvasWidth; const nowY = ((i + 1) / 4) / canvasWidth; if (nowX < minX) { minX = nowX; } if (nowY < minY) { minY = nowY; } if (nowX > maxX) { maxX = nowX; } if (nowY > maxY) { maxY = nowY; } } } let imgX = Math.ceil(minX); let imgY = Math.ceil(minY); let imgWidth = Math.ceil(maxX - minX); let imgHeight = Math.ceil(maxY - minY); let diff = Math.abs(imgWidth - imgHeight); if (diff) { if (imgWidth > imgHeight) { imgY -= diff / 2; imgHeight += diff; } else { imgX -= diff / 2; imgWidth += diff; } } // cact.lineWidth = 1; // cact.strokeRect(imgX, imgY, imgWidth, imgHeight); // cact.lineWidth = 30; //把大畫布上的圖片縮放之後複製到小畫布上 ebct.drawImage(canvas, imgX, imgY, imgWidth, imgHeight, 0, 0, 28, 28); //獲取小畫布上的所有畫素點 ({ data } = ebct.getImageData(0, 0, 28, 28)); //展開成784個元素的一維陣列(28*28的寬度) let list = []; for (let i = 0; i < data.length; i += 4) { let nowPixel = data[i - 1]; if (nowPixel) { list.push(1); } else { list.push(0); } } nowData = list; return doForecast(list); } btn.onclick = function () { const text = input.value; if (nowData) { doStudy(text, nowData); start_count.onclick(); let { result, probability } = doForecast(nowData); let i = 0; while (result != text) { ({ result, probability } = doForecast(nowData)); i++; if (i >= 100) { alert('100次都學不會,還學個雞兒!') break }; } console.log(result); } } function doForecast(list) { let i = 0; let forecastResult = []; let probabilitySum = 0; let additionalProbability = 0; for (let result in dataAggregation) { let data = dataAggregation[result]; let num = 0; for (let i = 0; i < list.length; i++) { let score = -(data[i] / studyCountAggregation[result]); if (list[i] == 0) { num += score; } else { num -= score; } } let probability = (num / 784) * 100; if (probability < 0) { additionalProbability -= probability; probability = 0; } if (probability > 100) { probability = 100; } forecastResult.push({ 'result': result , 'probability': probability }); probabilitySum += probability; i++; } forecastResult.sort(function (a, b) { return b.probability - a.probability; }); tb.innerHTML = ''; forecastResult.forEach(function (data) { const result = data.result; let probability = data.probability; const tr = document.createElement('tr'); const td1 = document.createElement('td'); const td2 = document.createElement('td'); td1.innerText = result; td2.innerText = probability + '%'; tr.appendChild(td1); tr.appendChild(td2); tb.appendChild(tr); }) let result, probability; if (forecastResult[0]) { result = forecastResult[0].result; probability = forecastResult[0].probability } if (result) { result_box.innerText = result; } if (i == 0) { alert('資料集空空如也,請告訴我這是什麼!'); } return { result, probability }; } function doStudy(result, data) { if (result in dataAggregation) { const data2 = dataAggregation[result]; if (data2.length !== data.length) { alert('資料長度不一致') return; } studyCountAggregation[result]++; for (let i = 0; i < data.length; i++) { if (data[i]) { data2[i] = data2[i] + 1; } else { data2[i] = data2[i] - 1; } } } else { dataAggregation[result] = []; studyCountAggregation[result] = 1; for (let i = 0; i < data.length; i++) { if (data[i]) { dataAggregation[result].push(1); } else { dataAggregation[result].push(-1); } } } for (let key in dataAggregation) { if (key == result) continue; const data3 = dataAggregation[key]; for (let i = 0; i < data.length; i++) { if (data[i]) { data3[i] = data3[i] - 0.05; } else { data3[i] = data3[i] + 0.05; } } studyCountAggregation[key] += 0.05; } } //清除按鈕,點選清空畫板 const clearBtn = document.getElementById('clear'); clearBtn.onclick = function () { tb.innerHTML = ''; result_box.innerText = ''; cact.clearRect(0, 0, 640, 480); ebct.clearRect(0, 0, 640, 480); } //下面是手寫畫板的事件繫結 let startPainting = false; canvas.onmousedown = function (e) { const { offsetX, offsetY } = e; cact.beginPath(); cact.moveTo(offsetX, offsetY); startPainting = true; } let lastMouseCoordinate = { offsetX: 0 , offsetY: 0 } canvas.onmousemove = function (e) { const { offsetX, offsetY } = e; if (startPainting) { const { offsetX: lastX, offsetY: lastY } = lastMouseCoordinate; if (lastX + lastY) { cact.moveTo(lastX, lastY); } lastMouseCoordinate = { offsetX, offsetY } cact.lineTo(offsetX, offsetY); cact.closePath(); cact.stroke(); } } canvas.onmouseup = function (e) { const { offsetX, offsetY } = e; startPainting = false lastMouseCoordinate = { offsetX: 0 , offsetY: 0 } } document.onmousemove = function (e) { if (e.target != canvas) { canvas.onmouseup.call(this, e); } }
</script><