소개할 프로그램은 아시는 분은 다 아실만한 프로그램입니다.
바로 대표적인 오픈소스 광학문자인식 (OCR, Optical Character Recognition) 라이브러리인 tesseract-ocr 과 안드로이드 문자인식 앱인 mezzofanti 입니다.
프로그램을 개발하신 분들과 도움을 주신 intruder 님께 감사드립니다.

tesseract-ocr (http://code.google.com/p/tesseract-ocr/) 은 2.03 버전까지 일부 언어만 지원되다가, 현재 3.00 버전부터 한글도 지원되고 내부적으로 leptonica (http://www.leptonica.com/) 라는 오픈소소 이미지 처리 라이브러리를 활용하고 있습니다. tesseract-ocr 은 심지어 AOSP(http://android.git.kernel.org) 및 eyes-free project 등에서도 이미 빌드하여 사용하고 있습니다.

mezzofanti (http://code.google.com/p/mezzofanti/) 는 카메라로 찍은 이미지 내의 글자를 tesseract 라이브러리를 이용해서 인식하는 오픈소스 안드로이드 앱입니다. 이 앱은 현재 1.0.3 버전까지 나와 있는데, 개발된지 1년도 더 지났고 tesseract 2.03 버전을 활용하므로 한글인식을 지원하지 않는 단점이 있습니다. 그래서, 한글 등이 지원될 수 있도록 mezzofanti 를 tesseract 3.0 버전에 적용해 보았습니다.
아래에 그렇게 구현하는 방법에 대해 순서적으로 정리했습니다.

1. 개발환경 구축
개발환경은 리눅스 우분투 10.04(Lucid) 이고, 안드로이드 NDK (r5b), SDK, JDK 등이 이미 설치되어 있어야 합니다.

2. mezzofanti 설치
mezzofanti 홈페이지 (http://code.google.com/p/mezzofanti/downloads/list) 로부터 Mezzofanti_java_code_1_0_3.zip 파일을 다운로드받습니다.
그리고, mezzofanti 디렉토리를 만들어 압축을 풉니다.
  $ unzip Mezzofanti_java_code_1_0_3.zip -d mezzofanti

3. tesseract 및 jpeg 라이브러리의 ndk 빌드
다음은 tesseract 3.0 소스를 가져와서 ndk 로 빌드하여야 합니다. 그런데, 이미 AOSP 내에 이 소스 패키지가 포함되어 있으므로 이 소스를 활용하도록 합니다. 그래서, 다음 명령을 사용하여 tesseract 와 관련된 패키지의 소스코드를 다운받습니다.
 $ git clone https://android.googlesource.com/platform/external/tesseract.git
 $ git clone https://android.googlesource.com/platform/external/jpeg.git
 $ git clone https://android.googlesource.com/platform/system/core.git

mezzofanti 디렉토리 아래 jni 서브디렉토리, 그 아래 include 서브디렉토리를 만듭니다.
  $ mkdir -p mezzofanti/jni/include

tesseract 와 jpeg 소스를 통째로 mezzofanti/jni 디렉토리로 복사 또는 옮깁니다.
 $ cp -r  tesseract mezzofanti/jni
 $ cp -r jpeg mezzofanti/jni

core/include/cutils 및 core/i 디렉토리를 통째로 mezzofanti/jni/include 로 복사 또는 옮깁니다.
 $ cp -r core/include/cutils/ mezzofanti/jni/include/
 $ cp -r core/include/log/ mezzofanti/jni/include/

core/libcutils/ashmem-dev.c  파일을 mezzofanti/jni/jpeg 로 복사 또는 옮깁니다.
 $ cp core/libcutils/ashmem-dev.c mezzofanti/jni/jpeg

mezzofanti/jni/Android.mk  파일을 만듭니다.
 LOCAL_PATH := $(my-dir)

include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
          	jpeg \
          	tesseract \
       	))

mezzofanti/jni/tesseract/Android.mk 와 mezzofanti/jni/jpeg/Android.mk  파일을 수정합니다.
$ diff tesseract/Android.mk mezzofanti/jni/tesseract/Android.mk
406c406,407
<     external/jpeg
---
>     $(LOCAL_PATH)/../jpeg \
>     $(LOCAL_PATH)/../include
433c434,435
< LOCAL_STATIC_LIBRARIES:=$(LOCAL_STATIC_LIBRARIES_)
<      libjpeg
---
> #LOCAL_STATIC_LIBRARIES:=$(LOCAL_STATIC_LIBRARIES_)
> #     libjpeg
436c437,439
<     liblog
---
>     libjpeg
> #    liblog
> LOCAL_LDLIBS := -llog 

$ diff jpeg/Android.mk mezzofanti/jni/jpeg/Android.mk 
14c14
<     jquant2.c jutils.c jmemmgr.c armv6_idct.S
---
>     jquant2.c jutils.c jmemmgr.c ashmem-dev.c armv6_idct.S
16a17
> LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include


mezzofanti/jni/tesseract/api/jni.cpp 파일에서는 mezzofanti 에서 활용하는 추가적인 함수를 위해 많은 부분을 수정해야 합니다. 이 부분은 첨부파일을 다운로드해서 덮어쓰면 되겠습니다.
(jni.cpp 파일의 DEBUG 매크로를 1로 하면 인식된 결과가 /sdcard/out.txt 에 저장됩니다)

이제 mezzofanti  디렉토리에서 ndk-build 를 하면 tesseract 빌드과정이 끝납니다. (android-ndk-r9 에서는 "error: format not a string literal and no format arguments [-Werror=format-security]"라는 오류가 발생합니다. 그럴 때는 android-ndk-r9/build/core/default-build-commands.mk 파일을 고쳐 "-Werror=format-security" 을 삭제해 줍니다.)

$ cd mezzofanti; ndk-build
…
SharedLibrary  : libjpeg.so
Install    	: libjpeg.so => libs/armeabi/libjpeg.so
...
SharedLibrary  : libocr.so
Install    	: libocr.so => libs/armeabi/libocr.so

4. mezzofanti 소스 수정
이제 tesseract 및 jpeg 라이브러리가 준비되었으니 이클립스 또는 ant 로 mezzofanti 를 빌드하면 됩니다. 그런데, 업그레이드된 tesseract 버전과도 잘 동작하도록 하기 위해 소스코드의 일부를 수정하여야 합니다. 이클립스 또는 리눅스에서 다음 부분들을 수정합니다.

먼저 mezzofanti/AndroidManifest.xml 파일에서 카메라 장치와 외부 메모리 장치(sd 카드)에 대한 쓰기 권한을 추가해 줍니다.
<uses-feature android:name="android.hardware.camera"/>
...
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

다음은 mezzofanti/src/com/itwizard/mezzofanti/OCR.java 파일을 수정해 줍니다.
OCR.java 의 OCR 클래스는 JNI 를 통해 tesseract 라이브러리와 연동되는 객체이며, 각종 native 메소드와 변수를 정의하고 있습니다.
diff mezzofanti-orig/src/com/itwizard/mezzofanti/OCR.java mezzofanti/src/com/itwizard/mezzofanti/OCR.java
278a279,280
>               	if ( lang.compareTo("kor") == 0 )
>                           	return "Korean";                   	 
384c386
<           	closeDebug();                       	// clean close debug    
---
>           	// closeDebug();                            	// clean close debug    
735a738
>                   	/*
836a840
>                   	*/
1006c1010
<   	public native void          	setVariableNative(                          	// set a lib variable
---
>   	public native boolean       	setVariableNative(                          	// set a lib variable
1017a1022,1025
>   	// aux functions for liblept
>   	public native void          	setEncodedNative(byte[] image);
>   	public native void          	normalizeBgNative(int reduction, int size, int bgval);
> 
1043c1051
<   	public native String	getBoxText();                               	// get the box for each letter
---
>   	// public native String     	getBoxText();                               	// get the box for each letter
1047c1055 
<   	public native void  	closeDebug();                               	// clean close the debug (if any)
---
>   	// public native void       	closeDebug();                               	// clean close the debug (if any)

각각의 부분에 대한 설명은 다음과 같습니다.
- 한글데이터 추가를 위해 OCR.java 파일의 LanguageMore() 메소드에서 278라인쯤에 내용을 추가했습니다. 기타 원하는 언어(중국어 번체, 간체, 일본어 등) 를 추가할 수도 있습니다.
- 735 라인부터 836라인까지 주석으로 막은 이유는 이 부분은 인식된 결과를 결과 액티비티로 보내기 전에 한번 가공해 주는 부분인데, 가공하지 않고 바로 결과로 보여주어야 한글 등이 제대로 보이더군요. 더욱 검토가 필요한 부분입니다.
- 나머지 부분은 native 메소드들과 관련하여 제거하거나 수정하거나 추가하는 부분들입니다.

그리고,  "Not enough space for installation on external strage" 와 같은 오류가 발생할 때는, mezzofanti/src/com/itwizard/mezzofanti/AssetsManager.java 파일을 수정하여 다음 부분 코드를 막아주면 됩니다.
diff mezzofanti-orig/src/com/itwizard/mezzofanti/AssetsManager.java mezzofanti/src/com/itwizard/mezzofanti/AssetsManager.java
146a146
>                   	/*
159a160
>                   	*/


또 하나, 기기에 따라 카메라의 setParameters 와 관련된 오류가 발생할 수 있습니다. 그런 경우를 위해 화면 크기를 고려해 카메라 프리뷰 사이즈를 지정하도록 하는 부분이 추가된 mezzofanti/src/com/itwizard/mezzofanti/CameraManager.java 파일을 첨부합니다.


5. mezzofanti 앱과 사전/학습 데이터파일 설치
이제 mezzofanti 를 이클립스 또는 ant 로 빌드하고, 안드로이드 스마트폰에 설치합니다.
앱을 설치하고 난 후에 곧바로 실행하면 제대로 동작하지 않는데, 사전/학습 데이터파일을 설치하지 않았기 때문입니다. 그래서 새로 빌드한 tesseract  3.0 버전에 맞는 영어, 한글 등의 사전/학습 데이터파일들(eng.traineddata.gz, kor.traineddata.gz 등)을 다음 링크들로부터 가져와서  /sdcard/tessdata 디렉토리에 넣고 압축을 풀어줍니다.

(근데, 갤럭시 s 같은 경우에는 아스트로 파일 매니저로 풀 때 확장자가 없어져버리더군요. 확장자가 반드시 .traineddata 이 되도록 고쳐주어야 합니다.)

6. mezzofanti 앱 실행
mezzofanti 를 실행하면 초기화면을 거쳐 카메라 화면이 나타납니다.
여기서 메뉴버튼을 눌러 Menu->Settings 메뉴의 "Set OCR dictionary language" 항목을 선택하면 영어와 한글 항목이 나타납니다. (내부 “Download new languages” 메뉴는 예전 버전의 데이터 파일이 다운되므로 활용하면 안됩니다.)

원하는 언어를 선택한 다음 다시 카메라 화면으로 되돌아가서 사진을 찍으면 이미지파일이 만들어지고 이것을 tesseract 를 통해 인식하게 됩니다. 찍는 모드는 전체 화면과 한줄라인 모드 2가지가 있습니다. 다음은 인식된 결과를 보여주는 예입니다.
device.png

적용된 앱에서는 여전히 예전 언어 인식 데이터파일을 다운로드하거나 참조하는 등의 코드가 있어 불완전하고 버그도 많고, 또 인식률도 50%가 안될 정도로 형편없지만 기본적인 기능을 확인했다는 데 의의를 둡니다. (중국어 한자가 오히려 인식률이 높은데 학습데이터파일이 문제인지도 모르겠습니다)
오히려, 관심있으신 분들께서 여기 오픈소스 자료들을 활용하여 훌륭한 앱을 만드셔서 무료로 배포해 주시길 기대합니다.