machine learning, image

python OCR of Hand-written Data using kNN 코드해석

qkqhxla1 2015. 6. 30. 18:54

http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.html?highlight=hand


이페이지 하나를 이해하기가 매우 힘들었다. 파이썬은 어느정도 사용하는데, 저기서는 데이터 분석용으로 numpy를 주로 사용하고, 무슨 복잡한 kNN알고리즘까지 들어가니 저 간단한 코드 몇줄 해석하는데 상당히 오래걸렸다. 나중에 다시 볼 때를 위해 정리해서 올려놓음.


샘플사진.(digits.png)



코드.

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('digits.png') #digits.png를 연다.
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #grayscale모드로 연다.
#위 코드는 간단하게 img = cv2.imread('digits.png',0)으로 줄여서 쓸 수도 있다.

# Now we split the image to 5000 cells, each 20x20 size
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
#사진을 보면 알겠지만,숫자가 오른쪽으로 100개, 아래로 50줄이 있다. grayscale모드로 가져오게 되면 모든 픽셀이 숫자형태로 나타나게 되며,
#이걸 50개의 행으로 vsplit 하게되면 각각의 줄로 나눠지고, 그걸 다시 100개로 나누면 각각의 글자들로 나눠지게 된다.
#글자들은 각각 크기가 20x20크기이며, 딱딱 20x20의 크기안에 있기 때문에 이렇게 나누게되면 각각의 글자들로 나눠진다.
#자세한 설명은 아래에 사진 첨부.

# Make it into a Numpy array. It size will be (50,100,20,20)
x = np.array(cells)
#이걸 np행렬로 만든다. 위의 50,100,20,20은 50줄의, 좌우로 100개의 글자, 크기는 20,20이라는 소리이다.

# Now we prepare train_data and test_data.
train = x[:,:50].reshape(-1,400).astype(np.float32) # Size = (2500,400)
#x[:,:50]은 이렇게 해석된다. x[:]는 np행렬인 x전체, 뒤의 :50은 50까지만 가져오겠다는 소리이다. 자세한 설명은 아래에 사진을 첨부함.
#reshape함수는 np행렬을 인자의 크기대로 다시 만든다. -1이 인자로 들어가면 나머지 인자에 맞춰서 알아서 변형하겠다는 소리이다. [1,2,3,4,5,6].reshape(3,3) == [[1,2,3],[4,5,6]]
#이고, [1,2,3,4,5,6].reshape(3,-1)도 같은소리, ~~.reshape(-1,3)도 같은소리이다.
#마지막의 .astype(np.float32)는 내부 인자를 전부 float32형으로 바꿔주겠다는 소리이다.

test = x[:,50:100].reshape(-1,400).astype(np.float32) # Size = (2500,400)
#위에서 train은 앞의 50개까지를, 이번의 test는 뒤의 50개를 테스트용으로 만들었다.

# Create labels for train and test data
k = np.arange(10)
train_labels = np.repeat(k,250)[:,np.newaxis]
#레이블을 붙인다. 0,1,2,3,4,5,6,7,8,9의 레이블을 붙이는데 train시 한 글자당 5줄 * 50개이므로 250개를 넣는다.
#ex) 0은 전부 500개인데, 앞의 250개는 훈련용으로 쓰므로 이렇게 넣음.

test_labels = train_labels.copy()
#test할 데이터의 레이블도 만든다. train과 수가 같으므로 그냥 train의 내용을 복사했다. 만약 다르면 다르게 만들어야한다.

# Initiate kNN, train the data, then test it with test data for k=1
knn = cv2.KNearest()
knn.train(train,train_labels)
ret,result,neighbours,dist = knn.find_nearest(test,k=5)
#훈련을 하고 결과를 도출해낸다. k=5는 앞에서 kNN알고리즘에 대해 적었는데, 검사할 이웃이 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
#결과로 나온 result와 test_labels의 인자를 하나하나 비교해서 같으면 1, 틀리면 0으로 만든다.

correct = np.count_nonzero(matches)
#행렬에서 0이 아닌 인자의 숫자를 구한다.

accuracy = correct*100.0/result.size
print accuracy


np.vsplit()으로 나누면 행으로 나눠진다. ex)

x[:,:50]의 경우 중간까지 가져온다는 뜻이다. ex)

빨간색 범위를 가져오겠다.



이걸로 몇번 삽질해본후 알아낸 단점.


트레이닝 데이터와 인식할 데이터의 크기가 같아야 한다...... 이게 너무 큰 단점.... 크거나 작은 크기의 이미지면 트레이닝 데이터와 맞는 크기로 바꿔줘야 한다. 어떻게 생각해보면 당연히 같아야 하는거아냐? 할지도 모르겠는데 이게 너무 큼...