Tesseract-OCR을 활용할 수 있는 Unity

KLab Advent Calendar 2016 12일째 글이다.

개시하다


OCR은 이미지 분석 문자를 통해 문자를 읽는 장치나 소프트웨어를 말한다.
최근에는 가계부 프로그램의 영수증 등을 읽는 데 쓰인다.
이 기능을 사용하려고 약간의 에디터 확장을 만들어서 조사를 해봤어요.
참고로 자신의 환경은 맥OS이기 때문에 윈도 등 다른 환경의 사람들은 적당히 다시 읽어주세요.

라이브러리 선택


Unity에서 사용할 수 있는 OCR 라이브러리를 검색하면

  • Vuforia

  • Tesseract-OCR
  • 를 참고하십시오.
    자욱한 소리!Vuforia는 Unity에서 간단하게 현실을 확장할 수 있는 프로그램 라이브러리로 그 기능으로서 문자인식이 있는 것 같다.
    Tesseract-OCR은 GiitHub이 공개한 Apache 라이선스 아래 OCR 라이브러리다.
    이 Tesseract-OCR은넷프레임워크가 이용할 수 있는 랩.NET wrapper for tesseract-ocr이 있는데, 유니티도 이용할 수 있기 때문에 테슬레이트를 해보기로 했다.

    . NET Wrapper for tesseract-ocr 가져오기


    결론부터 말하자면NET Wrapper for tesseract-ocr는 Unity에서 사용할 수 없습니다.
    .NET Wrapper for tesseract-ocr 필요System.Drawing.dll.System.Drawing.dll 자신이 모노에 들어갔기 때문에 그곳에서 유니티의 플러진 폴더 등을 넣는다.
    단, 라이브러리 내에서 사용된System.AppDomain.CurrentDomain.BaseDirectory은 Unity에서 반환null되므로 이동하지 않습니다.
    또 이 문제를 해결했어도 liblept172.solibdl.so가 없었다.
    유닛으로 이동할 수 있지만 맥OS로는 어려울 것 같아요.
    Unity에서 사용합니다.NET에서 사용할 수 있도록 랩으로 싸는 게 매력적인데 여기서 다른 방법을 먼저 시도해보자.

    DllImport에서 Tesseract-OCR 사용


    정통 테슬레이트는 맥OS라면 홈brew로 설치할 수 있다.
    다른 환경인 분들은 본가wiki를 보시는 것이 좋습니다.
    $ brew install tesseract
    
    Unity 스크립트DllImport에 설치된tesseract를 사용합니다.
    테슬레이트API를 보면서Unity에서 전달할 수 있는 매개 변수의 함수를 찾습니다.
    만약 아래의 함수가 있다면, 나는 기본적으로 할 수 있다고 생각한다.
  • TessBaseAPICreate
  • 생성 프로세서
  • TessBaseAPIInit3
  • 초기화 프로세서
  • 교사의 데이터, 설정 파일을 포함하는 디렉터리나 언어를 지정한다
  • TessBaseAPISetImage
  • 설정 이미지
  • bytes_per_pixel 24비트 이미지 3
  • 로 설정
  • bytes_per_linebytes_per_pixel * width
  • TessBaseAPIGetUTF8Text
  • 이미지에서 문자열 추출
  • UTF8에서 얻을 수 있는 최대치
  • 테스트용 스크립트를 미리 기록합니다.
    스크립트를 읽을 소스의 이미지를 Inspector에 표시하는 Image 구성 요소를 연결하고 실행하면 콘솔에서 읽을 문자열을 출력합니다.
    using UnityEngine;
    using UnityEngine.UI;
    using System;
    using System.Runtime.InteropServices;
    using System.Linq;
    using System.Collections.Generic;
    
    public class OcrTest : MonoBehaviour
    {
        [SerializeField]
        Image source;
    
        [DllImport ("libtesseract", EntryPoint="TessBaseAPICreate")]
        private static extern IntPtr Create();
    
        [DllImport ("libtesseract", EntryPoint="TessBaseAPIInit3")]
        private static extern int Init(IntPtr handle, string datapath, string language);
    
        [DllImport ("libtesseract", EntryPoint="TessBaseAPISetImage")]
        private static extern int SetImage(IntPtr handle, byte[] imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line );
    
        [DllImport ("libtesseract", EntryPoint="TessBaseAPIGetUTF8Text")]
        private static extern string GetText(IntPtr handle);
    
        void Start()
        {
            var originalData = source.sprite.texture.GetRawTextureData().Reverse().ToArray();
    
            var tmp = new List<byte>();
            var destination = new List<byte>();
            for(var i = 0;i < originalData.Length;i += 3)
            {
                tmp.Add(originalData[i]);
                tmp.Add(originalData[i + 1]);
                tmp.Add(originalData[i + 2]);
                if (tmp.Count >= 3 * source.sprite.texture.width) 
                {
                    tmp.Reverse();
                    destination.AddRange(tmp);
                    tmp.Clear();
                }
            }
    
            var handle = Create();
            Init(handle, null, "eng");
    
            SetImage(handle, destination.ToArray(),
                source.sprite.texture.width, 
                source.sprite.texture.height, 
                3, 
                3 * source.sprite.texture.width);
    
            Debug.Log(GetText(handle));
        }
    }
    
    
    주의해야 할 것은 GetRawTextureData() 그림의 왼쪽 아래에서부터byte 배열을 되돌려줍니다.
    그림의 왼쪽 상단에서 시작하는byte열로 변환해야 합니다.
    위 스크립트에서 GetRawTextureData() 얻은 배열을 반전시킨 후 각각 3byte를 읽고 그림의 폭까지 한 열을 더 반전시키는 방식으로 진행합니다.

    Unity Editor의 실행 결과


    이미지 읽기

    Unity 콘솔 출력
    ABCD
    Enjoy your life.
    EFG
    1984 0712
    abc de f
    Hello world!
    Unity 5.4.3p1
    
    이 스크립트를 실행하면 이런 느낌을 출력할 수 있습니다.
    나는 카메라로 종이의 문자를 찍는 것보다 정밀도가 더 좋다고 생각한다.
    또한tesseract는 일본어도 읽을 수 있어 시도해 보는 것도 재미있을 것 같다.

    끝말


    드디어 글을 읽을 수 있게 되었다.
    유니티에는 당연히 사용하기 쉬운 프로그램 라이브러리가 있다고 생각하지만 OCR만 사용해도 길을 잃은 느낌이 든다.
    결과적으로 DllImport가 최고였어요.
    Sqlite3로 Windows Phone8.0을 싸서 사용한 경험이 여기서 활용돼 정말 좋습니다.
    마침내 이렇게 하고 싶은 Editor 확장의 한 걸음을 내디뎠다.

    좋은 웹페이지 즐겨찾기