반응형
K-Nearest Neighbor
- KNN은 지도학습(Supervised Learning)의 가장 간단한 예시입니다.
- 다양한 레이블의 데이터 중에서, 자신과 가까운 데이터를 찾아 자신의 레이블을 결정하는 방식입니다.
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 각 데이터의 위치: 25 X 2 크기에 각각 0 ~ 100
trainData = np.random.randint(0, 100, (25, 2)).astype(np.float32)
# 각 데이터는 0 or 1
response = np.random.randint(0, 2, (25, 1)).astype(np.float32)
# 값이 0인 데이터를 각각 (x, y) 위치에 빨간색으로 칠합니다.
red = trainData[response.label() == 0]
plt.scatter(red[:, 0], red[:, 1], 80, 'r', '^')
# 값이 1인 데이터를 각각 (x, y) 위치에 파란색으로 칠합니다.
blue = trainData[response.label() == 1]
plt.scatter(blue[:, 0], blue[:, 1], 80, 'b', 's')
# (0 ~ 100, 0 ~ 100) 위치의 데이터를 하나 생성해 칠합니다.
newcomer = np.random.randint(0, 100, (1, 2)).astype(np.float32)
plt.scatter(newcomer[:, 0], newcomer[:, 1], 80, 'g', 'o')
knn = cv2.ml.KNearest_create()
knn.train(trainData, cv2.ml.ROW_SAMPLE, response)
ret, results, neighbours, dist = knn.findNearest(newcomer, 3)
# 가까운 3개를 찾고, 거리를 고려하여 자신을 정합니다.
print("result : ", results)
print("neighbours :", neighbours)
print("distance: ", dist)
plt.show()
숫자 이미지 분류하여 저장하기
from google.colab import files
uploaded = files.upload()
위는 Colab에서 실행시 원하는 파일을 업로드 하는 과정이다.
이미지 파일에는 가로 100개, 세로 50개로 총 5000개의 숫자가 있습니다. 각 숫자는 20x20의 해상도를 가지고 있습니다. kNN을 이용하기 위해서 학습하기와 테스트로 나눠서 진행하겠습니다.
숫자 인식 예제 코드 knn_trainer.py
import cv2
import numpy as np
img = cv2.imread('digits.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 세로로 50줄, 가로로 100줄로 사진을 나눕니다.
cells = [np.hsplit(row, 100) for row in np.vsplit(gray, 50)]
x = np.array(cells)
# 각 (20 X 20) 크기의 사진을 한 줄(1 X 400)으로 바꿉니다.
train = x[:, :].reshape(-1, 400).astype(np.float32)
# 0이 500개, 1이 500개, ... 로 총 5,000개가 들어가는 (1 x 5000) 배열을 만듭니다.
k = np.arange(10)
train_labels = np.repeat(k, 500)[:, np.newaxis]
np.savez("trained.npz", train=train, train_labels=train_labels)
학습하기
- 우선 위 이미지를 가로/세로롤 잘라서 하나의 숫자를 배열에 넣습니다.
- 그러면 순서대로 0부터 9까지 각각 500개씩 배열에 넣어집니다.
- 배열값이 0 ~ 499까지는 1, 500 ~ 999까지는 2 ... 4499 ~ 4999는 9를 의미하는 이미지 값이 들어가게 됩니다.
- 그러면 500개씩 Loop를 수행하면서 각 배열에 Label작업을 합니다.
- 그리고 이 결과값을 numpy파일('trained.npz')로 저장을 합니다.
숫자 인식 예제 코드 knn_trainer.py(2)
import matplotlib.pyplot as plt
# 다음과 같이 하나씩 글자를 출력할 수 있습니다.
plt.imshow(cv2.cvtColor(x[0, 0], cv2.COLOR_GRAY2RGB))
plt.show()
# 다음과 같이 하나씩 글자를 저장할 수 있습니다.
cv2.imwrite('test_0.png', x[0, 0])
cv2.imwrite('test_1.png', x[5, 0])
cv2.imwrite('test_2.png', x[10, 0])
cv2.imwrite('test_3.png', x[15, 0])
cv2.imwrite('test_4.png', x[20, 0])
cv2.imwrite('test_5.png', x[25, 0])
cv2.imwrite('test_6.png', x[30, 0])
cv2.imwrite('test_7.png', x[35, 0])
cv2.imwrite('test_8.png', x[40, 0])
cv2.imwrite('test_9.png', x[45, 0])
테스트 글자 넣기
- 위에서 X배열에 넣은 값들을 이용한다.
- 그리고 각각의 숫자에 대해서 이미지 파일을 만들어 저장한다.
테스트
- 학습한 numpy파일을 Load합니다.
- 마우스나 사진으로 찍은 손글씨 숫자를 학습할 때 사용한 동일한 해상도(20X20)으로 Resize를 합니다.
- kNN 알고리즘을 통해서 손글씩 숫자를 인식합니다.
아래는 테스트를 수행하는 예제입니다.
숫자 인식 예제코드 run.py
import cv2
import numpy as np
import glob
FILE_NAME = 'trained.npz'
# 파일로부터 학습 데이터를 불러옵니다.
def load_train_data(file_name):
with np.load(file_name) as data:
train = data['train']
train_labels = data['train_labels']
return train, train_labels
# 손 글씨 이미지를 (20 x 20) 크기로 Scaling합니다.
def resize20(image):
img = cv2.imread(image)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray_resize = cv2.resize(gray, (20, 20))
plt.imshow(cv2.cvtColor(gray_resize, cv2.COLOR_GRAY2RGB))
plt.show()
# 최종적으로는 (1 x 400) 크기로 반환합니다.
return gray_resize.reshape(-1, 400).astype(np.float32)
def check(test, train, train_labels):
knn = cv2.ml.KNearest_create()
knn.train(train, cv2.ml.ROW_SAMPLE, train_labels)
# 가장 가까운 5개의 글자를 찾아, 어떤 숫자에 해당하는지 찾습니다.
ret, result, neighbours, dist = knn.findNearest(test, k=5)
return result
train, train_labels = load_train_data(FILE_NAME)
for file_name in glob.glob('./test_*.png'):
test = resize20(file_name)
result = check(test, train, train_labels)
print(file_name)
print(result)
반응형
'개발자 > Computer Vision' 카테고리의 다른 글
[Computer Vision] OpenCV 기하학적(geometric) 변환 정리(활용 예제 및 그림 설명 포함) (0) | 2020.12.22 |
---|---|
OpenCV Rectangle 함수 에러 해결법 rectangle typeerror: function takes exactly 4 arguments (2 given) (0) | 2020.12.22 |
카메라 Calibration (0) | 2020.10.30 |
[OpenCV] Threshold 처리 (0) | 2020.08.30 |
OpenCV 이미지 연산 (0) | 2020.07.13 |