Python과 OpenCV – 48 : kNN을 이용한 글자 인식(OCR)

이 글의 원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.html 입니다.

이 글은 손으로 그린 글자를 판독하는 기능에 대한 것입니다. 이를 위해 몇가지 훈련 데이터(train_data)와 시험 데이터(test_data)가 필요합니다. 아래와 같은 2000×1000 픽셀 크기의 digits.png 파일을 사용합니다.

이 이미지에는 손으로 작성한 5000개의 0~9까지의 문자가 담겨 있습니다. 문자 하나당 500개씩 기록되어 있으며, 가로와 세로로 각각 100개씩, 5개씩 표기되어 있습니다. 이미지에서 문자 하나가 차지하는 크기는 20×20 픽셀입니다. 가장 먼저 이 이미지에서 5000개의 문자 단위로 잘라내야 합니다. 그리고 이 20×20 픽셀 크기 문자 이미지를 400 크기의 단일 행으로 만듭니다. 이 데이터가 모든 픽셀에 대한 화소값을 가지는 피쳐셋(Feature Set)입니다. 우리가 생성할 수 있는 가장 단순한 피쳐셋입니다. 이 데이터에서 각 문자의 250개에 해당하는 부분은 train_data로 사용하고 나머지 250개는 test_data로 사용합니다.

이제 코드를 작성해 보면..

import numpy as np
import cv2

img = cv2.imread('./data/digits.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# Now we split the image to 5000 cells, each 20x20 size
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]

# Make it into a Numpy array. It size will be (50,100,20,20)
x = np.array(cells)

# Now we prepare train_data and test_data.
train = x[:,:50].reshape(-1,400).astype(np.float32) # Size = (2500,400)
test = x[:,50:100].reshape(-1,400).astype(np.float32) # Size = (2500,400)

# Create labels for train and test data
k = np.arange(10)
train_labels = np.repeat(k,250)[:,np.newaxis]
test_labels = train_labels.copy()

# Initiate kNN, train the data, then test it with test data for k=1
knn = cv2.ml.KNearest_create()
knn.train(train, cv2.ml.ROW_SAMPLE, train_labels)
ret, result, neighbors, dist = knn.findNearest(test, k=5)

# Now we check the accuracy of classification
# For that, compare the result with test_labels and check which are wrong
matches = result==test_labels
correct = np.count_nonzero(matches)
accuracy = correct*100.0/result.size
print(accuracy)

코드를 설명하면, 8번은 digits.png 이미지를 가로로 100개, 세로로 50로 잘라 조각내어 cells 변수에 저장하는데, 각각의 조각 이미지에는 문자 하나가 담겨 있습니다. 11번 코드는 다시 이 cells를 NumPy의 배열로 만들어 x 변수에 저장합니다. 14번 코드는 배열 x 중 절반을 학습 데이터로 사용하고 나머지 절반을 테스트 데이터로 사용하고자 각각 train과 test 변수에 담습니다. train 변수에 저장된 문자에 대해 0~9까지의 값으로 라벨링해줘야 하는데, 18-19번 코드가 그에 해당합니다. 바로 이 train 데이터와 train_labels 데이터가 학습 데이터라고 할 수 있습니다. 이렇게 학습된 데이터를 토대로 test 변수에 저장된 문자들이 0~9까지 중 무엇에 해당하는지 kNN 알고리즘으로 파악하는 것이 23~25번 코드입니다. 최종적으로 테스트 데이터가 정확히 인식되었는지 확인하는 코드가 29~32번 코드입니다. 출력값은 91.76인데, 즉 성공률이 91.76%라는 의미입니다.

인식 정확도를 개선하기 위해서는 인식이 실패한 데이터를 학습시켜 train 변수에 추가하고 다음에 이 변수를 재활용하는 것입니다. 이를 위해 파일에 저장하고 다음에 저장된 파일로부터 불러오는 함수가 필요합니다. 학습 데이터를 저장하는 예는 다음과 같습니다.

np.savez('knn_data.npz',train=train, train_labels=train_labels)

데이터 파일을 불러오는 예는 다음과 같습니다.

with np.load('knn_data.npz') as data:
    print data.files
    train = data['train']
    train_labels = data['train_labels']

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다