안드로이드에서 한글과 영어인식하여 텍스트로 옮기는 샘플프로젝트를 만들어보겠습니다.
우선 OCR 앱을 만들기 위해서는 준비사항이 몇가지 있습니다.
1. build.gradle 에 tess-two 추가
2. 언어 데이터 파일(traineddata) 추가
3. OCR 인식을 위한 카메라 권한 및 저장소 권한 추가
tess-two 추가
// Tess-Two OCR
implementation 'com.rmtheis:tess-two:9.0.0'
build.gradle 에 추가시켜줍니다.
최신 버전은 아래 github에서 확인 하실 수 있습니다.
https://github.com/rmtheis/tess-two/releases
Language Data 추가
인식할 언어 데이터도 추가해줍니다.
영어와 한글을 인식해서 텍스트로 옮기기 위해 두가지 언어 데이터를 추가해줍니다.
언어 데이터는 아래 github에서 다운받을 수 있습니다.
https://github.com/tesseract-ocr/tessdata
assets 폴더가 없으신 분들은 [우클릭] -> [New] -> [Forder] -> [Asset Folder]를 만드시면됩니다.
Permission 추가
카메라로 찍은 사진을 내부 저장소에 저장후 사진을 가져와 텍스트를 인식해보겠습니다.
<uses-permission android:name="android.permission.CAMERA"></uses-permission> <!--카메라 권한-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission> <!--저장소 읽기 권한-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <!--저장소 쓰기 권한-->
public void PermissionCheck() {
/**
* 6.0 마시멜로우 이상일 경우에는 권한 체크후 권한을 요청한다.
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED &&
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED &&
checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
// 권한 없음
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
ConstantDefine.PERMISSION_CODE);
} else {
// 권한 있음
}
}
}
카메라와 저장소 권한을 요청합니다.
Language Data Path 설정
public void Tesseract() {
//언어파일 경로
mDataPath = getFilesDir() + "/tesseract/";
//트레이닝데이터가 카피되어 있는지 체크
String lang = "";
for (String Language : mLanguageList) {
checkFile(new File(mDataPath + "tessdata/"), Language);
lang += Language + "+";
}
m_Tess = new TessBaseAPI();
m_Tess.init(mDataPath, lang);
}
Tesstwo API와 언어파일위치를 설정해줍니다.
여기서 한글과 영어 모두 인식하기위해 lang 값에 "kor+eng" 이런식으로 데이터를 전달해줍니다.
영어만 인식하기위해서는 eng만 넣으면 되겠죠?
//check file on the device
private void checkFile(File dir, String Language) {
//디렉토리가 없으면 디렉토리를 만들고 그후에 파일을 카피
if (!dir.exists() && dir.mkdirs()) {
copyFiles(Language);
}
//디렉토리가 있지만 파일이 없으면 파일카피 진행
if (dir.exists()) {
String datafilepath = mDataPath + "tessdata/" + Language + ".traineddata";
File datafile = new File(datafilepath);
if (!datafile.exists()) {
copyFiles(Language);
}
}
}
//copy file to device
private void copyFiles(String Language) {
try {
String filepath = mDataPath + "/tessdata/" + Language + ".traineddata";
AssetManager assetManager = getAssets();
InputStream instream = assetManager.open("tessdata/"+Language+".traineddata");
OutputStream outstream = new FileOutputStream(filepath);
byte[] buffer = new byte[1024];
int read;
while ((read = instream.read(buffer)) != -1) {
outstream.write(buffer, 0, read);
}
outstream.flush();
outstream.close();
instream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
네 이제 Tesstwo 를 사용하여 OCR 앱을 만들 준비는 끝났습니다.
그럼 이제 사진을 찍어 문자를 인식해봐야 겠죠 ?
버튼을 눌렀을때 카메라 화면으로 넘어가고 넘어간 사진을 찍어 ActivityResult에서 받아 처리하도록 해보겠습니다.
Camera 실행
/**
* 기본카메라앱을 실행 시킨다.
*/
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// 사진파일을 생성한다.
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// 사진파일이 정상적으로 생성되었을때
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
this.getApplicationContext().getPackageName()+".fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, ConstantDefine.ACT_TAKE_PIC);
}
}
}
버튼을 클릭했을때 기본 카메라앱을 실행합니다.
onActivityResult 내부에서 ACT_TAKE_PIC로 찍은 사진결과를 받습니다.
case ConstantDefine.ACT_TAKE_PIC:
//카메라로 찍은 사진을 받는다.
if ((resultCode == RESULT_OK) ) {
try {
m_start = System.currentTimeMillis();
File file = new File(mCurrentPhotoPath);
Bitmap rotatedBitmap = null;
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),
FileProvider.getUriForFile(MainActivity.this,
getApplicationContext().getPackageName() + ".fileprovider", file));
// 회전된 사진을 원래대로 돌려 표시한다.
if (bitmap != null) {
ExifInterface ei = new ExifInterface(mCurrentPhotoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotatedBitmap = rotateImage(bitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotatedBitmap = rotateImage(bitmap, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotatedBitmap = rotateImage(bitmap, 270);
break;
case ExifInterface.ORIENTATION_NORMAL:
default:
rotatedBitmap = bitmap;
}
OCRThread ocrThread = new OCRThread(rotatedBitmap);
ocrThread.setDaemon(true);
ocrThread.start();
m_ivImage.setImageBitmap(rotatedBitmap);// 카메라로 찍은 사진을 뷰에 표시한다.
m_ocrTextView.setText(getResources().getString(R.string.LoadingMessage)); //인식된텍스트 표시
}
} catch (Exception e) {
}
}
break;
기본적으로 카메라로 찍은 사진을 받게되면 회전되어 결과가 나타납니다. 그부분을 원래대로 회전시켜 표시하도록 추가하였습니다.
결과
영어 보다 한글이 인식률이 떨어지는 것을 확인 할 수 있습니다.
또한 어떻게 찍느냐에 따라 인식률차이가 심하게 나타나는 부분이 있었습니다.
사진 위치는
[내파일] -> [내장메모리] -> [Android] -> [data] -> [패키지명을 찾으시면됩니다.] -> [files] -> [Pictures]
에 찍은 사진들이 저장됩니다.
조금이나마 도움되셨으면 좋겠습니다.
전체 코드는 제 github에 올려두었습니다.
https://github.com/hjiee/Android-TessTwo
'Android' 카테고리의 다른 글
[Android] Android Studio Live Template 알아두기#1 (0) | 2019.08.12 |
---|---|
[Android] OnItemClickListener not working in listView (1) | 2019.08.07 |
[Android] Fragment내에서 ViewPager생성 (0) | 2019.05.07 |
[Android] Only fullscreen opaque activities can request orientation (0) | 2019.03.14 |
[Android] Constraint Layout ChainStyle 사용하기 (1) | 2019.02.09 |