memorandums

日々の生活で問題解決したこと、知ってよかったことなどを自分が思い出すために記録しています。

サンデーぷろぐらみんぐ

小1の子供が足し算や引き算を勉強しています。

公文式もやっているので大量の計算問題に嫌気がさしているようで。。。

ふと、音声で問題が出て音声で答えられたら面白がってくれるんじゃないかなぁ。。。と思いまして。

土曜日の朝からあれこれやりまじめました。

どうせならJSで気軽にやりたいな。。。と思い、ぐぐって情報集めしました。

音声合成音声認識は以下を参考にさせてもらいました。

qiita.com

qiita.com

で、できたのが、こちらです。

娘に遊ばせたのが以下です。なんか動作がおかしいですが。。。ご愛嬌です。

www.youtube.com

勉強不足でわかりませんがChrome限定のようです。スマホChromeでも動きません。とりあえず遊びで作ったのでいいですが。。。気になりますね。

ちなみに、最初は、文字を書いたカードをPCのカメラに見せると文字認識して答え合わせができる。。。感じにしたがったです。途中まではいい感じだったのですが、文字領域だけを認識させることができず(映った顔とかが文字として認識されてしまいノイズになる)、断念しました。その足跡も残しておきたいと思います。

上記と重なりますが、最初、音声合成のやり方を試しました。

qiita.com

続いて、カメラを使って画像を取得してみました。

html5experts.jp

ちなみに、カメラはローカル(htmlファイルをブラウザにD&Dする)では実行できないので、MacローカルのWebサーバー(userdir)を利用するのに以下を参照しました。

qiita.com

続いてOCR

qiita.com

動くには動いたのですがちょっと遅い。そこで以下も試しました。

Ocrad.js - Optical Character Recognition in Javascript

確かに速い!ただ、文字領域以外を誤認識してしまう。。。で、文字領域を抽出するライブラリがないか探したところ、上記のOCR(Tesseract.js)はそこまでやっているとか、それでTesseract.jsに戻りました。

カメラの画像は大きいのと、カラーだと誤認識が多いようなのでグレー化する必要があると思いました。で、以下の画像処理ライブラリを試しました。canvasとか便利だなぁ。。。

ImageFilters.js API Demos
GitHub - arahaya/ImageFilters.js: A Javascript Image filter library for the HTML5 canvas tag.

2値化もしてみたのですが、誤認識が多くなったのでグレーのままにしました。

で、部品が揃ったので、あとは順次組み合わせていきました。とりあえず以下のような感じが試作の最終でした。先人のコードをつぎはぎしただけですが。。。動画をキャプチャして、その画像をTesseract.jsに渡して結果をもらっているだけです。

<!DOCTYPE html>
<html>
<head>
	<script src="imagefilters.js"></script>
	<script src='https://cdn.rawgit.com/naptha/tesseract.js/0.2.0/dist/tesseract.js'></script>
	<script type="text/javascript">
        let localVideo;
        let localStream;

        function shot() {
            var canvas = document.getElementById('mycanvas');
            var ctx = canvas.getContext('2d');
            ctx.drawImage(localVideo, 0, 0, 320, 240);
            var imageData = ctx.getImageData(0, 0, 320, 240);
//            var resized = ImageFilters.ResizeNearestNeighbor(imageData, img.width / 4, img.height / 4);
            var filtered = ImageFilters.GrayScale(imageData);
            ctx.putImageData(filtered, 0, 0);
            Tesseract.recognize(filtered).then(function(result){
                const a = document.querySelector("#test");
                a.innerHTML = result.text;
                console.log(result.text);
            });
        }

        // start local video
        window.onload = function() {
            localVideo = document.getElementById('local_video')
            navigator.mediaDevices.getUserMedia({video: true, audio: false})
            .then(function (stream) { // success
                localStream = stream;
                localVideo.src = window.URL.createObjectURL(localStream);
             }).catch(function (error) { // error
                console.error('mediaDevice.getUserMedia() error:', error);
                return;
            });
        }
    </script>
</head>

<body>
	<div id="test"></div>
	<button onclick="shot()">Shot</button>
	<br />
	<video id="local_video" autoplay style="width: 320px; height: 240px; border: 1px solid black;"></video>
	<canvas width="320" height="240" id="mycanvas"></canvas>
</body>

</html>

オールJSでこんなにできるなんて素晴らしい時代ですね。