machine learning, image

digit recognition with MNIST database with sklearn

qkqhxla1 2015. 9. 21. 17:46

http://hanzratech.in/2015/02/24/handwritten-digit-recognition-using-opencv-sklearn-and-python.html

에 나온데로 따라서 한거 정리. (환경 : 윈도우 7 파이썬 32비트.)


여태까지 숫자인식을 할때에는 파이썬으로 이미 만들어진 모듈이나, opencv로 내가 하나하나 입력해줘서 트레이닝후 인식을 했었는데, 이번엔 이미 만들어진 다수의 숫자 데이터를 가져와서(70000개), 각각의 특징점을 찾은 후(또는 이미 정리된 특징점으로) 숫자를 인식하는 기본적인 예제. 인식률이 높다는게 큰 특징.


1. sklearn 모듈 설치.

http://scikit-learn.org/stable/install.html

기본 필요조건.

Python (>= 2.6 or >= 3.3),

NumPy (>= 1.6.1),

SciPy (>= 0.9).

설치 : pip install -U scikit-learn


2. skikit 설치.

http://scikit-image.org/

설치 : https://pypi.python.org/pypi/scikit-image#downloads 에서 소스를 다운받아서 setuptools로. 

python setup.py install


3. 중간 점검과 데이터 다운로드.

# -*- encoding: cp949 -*-
from sklearn.externals import joblib
from sklearn import datasets
from skimage.feature import hog
from sklearn.svm import LinearSVC
import numpy as np
dataset = datasets.fetch_mldata("MNIST Original")

이 코드를 실행시킨다. 모듈 임포트 에러가 안 떠야 하며, 위 코드는 50메가정도의 데이터를 다운받느라 실행이 오래걸린다. 주의 : 절대 실행도중에 창을 끄거나 하지 말것. 

실행도중에 끄거나 멈추면 다운받던 파일이 깨진다. 해결법은

http://stackoverflow.com/questions/19530383/how-to-use-datasets-fetch-mldata-in-sklearn 에 나온데로 scikit_learn_data폴더를 찾아서 내부를 다 지워주면 된다. 나같은겨우 C:\Users\사용자이름\scikit_learn_data에 있었다.


저 데이터가 다운이 안될경우

http://mldata.org/repository/search/?searchterm=hand&data=Data 에서 matlab용으로 다운로드해서 넣으면 된다.


5. 트레이닝.

# -*- encoding: cp949 -*-
from sklearn.externals import joblib
from sklearn import datasets
from skimage.feature import hog
from sklearn.svm import LinearSVC
import numpy as np
dataset = datasets.fetch_mldata("MNIST Original")
features = np.array(dataset.data, 'int16')
labels = np.array(dataset.target, 'int')
list_hog_fd = []
for feature in features:
    fd = hog(feature.reshape((28, 28)), orientations=9, pixels_per_cell=(14, 14), cells_per_block=(1, 1), visualise=False)
    list_hog_fd.append(fd)

hog_features = np.array(list_hog_fd, 'float64')

clf = LinearSVC()
clf.fit(hog_features, labels)
joblib.dump(clf, "digits_cls.pkl", compress=3)

코드를 그대로 실행시킨다. 별다른 에러가 없으면 트레이닝 완료.

트레이닝시 hog라는 알고리즘을 이용하여 트레이닝하는데 뭔지 알고싶으면 이 사이트를 참고하라고 한다.

http://scikit-image.org/docs/dev/auto_examples/plot_hog.html


6. 실험.

실험용 이미지.

# -*- encoding: cp949 -*-
import cv2
from sklearn.externals import joblib
from skimage.feature import hog
import numpy as np

clf = joblib.load("digits_cls.pkl")
im = cv2.imread("photo8.jpg")
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
im_gray = cv2.GaussianBlur(im_gray, (5, 5), 0)
ret, im_th = cv2.threshold(im_gray, 90, 255, cv2.THRESH_BINARY_INV)
ctrs, hier = cv2.findContours(im_th.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
rects = [cv2.boundingRect(ctr) for ctr in ctrs]

for rect in rects:
	cv2.rectangle(im, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]), (0, 255, 0), 3)
	leng = int(rect[3] * 1.6)
	pt1 = int(rect[1] + rect[3] // 2 - leng // 2)
	pt2 = int(rect[0] + rect[2] // 2 - leng // 2)
	roi = im_th[pt1:pt1+leng, pt2:pt2+leng]

	roi = cv2.resize(roi, (28, 28), interpolation=cv2.INTER_AREA)
	roi = cv2.dilate(roi, (3, 3))

	roi_hog_fd = hog(roi, orientations=9, pixels_per_cell=(14, 14), cells_per_block=(1, 1), visualise=False) 	
	nbr = clf.predict(np.array([roi_hog_fd], 'float64'))
	cv2.putText(im, str(int(nbr[0])), (rect[0], rect[1]),cv2.FONT_HERSHEY_DUPLEX, 2, (0, 255, 255), 3)

cv2.imshow("Resulting Image with Rectangular ROIs", im)
cv2.waitKey()


코드를 실행하면 잘 인식함을 확인할수 있다. 


데이터베이스가 숫자 관련된 데이터베이스밖에 없는데, 내가 필요한건 영어 대문자+숫자의 데이터이다. 

일단 예제는 정리해두고 구글링해서 관련 데이터를 찾은 후 트레이닝을 시켜봐야겠다. 성공하게되면 다시 글씀...


난 단순히 영어 대문자 필기체를 높은 인식률로 인식하는걸 원하는데 내가 필요한 자료만 빼먹을수 없을것같다... 내가 원하는걸 만들려면 아예 빅데이터쪽으로 제대로 어느정도 공부를 해봐야할듯 싶다.