⌨️
スマホで撮影した写真をOCRで文字起こしし、音声データに変換して再生する方法
はじめに
SREホールディングス株式会社にて、ソフトウェアエンジニアをやっております、叶です。
入社から色々なAI技術に触れる機会がありました。
今回は、開発で携わったAI-OCR技術を用いた簡単なアプリを作ってみました。スマホのカメラで写真を撮って、写真に含まれるもテキストを文字起こして、音声データに変換して読み上げるというアプリです。
使用した技術
- フロント(React)
- react:Javascriptのエコシステムフレームワーク
- react-webcam: デバイスのカメラを操作し、撮影した画像データを取得するライブラリ
- バックエンド(python)
- flask: WEBアプリケーションライブラリ
- EasyOCR:画像から文字を抽出するライブラリ
- gTTs :文字を音声データに変換するライブラリ
フロント(React)
- 画面表示とAPI処理のソースコード
App.tsxのソースコード
App.tsx
import { useState } from "react";
import axios from "axios";
import Camera from "./Camera";
import AudioPlayer from "./AudioPlayer";
const dataURLtoBlob = (dataurl: string) => {
let arr = dataurl.split(",");
let mime = "image";
let test = arr[0].match(/:(.*?);/);
if (test !== null) {
mime = test[1];
}
let bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
};
const App = () => {
const [isCaptureEnable, setCaptureEnable] = useState<boolean>(false);
const [audioFile, setAudioFile] = useState<File | null>(null);
const capture = (imageSrc: string) => {
if (imageSrc) {
let params = new FormData();
params.append("image", dataURLtoBlob(imageSrc), "testImage.png");
let post_api = axios.create({
headers: {
"Content-Type": "multipart/form-data",
Accept: "multipart/form-data",
},
});
post_api
.post<File>("https://localhost:5000/api/img/ul", params, {
responseType: "blob",
})
.then(
(response) => response.status === 200 && setAudioFile(response.data)
)
.catch((error) => console.log(error));
}
};
return (
<>
<header>
<h1>カメラアプリ</h1>
</header>
{isCaptureEnable || (
<button onClick={() => setCaptureEnable(true)}>開始</button>
)}
{isCaptureEnable && <Camera sendCapture={capture} />}
{audioFile && <AudioPlayer mp3File={audioFile} />}
</>
);
};
export default App;
- ブラウザでスマホのカメラにアクセスし、写真を取得する
カメラのコンポーネントのソースコード
Camera.tsx
import { useRef, useState, useCallback } from "react";
import Webcam from "react-webcam";
const videoConstraints = {
width: 720,
height: 360,
facingMode: "environment",
};
const Camera = (props: { sendCapture: (imageSrc: string) => void }) => {
const webcamRef = useRef<Webcam>(null);
const [url, setUrl] = useState<string | null>(null);
const capture = useCallback(() => {
const imageSrc = webcamRef.current?.getScreenshot();
if (imageSrc) {
props.sendCapture(imageSrc);
setUrl(imageSrc);
}
}, [webcamRef]);
return (
<>
<div>
{/* Webカメラの関連設定 */}
<Webcam audio={false} width={540} height={360} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={videoConstraints} />
</div>
{/* カメラシャットダウン */}
<button onClick={capture}>キャプチャ</button>
{url && (
<>
<div>
<button onClick={() => setUrl(null)}>削除</button>
</div>
{/* 撮った写真のプレビュー */}
<div><img src={url} alt="Screenshot" /></div>
</>
)}
</>
);
};
export default Camera;
- 受け取った音声データを再生する
オーディオプレーコンポーネントのソースコード
AudioPlayer.tsx
import React, { useState } from "react";
const AudioPlayer = (props: { mp3File: File }) => {
const mytrack: HTMLAudioElement = document.getElementById(
"mytrack"
) as HTMLAudioElement;
const [audioSrc, setAudioSrc] = useState(
URL.createObjectURL(new Blob([props.mp3File], { type: "audio/mp3" }))
);
return (
<div>
<audio id="mytrack" controls>
<source src={audioSrc} />
</audio>
</div>
);
};
export default AudioPlayer;
バックエンド(Python)
- 画像ファイルを受け取る
- EasyOCRで文字起こしを行う
- gTTsで音声データに変換する
- MP3ファイルを送信する
バックエンドのソースコード
app.py
@app.route("/api/img/ul", methods=["POST"])
def file_upload():
# 受け取ったファイルを一旦保存
file = request.files['image']
print(file.filename)
file.save("test.png")
# EasyOCRで文字起こし
reader = easyocr.Reader(['ja','en']) # this needs to run only once to load the model into memory
results = reader.readtext('test.png', detail = 0)
print(results)
message = "".join(results)
# 文字を音声データに変換
tts1 = gTTS(text=message, lang='ja')
tts1.save("test.mp3")
# ファイルをレスポンスに設定
return send_file("../../test.mp3")
動作確認
サンプル写真
生成した音声データ
リポジトリ
まとめ
サンプル写真くらい内容が簡単だと、追加の画像処理なしで文字起こしができるようです。
今回は新しく学んだ内容を活用して、自分が欲しいアプリを作れたのでなかなか面白かったです。
AIが進んでいる世の中、将来に「AI & 人」でAIが人の生活に馴染んでいきそうです。
Discussion