2018年8月28日火曜日

画像から文字を認識してさらに翻訳!

youtubeや洋ゲー、漫画でちょっと出てくる外国語をぱっと翻訳できれば便利だと思いませんか?
気になった文を手打ちで写すのは面倒です。
これをgoogleのを画像認識を使って翻訳できるようにします。
若干手作業も入るので半自動って感じです。
APIと既存のソフトの組み合わせでこんなに便利になります!

準備として
①今回、WinShotというフリーのスクリーンショットを活用します。
保存先のフォルダの監視できればいいので、他のスクリーンショットソフトでもいいですがWinShotは優秀なのでお勧め。 矩形範囲指定かつPNGが保存できるようにしてください。
前回のノリでGoogle Play Consoleで「Google Cloud Translation API」を有効にします。
③さらに「Cloud Vision API」も有効します。

※②と③のサービスは有料です。洋ゲーで使いまくらなければ無料分で納まるかと思います。料金体系を理解して使用してください。便利なサービスなのでお金を払うのに値すると思う。
毎度のことですがAPIキーが他人の手にわたらないように!



以下、今回のコードの仕様
・「http://localhost/ocr_trs.php」をブラウザに入力して使用を開始します。
・ブラウザでコードのPHPを起動して、スクリーンショットを取ると自動で翻訳します。
・スクリーンショットで画像が保存されるたびにその画像を翻訳します。
・WinShotはショートカットキーで矩形範囲指定が行えるようにする。
そして読ませたい文字の部分を少し広めに囲って拡張子PNGで保存します。
コードはPNG対応になっています。文字がぼやっとするのが嫌なのでPNGにしています。
・認識した原文と翻訳後を表示する。
(画像認識結果がいまいちな場合は編集できるように原文をコピペできるように表示する)
・言語の指定をする必要が無いように言語検出を行う。 (その分、料金が発生することに注意)
・検出した言語→日本語の翻訳を行います。(日本語⇒日本語はエラーになってしまう)
・読みやすいようにピリオド以外の改行を無くした後、ピリオドで改行を行う


C:\xampp\htdocs直下に以下の2つのコードを保存してください。
1つ目
このコードはスクリーンショットソフトがPNGファイルを保存するフォルダを監視し続けます。
そして新規ファイルが保存されたらそのファイル名を返します。
どうもPHPではphpファイル直下のファイルしか画像表示できないようなので、「test.PNG」というファイル名を直下にコピーしています。
フォルダパスは自分の環境に合わせてください。

filechk.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
 set_time_limit(60*60);//タイムアウト時間を60分に変更
 
 //現在のフォルダ内のファイルを配列に入れる
 $basef = glob("C:\\Users\\main\\Documents\\tool\\WinShot\\Shot\\*.PNG");
 
 $flag = 1;
 while($flag)
 {
  //1 秒待つ
  usleep(1*1000000);
  $newf glob("C:\\Users\\main\\Documents\\tool\\WinShot\\Shot\\*.PNG");
 
  //ファイルの差分を取得
  $difff = array_diff($newf,$basef);
  foreach($difff as $file)
  {
      if(is_file($file))
      {
    usleep(0.1*1000000);//必要?
          $flag = 0;
          copy ($file, "C:\\xampp\\htdocs\\test.PNG");//表示用
          break;
      }
  }
 // $basef  = $newf;
 }
 echo $file;
?>



注釈として、
このコードは2つ目のコードから呼ばれます。
5行目で最初のフォルダの状況を保存し、12行目の最新のフォルダの状況を取得。
15行目で差分をとり、その差分があれば28行目でそのファイル名を返します。
※固定の名前でコピーしているのだからファイル名を返す必要はないのかも。。。
11行目で1秒毎に監視しています。頻度を早くするとレスポンスが少し良くなると思います。
20行目コピーを行うときに待ちなしで行うと失敗することがあるのでちょっとだけまっています
22行目表示用にコピーを行います。


2つ目
①は自分のAPIキー。
新規に画像が保存されたらそのファイルを画像認識のAPIに投げます。
次に画像認識結果のテキスト部分を翻訳のAPIに投げるという単純な構造です。

ocr_trs.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<!DOCTYPE html>
<html>
    <head>
        <title>翻訳</title>
        <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
 
    </head>
    <body>
        <style>
          t0 {color: blue; font-size:20px;}
          t1 {color: red; font-size:20px;}
         img.gazo{
               width: auto;
               height: auto;
               border:solid 5px #0000FF;
               clear:both;
               }
        </style>
     </body>
 
 
<?php
// APIキー
define("APIKEY","①");
set_time_limit(60*60);//タイムアウト時間を60分に変更
 
//翻訳関数
function trns_us($text)
{
    //言語の検出
    $url = "https://www.googleapis.com/language/translate/v2/detect?key=" . APIKEY . "&q=".urlencode($text);
    $resjson = file_get_contents($url);
    $resjson = mb_convert_encoding($resjson, 'UTF-8', 'auto');
    $resarray = json_decode($resjson);
    $lang = $resarray->data->detections[0][0]->language;
//print_r($result);
 
     
     
    $url = "https://www.googleapis.com/language/translate/v2?key=" . APIKEY . "&source=".$lang."&target=ja&q=".urlencode($text);
    $resjson = file_get_contents($url);
    $resjson = mb_convert_encoding($resjson, 'UTF-8', 'auto');
    $resarray = json_decode($resjson);
    $result = $resarray->data->translations[0]->translatedText;
//    echo $result;
    return $result;
}
 
 
$file  = isset($_COOKIE["file"])? $_COOKIE["file"] : "";
if ( $file == "" ) {
    echo "画像を取得してください".PHP_EOL;
}
else
{
    $file = $_COOKIE["file"];
    echo     $file .PHP_EOL;
    echo "<img src=test.PNG  class=gazo>";
 
    //ブラウザに少しずつ表示するため必要
    ob_flush();
    flush();
         
    // Feature Type
    $feature = 'TEXT_DETECTION';
    // パラメータ設定
    $param = array("requests" => array());
    $item["image"] = array("content" => base64_encode(file_get_contents($file)));
    $item["features"] = array(array("type" => $feature));
    $param["requests"][] = $item;
 
    // リクエスト用のJSONを作成
    $json = json_encode($param);
    // リクエストを実行
    $curl = curl_init() ;
    curl_setopt($curl, CURLOPT_URL, "https://vision.googleapis.com/v1/images:annotate?key=" . APIKEY);
    curl_setopt($curl, CURLOPT_HEADER, true);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_TIMEOUT, 30);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $json);
    $res1 = curl_exec($curl);
    $res2 = curl_getinfo($curl);
    curl_close($curl);
 
    echo "<br>";
    // 取得したデータ
    $json = substr($res1, $res2["header_size"]);
    $data = json_decode($json, true);
    $str = $data["responses"][0]["textAnnotations"][0]["description"];
    $str2 = str_replace(array("\r\n","\n","\r"), " ", $str);//改行をなくす
    echo "<t0>" .  str_replace(". ", ".<br>", $str2) . "</t0>";
    echo "<br>";
    $str3 = trns_us($str2);//翻訳
 
    $str3 = str_replace("。", "。<br>", $str3);//表示は改行ありで。
    echo "<t1>" . $str3  . "</t1>";
    echo "<br>";
 
 
}
 
//http://localhost/ocr_trs.php
?>
 
<script type="text/javascript">
    var fname = "";
    $.ajax({
        url : "filechk.php",
        type : "POST",
        data : {    post_data_1:1,
                    }
    }).done(function(data,text) {
        console.log("ajax通信に成功しました");
        fname = data;
//        console.log(fname);
        document.cookie = 'file='+fname;
        location.reload(true);
    }).fail(function(xhr, textStatus, errorThrown) {
        console.log("ajax通信に失敗しました");
        location.reload(true);
    });
  </script>
</html>




注釈として
24行目、①の部分に自身のAPIキーを入力します。
25行目、PHPで長時間待つために必要
31行目から35行目。言語の検出を行わない場合は$langをその言語に入力してこれらをコメントアウトしてください。
57行目 ファイル名を表示してますが邪魔ならコメントアウト
65行目 文字認識を指定しています。
68行目 画像データをbase64という文字列に変換しています。
93行目 改行を一度なくしたあと、94行目でピリオドを改行に変換しています。
98行目 翻訳結果のピリオドを「。」に変換しています。
110行目から javascriptからajax通信を使いphpから新規のスクリーンショットのファイル名を取得しています。


////////////////////////////////////////////////////////////////////////////////////
以下はいくつかの使用例です。
「第3のギデオン」という漫画のビッグ・モータの墓の文言です。

文字が石碑風になっているので認識がいまいちな。
原文(青字)をコピペして少し修正しグーグル翻訳を書けます。(フランス革命の話なのでフランス語で)


これで伝えたいことがだいたいわかると思います。


youtubeのゲーム実況で出てきた英文です。

まぁだいたいの意味がわかればいいでしょう。飾った文字じゃないのでちゃんと認識してます。 ※ファイル名表示邪魔かも。

タイ語です。
ピリオドがないので区切りがいまいちかも。
話の流れと合わせて、なんとか予想できるのでまぁ理解の助けになります。

//////////////////////////////////////////////////////////////////////////////////////////
画像認識はgoogle driveからもできるらしいけど、こっちの方が10秒もかからないしスムーズにできると思います。
画像で提示されたシリアルコードを手で写すのがメンドクサイときのも画像認識は使えます。

0 件のコメント:

コメントを投稿