2016년 8월 20일 토요일

Simple Android OCR 소스 분석 TessApi

앞에서 빌드했던것을 바탕으로 소스를 분석 해보도록 하겠습니다.

소스는 아래 링크에서 받을 수 있습니다.
https://github.com/GautamGupta/Simple-Android-OCR

한글 되게 패치한 소스를 기반으로 분석진행하겠습니다.
한글 관련 사항은 이전 글 확인하시기 바랍니다.

TessApi를 사용하는 코드는 아래 코드입니다.

TessBaseAPI baseApi = new TessBaseAPI();
baseApi.setDebug(true);
baseApi.init(DATA_PATH, lang);
baseApi.setImage(bitmap);

String recognizedText = baseApi.getUTF8Text();

baseApi.end();


TessBaseAPI jni로 되어있는 library들로 연결되어있습니다.
이 부분은 따로 추후에 분석 해보도록 하겠습니다.

BaseAPI는 init을 호출하고 setImage를 호출하면 getUTF8Text 함수로 부터 OCR로 변환된 글씨를 받을 수 있습니다.
위코드는 사진을 찍는 부분에 들어가야 할겁니다.
onPhotoTaken() 메소드 안에 해당 코드가 들어있습니다.

카메라 구동은 저당될 파일 경로를 정하고 MediaStore.ACTION_IMAGE_CAPTURE 인텐트를 보내면 됩니다.
protected void startCameraActivity() {
   File file = new File(_path);
   Uri outputFileUri = Uri.fromFile(file);

   final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
   intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);

   startActivityForResult(intent, 0);
}
사진이 찍히고 나면 다시 돌아오게 되는데 아래 함수로 돌아오게 됩니다.
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {

   Log.i(TAG, "resultCode: " + resultCode);

   if (resultCode == -1) {
      onPhotoTaken();
   } else {
      Log.v(TAG, "User cancelled");
   }
}

여기에서 resultCode == -1 조건을 넣었는데 다른 예제들은 RESULT_OK를 사용합니다.

RESULT_OK

Added in API level 1
int RESULT_OK
Standard activity result: operation succeeded.
Constant Value: -1 (0xffffffff)

사진을 찍기전에는 sd card에 있는 언어 학습 데이터를 내부영역으로 복사 하는 작업을 합니다.
assets에 있는 traindata를 sdcard영역으로 복사를 합니다.
제가 원본소스를 변형해서 dataCopy 메소드로 이름을 만들었습니다.
private void dataCopy(String one) {
   // lang.traineddata file with the app (in assets folder)
   // You can get them at:
   // http://code.google.com/p/tesseract-ocr/downloads/list
   // This area needs work and optimization
   if (!(new File(DATA_PATH + "tessdata/" + one + ".traineddata")).exists()) {
      try {

         AssetManager assetManager = getAssets();
         InputStream in = assetManager.open("tessdata/" + one + ".traineddata");
         //GZIPInputStream gin = new GZIPInputStream(in);
         OutputStream out = new FileOutputStream(DATA_PATH 
              + "tessdata/" + one + ".traineddata");

         // Transfer bytes from in to out
         byte[] buf = new byte[1024];
         int len;
         //while ((lenf = gin.read(buff)) > 0) {
         while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
         }
         in.close();
         //gin.close();         out.close();

         Log.v(TAG, "Copied " + one + " traineddata");
      } catch (IOException e) {
         Log.e(TAG, "Was unable to copy " + one + " traineddata " + e.toString());
      }
   }
}

호출해주는 쪽은 eng+kor 이렇게 붙어 있는 경우 분리해 주기위해 아래와 같이 표현하였습니다.
String lang_one[] = lang.split("\\+");
for(String one : lang_one) {
   dataCopy(one);
}

사진을 찍고 TessBaseAPI를 호출하기전에 이미지를 bitmap으로 가공을 해주어야 하는데요

onPhotoTaken 메소드 앞부분에서 진행합니다.
파일을 읽고 exif 정보를 보고 회전되어있다면 bitmap을 회전시켜서 bitmap ARGB8888 format을 만듭니다.
해당포맷은 alpha 채널을 포함한 rgb 32bit가 하나의 점을 이루게 되는 포맷입니다.
protected void onPhotoTaken() {
   _taken = true;

   BitmapFactory.Options options = new BitmapFactory.Options();
   options.inSampleSize = 4;

   Bitmap bitmap = BitmapFactory.decodeFile(_path, options);

   try {
      ExifInterface exif = new ExifInterface(_path);
      int exifOrientation = exif.getAttributeInt(
            ExifInterface.TAG_ORIENTATION,
            ExifInterface.ORIENTATION_NORMAL);

      Log.v(TAG, "Orient: " + exifOrientation);

      int rotate = 0;

      switch (exifOrientation) {
      case ExifInterface.ORIENTATION_ROTATE_90:
         rotate = 90;
         break;
      case ExifInterface.ORIENTATION_ROTATE_180:
         rotate = 180;
         break;
      case ExifInterface.ORIENTATION_ROTATE_270:
         rotate = 270;
         break;
      }

      Log.v(TAG, "Rotation: " + rotate);

      if (rotate != 0) {

         // Getting width & height of the given image.
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();

         // Setting pre rotate
         Matrix mtx = new Matrix();
         mtx.preRotate(rotate);

         // Rotating Bitmap
         bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
      }

      // Convert to ARGB_8888, required by tess
      bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

   } catch (IOException e) {
      Log.e(TAG, "Couldn't correct orientation: " + e.toString());
   }









댓글 없음:

댓글 쓰기