質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Tesseract

Tesseractは、Googleが提供しているオープンソースのOCRエンジンです。機械学習があり60以上の言語に対応でき、日本語の文字認識も可能です。さらに精度を上げることもできます。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

1回答

649閲覧

Canvasでフリーハンドで描いた文字をtess-twoで文字認識

MasayaUemura

総合スコア11

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Tesseract

Tesseractは、Googleが提供しているオープンソースのOCRエンジンです。機械学習があり60以上の言語に対応でき、日本語の文字認識も可能です。さらに精度を上げることもできます。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

1クリップ

投稿2017/10/06 15:11

編集2017/10/07 06:52

###前提・実現したいこと
javaを扱い始めて2週間ほどの初心者です。
アプリ内でフリーハンドでかいた文字をtess-twoで認識したいのですが、うまく動きません。

###発生している問題・エラーメッセージ

tess-twoで認識をおこなった結果が空欄になってしまいます。 なお、コンパイルでエラーはでません。 UIスレッドでの処理が重すぎてフレームが60くらいスキップされますが、処理は行われてる模様です。

###該当のソースコード

メインクラス

java

1 2package com.example.***.*** 3 4import android.content.res.AssetManager; 5import android.graphics.Bitmap; 6import android.os.Bundle; 7import android.support.v7.app.AppCompatActivity; 8import android.util.Log; 9import android.view.View; 10import android.widget.Button; 11import android.widget.ImageView; 12import android.widget.TextView; 13 14import com.googlecode.tesseract.android.TessBaseAPI; 15 16 17import java.io.File; 18import java.io.FileNotFoundException; 19import java.io.FileOutputStream; 20import java.io.IOException; 21import java.io.InputStream; 22import java.io.OutputStream; 23 24 25public class MainActivity extends AppCompatActivity { 26 27 String datapath = ""; 28 29 @Override 30 protected void onCreate(Bundle savedInstanceState) { 31 super.onCreate(savedInstanceState); 32 setContentView(R.layout.activity_main); 33 34 //描画とクリアボタン 35 Button button = (Button) findViewById(R.id.button1); 36 button.setOnClickListener(new View.OnClickListener() { 37 @Override 38 public void onClick(View view) { 39 PaintView paintView = (PaintView) findViewById(R.id.drew); 40 paintView.clear(); 41 TextView textView = (TextView)findViewById(R.id.textView); 42 textView.setText(""); 43 } 44 }); 45 46 //認識ボタン 47 Button button2 = (Button) findViewById(R.id.button2); 48 button2.setOnClickListener(new View.OnClickListener() { 49 @Override 50 public void onClick(View view) { 51 52 View drewview = findViewById(R.id.drew); //描いた絵をdrewviewとして読み込む 53 drewview.setDrawingCacheEnabled(true); // キャッシュを取得する設定にする 54 drewview.destroyDrawingCache(); // 既存のキャッシュをクリアする 55 Bitmap bmp = drewview.getDrawingCache(); //drewviewをbitmap bmpに変換 56 bmp = bmp.copy(Bitmap.Config.ARGB_8888, true);//ARGB_8888に合わせる 57 58 59 final String language = "kor"; //tess-two言語の選択 60 datapath = getFilesDir() + "/tesseract/"; //directoryの指定 61 checkFile(new File(datapath + "tessdata/")); //学習データの有無チェック 62 63 TessBaseAPI tessOCRAPI = new TessBaseAPI(); //Init OCR 64 tessOCRAPI.init(datapath, language); 65 66 tessOCRAPI.setImage(bmp); //bmp型にした描いた絵をセットする 67 68 String APIkekka; 69 APIkekka = tessOCRAPI.getUTF8Text(); //OCRの結果をString型のAPIkekkaに 70 tessOCRAPI.end(); // Close OCR API 71 72 TextView kekka = (TextView) findViewById(R.id.textView); 73 kekka.setText(APIkekka+ "が結果です"); //APIkekkaをtextviewに表示 74 Log.d(APIkekka, "結果表示"); //Logに結果表示 75 76 ImageView madebmp = (ImageView)findViewById(R.id.imageView); //bmpが正常に取得できているか画面に出力 77 madebmp.setImageBitmap(bmp); 78 } 79 }); 80 81 82 } 83 84 85 86 private void checkFile(File dir) { 87 if (!dir.exists()&& dir.mkdirs()){ 88 copyFiles(); 89 } 90 if(dir.exists()) { 91 String datafilepath = datapath+ "/tessdata/kor.traineddata"; 92 File datafile = new File(datafilepath); 93 94 if (!datafile.exists()) { 95 copyFiles(); 96 } 97 } 98 } 99 100 private void copyFiles() { 101 try { 102 String filepath = datapath + "/tessdata/kor.traineddata"; 103 AssetManager assetManager = getAssets(); 104 105 InputStream instream = assetManager.open("tessdata/kor.traineddata"); 106 OutputStream outstream = new FileOutputStream(filepath); 107 108 byte[] buffer = new byte[1024]; 109 int read; 110 while ((read = instream.read(buffer)) != -1) { 111 outstream.write(buffer, 0, read); 112 } 113 114 115 outstream.flush(); 116 outstream.close(); 117 instream.close(); 118 119 File file = new File(filepath); 120 if (!file.exists()) { 121 throw new FileNotFoundException(); 122 } 123 } catch (FileNotFoundException e) { 124 e.printStackTrace(); 125 } catch (IOException e) { 126 e.printStackTrace(); 127 } 128 } 129} 130 131

PaintView.java

java

1 2public class PaintView extends View { 3 4 private Paint paint; 5 private Path path; 6 7 public PaintView(Context context){ 8 this(context,null); 9 } 10 11 public PaintView(Context context, AttributeSet attrs) { 12 super(context, attrs); 13 path = new Path(); 14 paint = new Paint(); 15 paint.setColor(0xFF000000); 16 paint.setStyle(Paint.Style.STROKE); 17 paint.setStrokeJoin(Paint.Join.ROUND); 18 paint.setStrokeCap(Paint.Cap.ROUND); 19 paint.setStrokeWidth(10); 20 21 } 22 @Override 23 protected void onDraw(Canvas canvas) { 24 canvas.drawPath(path, paint); 25 } 26 @Override 27 public boolean onTouchEvent(MotionEvent event) { 28 float x = event.getX(); 29 float y = event.getY(); 30 31 switch (event.getAction()) { 32 case MotionEvent.ACTION_DOWN: 33 path.moveTo(x, y); 34 invalidate(); 35 break; 36 case MotionEvent.ACTION_MOVE: 37 path.lineTo(x, y); 38 invalidate(); 39 break; 40 case MotionEvent.ACTION_UP: 41 path.lineTo(x, y); 42 invalidate(); 43 break; 44 } 45 return true; 46 } 47 public void clear(){ 48 path.reset(); 49 invalidate(); 50 } 51} 52

Activity_main.xml

xml

1<?xml version="1.0" encoding="utf-8"?> 2<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context="com.example.***.***.MainActivity"> 8 9 <view 10 class="com.example.***.***.PaintView.java 11 android:id="@+id/drew" 12 app:layout_constraintBottom_toBottomOf="parent" 13 app:layout_constraintRight_toRightOf="parent" 14 app:layout_constraintLeft_toLeftOf="parent" 15 app:layout_constraintTop_toTopOf="parent" 16 android:layout_width="203dp" 17 android:layout_height="204dp" 18 app:layout_constraintHorizontal_bias="0.029" 19 app:layout_constraintVertical_bias="0.033"/> 20 <!--android:background="@drawable/flame_style"--> 21 22 <Button 23 android:id="@+id/button1" 24 app:layout_constraintBottom_toBottomOf="parent" 25 app:layout_constraintRight_toRightOf="parent" 26 app:layout_constraintLeft_toLeftOf="parent" 27 app:layout_constraintTop_toTopOf="parent" 28 android:layout_width="wrap_content" 29 android:layout_height="wrap_content" 30 android:text="clear" 31 app:layout_constraintHorizontal_bias="0.179" 32 app:layout_constraintVertical_bias="0.74" /> 33 34 <Button 35 android:id="@+id/button2" 36 app:layout_constraintBottom_toBottomOf="parent" 37 app:layout_constraintRight_toRightOf="parent" 38 app:layout_constraintLeft_toLeftOf="parent" 39 app:layout_constraintTop_toTopOf="parent" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:text="認識" 43 app:layout_constraintVertical_bias="0.74" 44 app:layout_constraintHorizontal_bias="0.81" /> 45 46 <TextView 47 android:id="@+id/textView" 48 app:layout_constraintBottom_toBottomOf="parent" 49 app:layout_constraintTop_toTopOf="parent" 50 app:layout_constraintLeft_toLeftOf="parent" 51 app:layout_constraintRight_toRightOf="parent" 52 android:layout_width="300dp" 53 android:layout_height="wrap_content" 54 android:text="" 55 android:textSize="40sp" 56 android:gravity="center_horizontal" 57 android:background="@drawable/flame_style" 58 tools:layout_editor_absoluteX="55dp" 59 app:layout_constraintVertical_bias="0.91" /> 60 61 <ImageView 62 android:id="@+id/imageView" 63 android:layout_width="202dp" 64 android:layout_height="185dp" 65 app:layout_constraintBottom_toBottomOf="parent" 66 app:layout_constraintRight_toRightOf="parent" 67 app:layout_constraintLeft_toLeftOf="parent" 68 app:layout_constraintTop_toTopOf="parent" 69 app:srcCompat="@drawable/flame_style" 70 app:layout_constraintHorizontal_bias="1.0" 71 app:layout_constraintVertical_bias="0.519" /> 72</android.support.constraint.ConstraintLayout> 73

###試したこと
Viewにフリーハンドで書いた文字をView全体ごとキャッシュを利用してキャプチャしてそれをBitmap型に格納し、tess-twoに引数として渡しているので、どっかでミスってBitmap型に格納した画像が真っ白になってるのかな?と思い、格納している画像も認識結果と一緒に表示するようにしたところ、画像はしっかりかいたものがそのままでてきましたのでキャッシュに失敗してるということはなさそうです。

適当な画像をdrawableにいれてその画像をtess-twoで認識させた場合はうまく結果が返ってきます。

###補足情報(言語/FW/ツール等のバージョンなど)
MacOS X 10.11.6
Android studio ver 2.3.3
最小JDK API23:Android6.0
コンパイル ツール ver26.0.2
実機はAndroid6.0です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

私もtesseract/tess-two をAndroidで使ってみたいと考えていましたので、ご質問の件、調べました。PaintView.javaの onDrawで、PaintViewの背景色を単色で塗りつぶすことで文字認識ができるようになりました。

Java

1public PaintView(Context context, AttributeSet attrs) { 2 super(context, attrs); 3 this.setBackgroundColor(Color.WHITE); 4 //this.setBackgroundColor(Color.LTGRAY); 5 path = new Path(); 6 paint = new Paint(); 7 paint.setColor(0xFF000000); 8 paint.setStyle(Paint.Style.STROKE); 9 paint.setStrokeJoin(Paint.Join.ROUND); 10 paint.setStrokeCap(Paint.Cap.ROUND); 11 paint.setStrokeWidth(10); 12 }

原因としては、以下のコードでViewのビットマップをアルファチャネル付きで
取得していた為に、手書きのストロークの背景が透過色になってしまい、
tessOCRAPI.setImage(bmp)で認識できなかったようです。

Java

1 View drewview = findViewById(R.id.drew); //描いた絵をdrewviewとして読み込む 2 drewview.setDrawingCacheEnabled(true); // キャッシュを取得する設定にする 3 drewview.destroyDrawingCache(); // 既存のキャッシュをクリアする 4 Bitmap bmp = drewview.getDrawingCache(); //drewviewをbitmap bmpに変換 5 bmp = bmp.copy(Bitmap.Config.ARGB_8888, true);//ARGB_8888に合わせる

MasayaUemura様の提示されたコードをもとに作成したテストプロで認識させた結果が以下になります。
手書き用のキャンバス部分の背景色は分かり易くする為にthis.setBackgroundColor(Color.LTGRAY);
で灰色としています。

イメージ説明
手書きの"ABC 123"が文字認識され、意図したものとは違うものの、
結果が出ているのが分かります。

また、traineddataはkor(韓国語版)では無く、eng(英語版)にしているのが
異なります。korに変えても認識できると思いますが、できるかできないかは
精度の問題だと思いましたので私の方では試していません。

###"kor"での確認と、適切な修正について追記
"kor"の韓国語traineddataでハングル文字も認識できることを確認しました。
また、PaintView#onDraw内でsetBackgroundColorによって背景色を
セットする修正をしましたが、そうではなく、レイアウトxmlで背景色をセットする方が
適切かもしれません。

XML

1<!--抜粋--> 2 class="examples.products.test25.PaintView" 3 android:id="@+id/drew" 4 android:background="#ffffff"

投稿2017/10/12 13:05

編集2017/10/13 03:13
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MasayaUemura

2017/11/16 04:41

質問後にいろいろ試していたところ、回答でおっしゃっている通り背景色が問題であることがわかりました。 xmlで直接背景色を設定したところうまく認識できました。ありがとうございました。
dodox86

2017/11/16 05:01 編集

コメントありがとうございます。その後が気になっていましたが、動くようになって良かったです。私も勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問