학습 데이터 영상 정규화 - Normalization
학습 데이터 영상과 테스트 데이터 영상의 위치, 크기, 회전 등의 요소를 정규화 하면 인식 성능을 향상시킬 수 있습니다.
이번 포스팅에서는 입력 영상의 무게 중심이 전체 영상 중앙이 되도록 위치를 정규화하여 성능을 높여보겠습니다.
무게 중심을 이용한 정규화 방법은 흰색 객체의 x좌표, y좌표를 다 더해서 전체 픽셀수로 나누어서 구현합니다.
무게 중심 정규화 이외에도 회전, 기울기, 크기 정규화를 한다면 더 정확도가 높아질 수 있습니다.
이전 포스팅에서 구현해보았던 HOG&SVM 필기체 숫자 인식 프로그램을 위치 정규화로 성능을 높여보겠습니다.
숫자 영상 위치 정규화 예제 코드
예제 코드 출처 : 황선규 박사님 github홈페이지 sunkyoo.github.io/opencv4cvml/
황선규 박사님의 예제코드를 분석하고 실습해보았습니다.
위치 정규화 과정은 cv2.moments로 무게 중심 좌표를 구하고 이를 이용해 affine matrix 생성 후, warpAffine 함수를 이용하여 위치 변환을 합니다.
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)
# 정규화 함수 정의
def norm_digit(img):
# cv2.moments 함수를 이용해서 cx와 cy 계산
m = cv2.moments(img)
cx = m['m10'] / m['m00']
cy = m['m01'] / m['m00']
h, w = img.shape[:2]
# affine 행렬 생성
aff = np.array([[1, 0, w/2 - cx], [0, 1, h/2 - cy]], dtype=np.float32)
# warpAfine
dst = cv2.warpAffine(img, aff, (0, 0))
# dst를 학습과 추론 둘 다 이용합니다.
return dst
# 학습 데이터 & 레이블 행렬 생성
digits = cv2.imread('digits.png', cv2.IMREAD_GRAYSCALE)
if digits is None:
print('Image load failed!')
sys.exit()
h, w = digits.shape[:2]
hog = cv2.HOGDescriptor((20, 20), (10, 10), (5, 5), (5, 5), 9)
print('Descriptor Size:', hog.getDescriptorSize())
cells = [np.hsplit(row, w//20) for row in np.vsplit(digits, h//20)]
cells = np.array(cells)
cells = cells.reshape(-1, 20, 20) # shape=(5000, 20, 20)
desc = []
for img in cells:
img = norm_digit(img) # 정규화
desc.append(hog.compute(img))
train_desc = np.array(desc)
train_desc = train_desc.squeeze().astype(np.float32)
train_labels = np.repeat(np.arange(10), len(train_desc)/10)
# SVM 학습
svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_RBF)
svm.setC(2.5)
svm.setGamma(0.50625)
svm.train(train_desc, cv2.ml.ROW_SAMPLE, train_labels)
#svm.save('svmdigits.yml')
# 사용자 입력 영상에 대해 예측
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 = norm_digit(test_image)
test_desc = hog.compute(test_image).T
_, res = svm.predict(test_desc)
print(int(res[0, 0]))
img.fill(0)
cv2.imshow('img', img)
cv2.destroyAllWindows()
모퉁이에 숫자를 필기하여도 위치 정규화에 의해 제대로 인식하는 것을 확인할 수 있었습니다.
이처럼 항상 여러 개의 데이터를 분석할 때 어떤 식으로 정규화를 할지 고민해야 합니다.
정해져 있는 한 가지 방법이 있는 것이 아니라 많은 방법으로 정규화를 할 수 있습니다.
정규화를 어떻게 하냐에 따라서 머신러닝의 성능이 달라지게 됩니다.
OpenCV 홈페이지와 황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.
'Python > 파이썬 OpenCV 공부' 카테고리의 다른 글
[OpenCV 딥러닝] 미리 학습된 파일을 OpenCV DNN 모듈로 딥러닝 실행하기 - cv2.dnn.readNet (1) | 2020.10.28 |
---|---|
[OpenCV 머신러닝] OpenCV에서 k-means 알고리즘 사용하기 - cv2.kmeans (0) | 2020.10.25 |
[OpenCV 머신러닝] OpenCV에서 HOG 알고리즘을 이용한 SVM 필기체 숫자 인식 (0) | 2020.10.25 |
[OpenCV 머신러닝] OpenCV에서 서포트 벡터 머신(SVM) 사용하기 - cv2.ml.SVM_create, cv2.ml_SVM.trainAuto (0) | 2020.10.24 |
[OpenCV 머신러닝] 서포트 벡터 머신 알고리즘이란? (0) | 2020.10.24 |