Python/파이썬 OpenCV 공부

[OpenCV 머신러닝] 학습 데이터 영상을 위치 정규화하여 성능 높이기 - cv2.moments, cv2.warpAffine

AI 꿈나무 2020. 10. 25. 21:40
반응형

학습 데이터 영상 정규화 - Normalization

 학습 데이터 영상과 테스트 데이터 영상의 위치, 크기, 회전 등의 요소를 정규화 하면 인식 성능을 향상시킬 수 있습니다.

 

 이번 포스팅에서는 입력 영상의 무게 중심이 전체 영상 중앙이 되도록 위치를 정규화하여 성능을 높여보겠습니다.

 

 무게 중심을 이용한 정규화 방법은 흰색 객체의 x좌표, y좌표를 다 더해서 전체 픽셀수로 나누어서 구현합니다.

 무게 중심 정규화 이외에도 회전, 기울기, 크기 정규화를 한다면 더 정확도가 높아질 수 있습니다.

 

 이전 포스팅에서 구현해보았던 HOG&SVM 필기체 숫자 인식 프로그램을 위치 정규화로 성능을 높여보겠습니다.

 

[OpenCV 머신러닝] OpenCV에서 HOG 알고리즘을 이용한 SVM 필기체 숫자 인식

HOG & SVM 필기체 숫자 인식  픽셀값을 이용하여 SVM을 학습시키는 것보다 HOG 알고리즘으로 추출한 특징 벡터를 이용하여 SVM을 학습시키는 것이 정확도가 더 뛰어납니다.  이번 포스팅에서는 HOG

deep-learning-study.tistory.com

 

숫자 영상 위치 정규화 예제 코드

 예제 코드 출처 :  황선규 박사님 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로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.

반응형