Tesseract 및 OpenCV를 이용한 텍스트 인식 (ORC) - grruju/uju GitHub Wiki

Tesseract OCR 이란?

테서랙트(Tesseract)는 Apache 2.0 라이선스에 따라 사용할 수 있는 오픈 소스 텍스트 인식 (Open Source OCR) 엔진 입니다. Tesseract는 유니코드 (UTF-8)를 지원 하며 100개 이상의 언어를 지원합니다. 사용시 단점으로 GPU지원을 하지 않으며, 속도가 느린편입니다. 테서랙트 OCR 사용시 유의사항은 본문 아래쪽 내용을 참고하세요. https://github.com/tesseract-ocr/tesseract

파이썬 테서랙트란?

Python-tesseract는 Google의 Tesseract-OCR Engine을 래핑한 라이브러리입니다. jpeg, png, gif, bmp, tiff 등을 포함하여 Pillow 및 Leptonica 이미징 라이브러리에서 지원하는 모든 이미지 유형을 읽을 수 있으므로 tesseract에 대한 독립 실행 형 호출 스크립트로도 유용합니다. 또한 스크립트로 사용되는 경우 Python-tesseract는 인식 된 텍스트를 파일에 쓰는 대신 인쇄합니다.

1. 다운로드

tesseract-ocr-w64-setup-v5.0.0-alpha.20210506.exe

2. Install

설치 중 Additional language data (download) 옵션에서 Korean 추가

1

환경변수 Path에 C:\Program Files\Tesseract-OCR 추가

2

설치 확인

cmd or powershell에서 확인 가능

tesseract --version

3

3. pytesseract install

python 에서 사용하기 위해 pytesseract 설치

pip install pytesseract

4. Python으로 테스트

코드

from PIL import Image
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract' 
img = Image.open('test.png') 
text = pytesseract.image_to_string(img,lang='kor+eng') 

print (text)

예제

4

결과

5



OpenCV

OpenCV(Open Source Computer Vision)은 오픈 소스 컴퓨터 비전 라이브러리이다. 원래는 인텔이 개발하였다. 윈도, 리눅스 등의 여러 플랫폼에서 사용할 수 있다. 실시간 이미지 프로세싱에 중점을 둔 라이브러리이다.

예제 이미지

6

번호판의 글자에 윤곽선을 잡아주기 위해 먼저 OpenCV라이브러리를 이용하여 원본 이미지에 전처리 과정을 진행 한다.

먼저 컬러 이미지를 Gray 이미지로 바꿔주는 것이 필요하다. RGB 색상 공간으로 볼때, 컬러 이미지의 모든 색은 R(빨간색)+G(녹색)+B(파란색)의 색을 조합해 표현 한다. 3가지 색상값을 1/3로 나누어 주거나, R,G,B 중 하나의 값만으로 표현하면 Gray 이미지로 표현할 수 있다.

img = cv2.imread('C:/Users/river/GrrUJU/uju/python/img/6.png', cv2.IMREAD_COLOR)
copy_img=img.copy()
img2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

Gray 이미지를 얻은 후, 필터를 적용시켜 윤곽선을 더 잘 잡을 수 있도록 한다. (가우시안 Blur 필터 적용)

blur = cv2.GaussianBlur(img2,(3,3),0)
cv2.imwrite('blur.jpg',blur)

blur

가우시안 필터 적용 전과 후의 차이가 느껴지지 않는다. 사람의 눈으로는 크게 차이가 느껴지지 않지만, 실제 엣지검출이나 영상처리과정에서 큰 영향을 끼친다고 한다...

전처리 된 사진에서 엣지를 검출한다.

canny = cv2.Canny(blur,100,200)
cv2.imwrite('canny.jpg',canny)

canny

cv2.Canny에 적용되는 Threshold1,2의 값(100,200)은 특정 사진에 맞춰 설정된 값이다. 이외에도 가우시안 값에 적용시킨 3x3 매트릭스 값도 마찬 가지이다. 이러한 값은 흑백영상에서 명암의 밝기 차이에 대한 변화율이라 생각하면 된다.

이제 엣지를 추출한 이미지에 대해 cv.findContours 함수를 사용하여 canny 이미지에서 Contours를 찾는다.

contours,hierarchy  = cv2.findContours(canny.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

Contours는 같은 에너지를 가지는 점들을 연결한 선?이다.


### OpeCV는 Contour를 찾을때 검은 바탕에 찾는 물체는 흰색으로 설정해주어야 한다.

전체 이미지에서 Contour의 가로 세로 비율 값과 면적을 통해, 번호판 영역에 벗어난 걸로 추정되는 값들은 제외 시킨다.

for i in range(len(contours)):
    cnt=contours[i]          
    area = cv2.contourArea(cnt)
    x,y,w,h = cv2.boundingRect(cnt)
    rect_area=w*h  #area size
    aspect_ratio = float(w)/h # ratio = width/height
                  
    if  (aspect_ratio>=0.2)and(aspect_ratio<=1.0)and(rect_area>=100)and(rect_area<=700): 
        cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),1)
        box1.append(cv2.boundingRect(cnt))

위 스크립트를 통해서 아래와 같은 이미지가 나오게 된다.

snake

이제 번호판 영역을 추출해야 한다. 위 이미지를 보면 번호판 영역에서 Rectangle들이 정렬로 모여 있는것을 확인할 수 있다.

9

위 그림의 화살표처럼 Rectangle과 Rectangle사이 간격과 기울기 값이 일정 범위 안에 들어올 시 카운트를 올리게 된다. 노란색 화살표의 경우 Rectangle사이 간격이 좁고 기울기의 차가 적으므로 가장 높은 카운트를 가지게 된다.

위의 알고리즘을 적용하기 위해 Contour 배열에 대해 버블정렬을 해준다.

for i in range(len(box1)): ##Buble Sort on python
    for j in range(len(box1)-(i+1)):
        if box1[j][0]>box1[j+1][0]:
            temp=box1[j]
            box1[j]=box1[j+1]
            box1[j+1]=temp

카운트가 가장 높은 Contour 값을 찾으면 번호판의 시작점이 된다.

for m in range(len(box1)):
    count=0
    for n in range(m+1,(len(box1)-1)):
        delta_x=abs(box1[n+1][0]-box1[m][0])
        if delta_x > 150:
            break
        delta_y =abs(box1[n+1][1]-box1[m][1])
        if delta_x ==0:
            delta_x=1
        if delta_y ==0:
            delta_y=1       
            gradient =float(delta_y) /float(delta_x)
        if gradient<0.25:
            count=count+1
        #measure number plate size         
    if count > f_count:
        select = m
        f_count = count;
        plate_width=delta_x

번호판 사이즈 부분에 대해서는 아래 코드 처럼 상수 값으로 Offset을 주어서 추출 한다.

number_plate=copy_img[box1[select][1]-10:box1[select][3]+box1[select][1]+20,box1[select][0]-10:140+box1[select][0]] 

test232

이제 번호판 여역 이미지에 대해 Gray이미지로 만들어준 다음, cv2.threshold를 사용하여 흑/백의 값만 나올 수 있도록 이진화 처리를 한다.

plate_gray=cv2.cvtColor(resize_plate,cv2.COLOR_BGR2GRAY)
ret,th_plate = cv2.threshold(plate_gray,150,255,cv2.THRESH_BINARY)

plate_th

그리고 erode 작업을 통해 검은색 글자 부분을 더 강조해준다.

kernel = np.ones((3,3),np.uint8)
er_plate = cv2.erode(th_plate,kernel,iterations=1)
er_invplate = er_plate

er_plate

그리고 pytesseract를 이용하여 인식을 하면,

image

19세 1004의 값이 나와야 하지만, 1941004 의 값이 나왔다. 한글 '세'글자를 인식하지 못하고 숫자 '4'로 인식된 결과이다. 인식률의 차이로 발생한 오차이며, 필터나, Canny 등의 상수 값을 조정하여 인식률을 높일 수 있다고 한다...

소스파일

코드 : pytesseract_opency.py
이미지 : img 폴더의 6.png

시작은 매크로 였으나 옆길로 샌 결과.

끝을 맺고 싶으나 실력이 미비하기에 우선 진행 과정만 정리한다.

자세한 내용은 원본을 참조하시길.

https://emaru.tistory.com/15

⚠️ **GitHub.com Fallback** ⚠️