Python/파이썬 OpenCV 공부

[OpenCV 머신러닝] OpenCV로 KNN 필기체 숫자 인식 프로그램 구현하기

AI 꿈나무 2020. 10. 24. 21:17
반응형

k 최근접 이웃 알고리즘을 이용한 필기체 숫자 인식

 만약 정해진 폰트로 인쇄된 숫자라면 템플릿 매칭으로도 숫자 인식이 가능합니다.

 

 OpenCV 필기체 숫자 데이터는 OpenCV 깃허브에서 제공하는 숫자 데이터를 이용했습니다.

 

opencv/opencv

Open Source Computer Vision Library. Contribute to opencv/opencv development by creating an account on GitHub.

github.com

 데이터에는 20X20 숫자 영상이 가로 100개, 세로 50개 총 5000개의 숫자가 있습니다.

 각 행에 100개의 데이터가 있고 각 숫자(0~9)는 5줄마다 구분 됩니다.

 

 이 데이터를 이용해서 머신러닝 알고리즘을 학습시키고 추론까지 진행해 보겠습니다.

 

KNN 필기체 숫자 인식

 KNN 알고리즘은 이해하기 쉽지만 성능이 아주 좋진 않습니다.

 HOG-SVM 방법은 영상의 특징 벡터를 이용하는데 KNN 방법은 단순히 픽셀 값만 이용하게 됩니다.

 픽셀값 자체를 이용하는 것이 제일 간단하고 가장 간단하게 필기체를 구분할 수 있습니다.

 

KNN 필기체 숫자 인식 흐름도

 20X20 크기의 영상 하나를 1행으로 나열합니다. (1X400)

 전체 벡터를 하나의 행렬로 묶어서 표현합니다. (1x400 크기의 벡터 5000개)

 그러면 5000X400 크기의 행렬 1개가 되는데 이를 KNearest에 입력으로 줍니다.

 

 KNN은 지도 학습이므로 정답에 해당하는 레이블 데이터도 같이 입력해줘야 합니다.

 위부터 500개씩 0, 1, 2, 이므로 레이블 데이터도 만들어서 KNearest에 입력해줘야 합니다.

 

KNN 필기체 숫자 인식 예제

 예제 코드 출처 :  황선규 박사님 github홈페이지 sunkyoo.github.io/opencv4cvml/

 황선규 박사님의 깃허브에 있는 예제코드를 직접 따라해보고 분석해보았습니다.

 이 코드는 마우스로 직접 숫자를 그려서 KNN으로 인식하는 프로그램입니다.

 

# 마우스로 숫자를 그려서 인식하는 프로그램
oldx, oldy = -1, -1

def on_mouse(event, x, y, flags, _):
    global oldx, oldy
    
    if event == cv2.EVENT_LBUTTONDOWN:
        oldx, oldy = x, y
        
    elif event == cv2.EVENT_LBUTTONUP:
        oldx, oldy = -1, -1
    
    elif event == cv2.EVENT+MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            cv2.line(img, (oldx, oldy), (x, y), (255, 255, 255), 40, cv2.LINE_AA)
            oldx, oldy = x, y
            cv2.imshow('img', img)
            
# 학습 & 레이블 행렬 생성
# 그레이스케일로 불러오기
digits = cv2.imread('digits.png', cv2.IMREAD_GRAYSCALE)

if digits is None:
    print('Image load failed!')
    sys.exit()
    
# digits의 가로 크기와 세로 크기 계산
h, w = digits.shape[:2]

# 각각의 부분 영상을 잘라내는 코드
# 세로와 가로를 20x20으로 나눔
cells = [np.hsplit(row, w//20) for row in np.vsplit(digits, h//20)]

# list를 ndarray로 변환
cells = np.array(cells) # (50, 100, 20, 20)

# (5000, 400) 2차원 행렬로 변환, 데이터 타입은 float32
train_images = cells.reshape(-1, 400).astype(np.float32)

# 정답 레이블 데이터, shape(5000, ) int32
train_labels = np.repeat(np.arrange(10), len(train_images)/10)

# KNN 학습
knn = cv2.ml.KNearest_create() # 객체 생성
knn.train(train_images, cv2.ml.ROW_SAMPLE, train_labels) 

# 사용자 입력 영상에 대해 예측
img = np.zeros((400, 400), np.uint8)

cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)

while True:
    key = cv2.waitKey()

    if key == 27:
        break
    elif key == ord(' '): # 스페이스바 누를시 동작
        test_image = cv2.resize(img, (20, 20), interpolation=cv2.INTER_AREA)
        test_image = test_image.reshape(-1, 400).astype(np.float32) # 1행 400열로 변환

        ret, _, _, _ = knn.findNearest(test_image, 5)
        print(int(ret))

        img.fill(0) # 출력하고나서 영상을 검은색으로 채워줌
        cv2.imshow('img', img)

cv2.destroyAllWindows()

 

 

 이처럼 입력한 필기체를 KNN 방법으로 인식하는 것을 확인할 수 있습니다.

 


OpenCV 홈페이지와 황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.

 

반응형