#概要
AzureのOCR機能であるComputerVisionを利用したOCR Webページを作成しました
初めてAuzreを触ったり Web環境の構築を行ったので備忘録として書いていきたいと思います
また どなたかの参考になれば幸いです
こちらの記事及び関連サイトを参考に作成しました (コードはほぼコピペです)
[AzureのComputer Vision API&Face API ] WEBカメラでパシャリと感情分析やOCRしてみる
#1.Azure無料アカウント作成
Azureのアカウントを持ってない人はまずアカウントを作成してください
1年間 特定のサービスを無料で利用できたり30日間¥22,500分の利用が無料になります
#2.リソースグループ作成
####1.①左上のメニューバー → ②[リソースグループ] → ③[作成] をクリック
####2.各項目を入力し、[確認および作成]をクリック
①サブスクリプション:無料枠で使用したかったので[FreeTrial]を選択
②リソースグループ:任意の名前を入力
③リージョン:日本で使用するので[東日本]を選択
####4.右上に表示されるポップアップの[リソースグループに移動]をクリック
####5.リソースグループの確認
先ほど付けた名前でリソースグループが作成されていることが確認できます
#3.ComputerVision作成
####1.検索ボックスでCognitive Serviceを検索
####2.Cognitive Seviceのページで[+追加]をクリック
####3.検索ボックスでComputer Visionを検索し、クリック
####5.各項目を入力し、[作成]をクリック
リソースグループの作成時と同様に各項目を入力する
①名前:任意の名前を入力
②サブスクリプション:無料枠で使用したかったので[FreeTrial]を選択
③場所:日本で使用するので[東日本]を選択
④価格レベル:無料枠で使用したかったので[Free F0]を選択
⑤リソースグループ:先ほど作成した[test-rg]を選択
※注意※
①[名前]はAzure上で一意の名前である必要があります
入力した名前が既に使用されている場合は以下のような警告が表示されます
####6.リソースのデプロイ
デプロイの完了を待つ
↓
完了したら[リソースに移動]をクリック
####7.Computer Visionの確認
Computer Visionのリソースが作成されていることが確認できます
#4.環境構築
PCのカメラを使って文字を読み取るOCRサイトを作成するにあたり 環境構築を行います
必要なフレームワーク・ライブラリは以下の通りです
・Node.js
・Vue.js
・axios
ちなみに すでに環境がある方は **8.コードを書く**まで飛ばしてください
#5.Node.jsインストール
Vue.jsをインストールするために必要なnpmをインストールするために
まずはNode.jsをインストールします
1.Node.jsのHPで[推奨版]を選択
3.チェックボックスにチェックを入れ [Next]をクリック
4.インストール先を確認し [Next]をクリック (今回はデフォルトのまま進む)
5.インストールするモジュールを確認し [Next]をクリック (今回はデフォルトのまま進む)
6.チェックを外した状態で [Next]をクリック (今回はデフォルトのまま進む)
オプションのモジュールをインストールしたい場合はチェックを入れて進んでください
これでNode.js及びnpmをインストールできました
#6.Vue.jsインストール
PCのカメラを使用するためにVue.jsをインストールします
コマンドプロンプトで以下を実行します
npm install -g vue-cli
#7.axiosインストール
OCR結果を受け取るためにaxiosをインストールします
コマンドプロンプトで以下を実行します
npm install axios
#8.コードを書く
任意の名前でhtmlファイルを作成し コードを書きます
長いのでサンプルコードは**12.サンプルコード**に記載します
#9.ComputerVisionのキーを取得
サンプルコード内にある
ここにキーを記載
とここにエンドポイントを記載
に自分のComputerVisionの情報を記載します
まずはキーを取得します
####1.[キーとエンドポイント]画面に遷移
3.Computer Visionの作成の**7.Computer Visionの確認**の画面を表示し、左のメニューから[リソースの管理]>[キーとエンドポイント]をクリック
####3.コード内の「ここにキーを記載」を[キー1]に置き換える
headers: {
'Content-type': 'application/octet-stream',
'Ocp-Apim-Subscription-Key':'ここにキーを記載'
},
#10.ComputerVisionのエンドポイントURLを取得
####1.以下のサイトにアクセスし、リージョンを選択
Computer Vision API - v3.0
2.リソースグループ作成の**2.各項目を入力し、[確認および作成]をクリック**で選択したリージョンをクリックする
(この記事では[Japan East]を選択)
####2.各項目を選択
①[japaneast.api~~]と[[resouce name].cognitive~~]のどちらかを選択
(この記事では[japaneast.api~~]を選択)
②読みたい文字の言語を選択
デフォルトはunk (ComputerVisionが言語を判断する)
日本語の場合はja
英語の場合はen を選択
③画像のテキストの向きを検出するかどうかを選択
④APIに送信される本文のタイプを選択
(この記事では[application/octet-stream]を選択)
⑤10.ComputerVisionのキーを取得 で取得したキーを入力
####3.エンドポイントURLをコピー
[Request URL]に書かれているURLをコピーする
####4.コード内の「ここにキーを記載」を[Request URL]に置き換える
const COMPUTER_VISION_API_ENDPOINT_URL = 'ここにエンドポイントを記載';
#11.実行してみる
htmlファイルをブラウザーで開きます
[カメラON]ボタンを押してPCのカメラの前に読み取り対象を持っていき
[写真を撮る!]ボタンを押して写真を撮ると
[読み込み結果 :]に結果が返ってきます
【読み取り対象】Cloud Architect Powered by A.R.I. Group
【読み取り結果】CloudArchitectA.R.I.Group
「Powered by」が読み取れてないですね
文字が小さすぎるでしょうか…
PCのカメラの精度も影響してくるかと思いますが 他の文字はきちんととれてるみたいです
色んな言語を読み込ませてみたいですね
🌷🌷🌷🌷🌷
長くなってしまいましたが お付き合いいただきありがとうございました
#12.サンプルコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TestPageForOCR</title>
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css" />
<!-- Load polyfills to support older browsers -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver"
crossorigin="anonymous"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<!-- Load the following for BootstrapVueIcons support -->
<script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue-icons.min.js"></script>
</head>
<body>
<br>
<br>
<div class="container">
<div id="appFaceAPI-File">
<div class="row">
<div class="col">
<h2>①判定したい画像を選んでください</h2>
</div>
</div>
<div class="row">
<div class="col">
<div class="form-group">
<!-- https://bootstrap-vue.org/docs/components/form-file -->
<div>
<!-- Styled -->
<b-form-file
v-model="file"
:state="Boolean(file)"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
@change="handlerFileChange"
></b-form-file>
<div class="mt-3">ファイルネーム: {{ file ? file.name : '' }}</div>
</div>
<div>
<br>
<h2><p>②カメラで撮影します。</p></h2>
<p>※ カメラで撮影する前にカメラをONにしてください。</p>
<p>※ カメラOFFで消えない時はリロードするとカメラを停止できます。</p>
</div>
<div>
<table>
<tr>
<td><button id="on" v-on:click="btnON()">カメラON</button></td>
<td><button id="off" v-on:click="btnOFF()">カメラOFF</button></td>
<td><b-button v-on:click="hanlderCapture">写真を撮る!</button></td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div>
<table>
<tr>
<td>
<!-- キャプチャした画像 -->
<h3>カメラの映像</h3>
<video ref="video" id="video" width="320" height="240" autoplay></video>
</td>
<td>
<h3>写真のキャプチャ</h3>
<canvas ref="canvas" id="canvas" width="320" height="240"></canvas>
</td>
<td>
<!-- 選択したサムネイル -->
<h3>選択した画像のサムネ</h3>
<img id="output" width="320" height="240" >
</td>
</tr>
</table>
</div>
<div class="row">
<div class="col">
<h2>読み込み結果 : </h2>
<pre><code>{{ letter }}</code></pre>
</div>
</div>
<br>
</div>
</div>
<!-- axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
const app = new Vue({
el: '#appFaceAPI-File',
data: {
response: '',
file: null,
feel:'',
score:'',
letter:'',
oarray:'',
/// ここから下はカメラ用
video: {},
canvas: {},
captures: []
},
methods: {
handlerFileChange: async function (e) {
//console.log('handlerFileChange');
// 1. ファイルアップロードの入力から、まずファイル情報を取り出す
const files = e.target.files || e.dataTransfer.files;
const file = files[0];
/// サムネイルを取得するための記述
// https://web.dev/read-files/ 参照
const output = document.getElementById('output');
const reader = new FileReader();
reader.addEventListener('load', event => {
output.src = event.target.result;
});
reader.readAsDataURL(file);
////
// 2. ファイル参照の中から ArrayBuffer としてデータを取り出す
let contentBuffer = await this.readFileAsync(file);
console.log('bbbbbb' + file);
this.sendCognitiveAsFile(contentBuffer);
},
// ファイル情報の中から ArrayBuffer としてデータを取り出す
// 本来 onnload で取り出すが await / async で呼び出せるようにしている
readFileAsync: function (file) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
//console.log('aaaaaa' + reader.result);
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
})
},
///////////////////////// 写真
// キャプチャボタンの挙動
hanlderCapture: async function () {
this.canvas = this.$refs.canvas
this.canvas.getContext('2d').drawImage(this.video, 0, 0, 320, 240);
// まず、CanvasからBlogデータを取得
const blob = await this.getBlogData(this.canvas);
// BlogデータをArrayBufferに変換
const contentBuffer = await this.readBlobToArrayBuffTo(blob);
// console.log(contentBuffer);
this.sendCognitiveAsFile(contentBuffer);
},
getBlogData: function (canvas) {
return new Promise((resolve, reject) => {
try {
// 標準はPNG 読み込みなので、ファイルサイズが重くなりがち
/*
canvas.toBlob(function(blob){
resolve(blob);
});
*/
// JPEG画質も指定できる
canvas.toBlob(function(blob){
resolve(blob);
},"image/jpeg", 0.8);
} catch( e ){
reject(e);
}
})
},
// Blob の中から ArrayBuffer としてデータを取り出す
// Blob : Binary Large Object バイナリデータを格納する場合のデータ型
//
// 本来 onnload で取り出すが await / async で呼び出せるようにしている
readBlobToArrayBuffTo: function (file) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
})
},
/////////////////////////////////
// このあたりは以下の記事を参考に。
// https://www.1ft-seabass.jp/memo/2020/05/07/azure-face-api-application-octet-stream-using-axios/
sendCognitiveAsFile: async function(contentBuffer) {
const COMPUTER_VISION_API_ENDPOINT_URL = 'ここにエンドポイントを記載';
// サブスクリプションをOcp-Apim-Subscription-Keyヘッダーに
// JSONで送るのでContent-typeヘッダーにapplication/octet-stream指定
const config = {
url: COMPUTER_VISION_API_ENDPOINT_URL,
method: 'post',
headers: {
'Content-type': 'application/octet-stream',
'Ocp-Apim-Subscription-Key':'ここにキーを記載'
},
data: contentBuffer
};
var alltext = '';
var ocrarray = [];
// axios
try {
// POSTリクエストで送る
const responseAzure = await axios.request(config);
console.log('post OK');
// データ送信が成功するとレスポンスが来る
console.log(responseAzure.data);
for(let i = 0; i <= responseAzure.data.regions[0].lines.length -1; i++){
ocrarray.push(responseAzure.data.regions[0].lines[i].words);
for(let j = 0; j <= responseAzure.data.regions[0].lines[i].words.length - 1 ; j++){
alltext = alltext + responseAzure.data.regions[0].lines[i].words[j].text ;
//console.log(responseAzure.data.regions[0].lines[i].words.length);
}
}
this.letter = alltext ;
this.oarray = ocrarray ;
} catch (error) {
console.log('post Error');
// ダメなときはエラー
console.error(error);
}
},
// ストリームの停止
btnOFF(){
this.video = this.$refs.video;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
this.video.srcObject = stream ;
stream.getTracks().forEach(track => track.stop()); // ストリームの停止
})
}
},
// ストリームの開始
btnON(){
this.video = this.$refs.video;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
this.video.srcObject = stream ;
this.video.play() ;
})
}
}
}
,
mounted() {
console.log('mounted');
}
})
</script>