1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ReactNativeでOCR実装

Last updated at Posted at 2023-08-02

はじめに

業務で扱ったOCRを実装してみた。
題材は千と千尋の神隠しの湯婆婆が千尋の名前を取るシーン

以下記事がおもしろくてやってみたくなった
Javaで湯婆婆を実装してみる

「入力は手書き」 そして 「入力内容をCloud Vision APIで読み取らせて例の処理を実行」 することにした

コード

import React, { useRef, useState } from 'react';
import {
  StatusBar,
  SafeAreaView,
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
} from 'react-native';
import RNDrawOnScreen from 'react-native-draw-on-screen';
import ViewShot, { captureRef } from 'react-native-view-shot';

// GCPで取得したAPIキー
const GCP_API_KEY = '';

const Yubaba = () => {
  const RNDraw = useRef(null);
  const RNViewShot = useRef(null);
  const [name, setName] = useState('');
  const { length } = name;
  const newName = name.substr(Math.floor(Math.random() * length), 1);

  // Cloud Vision API call
  const callCloudVisionAPI = async (data) => {
    const body = JSON.stringify({
      requests: [
        {
          features: [
            {
              // テキスト認識
              type: 'TEXT_DETECTION',
              // 取得したい結果数
              maxResults: 1,
            },
          ],
          image: {
            // base64エンコードした画像をそのままセット
            content: data,
          },
        },
      ],
    });

    const response = await fetch(
      `https://vision.googleapis.com/v1/images:annotate?key=${GCP_API_KEY}`,
      {
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        method: 'POST',
        body: body,
      }
    );

    const resJson = await response.json();
    const description = resJson.responses[0]?.textAnnotations[0]?.description || '';

    if (description) {
      setName(description.replace(/\r?\n/g, ''));
    }
  };

  // クリアボタン押下イベント
  const onPressClear = () => {
    RNDraw?.current?.clear();
    setName('');
  };

  // OKボタン押下イベント
  const onPressOk = () => {
    captureRef(RNViewShot, { result: 'base64' }).then(callCloudVisionAPI);
  };

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView style={styles.container}>
        <View style={styles.contentWrap}>
          <Text>{`契約書だよ。そこに名前を書きな。`}</Text>
        </View>
        <ViewShot style={styles.canves} ref={RNViewShot}>
          <RNDrawOnScreen penColor={'black'} strokeWidth={10} ref={RNDraw} />
        </ViewShot>
        <View style={styles.buttonWrap}>
          <TouchableOpacity
            style={[styles.button, { borderColor: '#007AFF' }]}
            onPress={onPressOk}
          >
            <Text style={[styles.buttonText, { color: '#007AFF' }]}>{`OK`}</Text>
          </TouchableOpacity>
          <TouchableOpacity
            style={[styles.button, { borderColor: '#FF7A00' }]}
            onPress={onPressClear}
          >
            <Text style={[styles.buttonText, { color: '#FF7A00' }]}>{`クリア`}</Text>
          </TouchableOpacity>
        </View>
        {!!name && (
          <View style={styles.contentWrap}>
            <Text>{`フン。${name}というのかい。贅沢な名だねぇ。`}</Text>
            <Text>{`今からお前の名前は${newName}だ。いいかい、${newName}だよ。\n分かったら返事をするんだ、${newName}!!`}</Text>
          </View>
        )}
      </SafeAreaView>
    </>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  contentWrap: {
    width: '100%',
    margin: '4%',
    marginTop: '8%',
  },
  canves: {
    height: '30%',
    margin: '2%',
    borderWidth: 2,
    borderColor: '#ccc',
    backgroundColor: '#FFF',
  },
  buttonWrap: {
    margin: '2%',
    width: '100%',
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    borderWidth: 1,
    margin: '2%',
    padding: 10,
    borderRadius: 4,
  },
  buttonText: {
    fontSize: 14,
  },
});

手書きUI

手書きのUIには、react-native-draw-on-screenを使用しています。文字認識を容易にするため、文字色は黒で線の太さも固定しています。さらに、手書きした内容を一時的に画像として保存したいため、react-native-view-shotを使用して画像化したい要素をラップしています。
 

import RNDrawOnScreen from 'react-native-draw-on-screen';
import ViewShot, {captureRef} from 'react-native-view-shot';

// ...略

<ViewShot style={styles.canves} ref={RNViewShot}>
  <RNDrawOnScreen penColor={'black'} strokeWidth={10} ref={RNDraw} />
</ViewShot>

キャプチャ

手書きが完了したら、react-native-view-shotを使用してキャプチャを撮影します。CloudVisionAPIには、base64形式でデータを送信するためにオプションを指定しています。オプションを指定しなかった場合は、キャプチャが端末ストレージ内に保存され、そのパスが"data"に格納されます。

★プロジェクトで学んだことが生きた。。。。

// react-native-view-shotで描画部分のキャプチャを取得
 captureRef(RNViewShot, {result: 'base64'}).then(async (data)

CloudVisionAPIへ送信

Cloud Vision(doc)
1000リクエスト/月までは無料。

 // リクエストボディ作成
const body = JSON.stringify({
  requests: [
    {
      features: [
        {
          // テキスト認識
          type: 'TEXT_DETECTION',
          // 取得したい結果数
          maxResults: 1,
        },
      ],
      image: {
        // base64エンコードした画像をそのままセット
        content: data,
      },
    },
  ],
});

// CloudVisionAPI実行
const response = await fetch(
  'https://vision.googleapis.com/v1/images:annotate?key=' + GCP_API_KEY,
  {
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    method: 'POST',
    body: body,
  },
);

実行結果

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3433353432392f65656662666264302d653762382d626437632d666361322d3938316330393561626534642e676966.gif

まとめ。ざっとコードの要点

  1. import文: 必要なReact Nativeコンポーネントやライブラリをインポートしています。

  2. GCP_API_KEY: Google Cloud Vision APIにアクセスするためのAPIキーが定義されています。APIキーはセキュリティのため、実際の値が示されていないことに注意してください。

  3. Yubabaコンポーネント: アプリケーションのメインコンポーネントが定義されています。

  4. useRefフック: RNDrawとRNViewShotの2つのリファレンスが作成されています。これらは、描画部分を手書きするためのコンポーネント(RNDrawOnScreen)と、描画部分をキャプチャするためのコンポーネント(ViewShot)への参照を保持します。

  5. useStateフック: nameという状態変数が定義されています。手書きの名前が入力された後、ここに名前がセットされて表示されます。

  6. onPressClear関数: クリアボタンが押されたときに、手書きの名前をクリアしてnameを空にします。

  7. onPressOk関数: OKボタンが押されたときに、手書きの名前をテキストとして認識し、nameにセットします。

  8. captureRef関数: ViewShotを使用して描画部分をキャプチャします。キャプチャした画像は、Google Cloud Vision APIに送信されます。

  9. fetchを使用して、Cloud Vision APIに対してPOSTリクエストを送信し、手書きの名前をテキストとして認識します。

  10. stylesオブジェクト: アプリケーションのスタイルが定義されています。

  11. return文: アプリケーションのUIがJSXで記述されています。View、Text、TouchableOpacityなどのコンポーネントが組み合わさっています。

  12. ViewShotの中にRNDrawOnScreenコンポーネントがあり、ユーザーが手書き入力を行えるようになっています。

  13. 「OK」ボタンと「クリア」ボタンがあり、それぞれonPressOkonPressClear関数が紐づいています。

  14. nameが空でなければ、手書きされた名前に対して湯婆婆のセリフが表示されます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?