모멘트 기반 객체 검출
모멘트(Moments)는 영상의 형태를 표현하는 일련의 실수 값입니다.
모멘트 기반 객체 검출은 두 개의 외곽선, 그레이스케일 영상을 이용하여 모양을 비교하는 방법입니다.
기본적으로 회전, 크기 변환, 대칭, 이동에 강력하며 객체에 변형이 생긴 경우에는 성능이 떨어집니다.
특정 함수 집합과의 상관 관계(correlation) 형태로 계산합니다.
f(x,y)는 입력영상을 의미합니다.
$x^p, y^q$는 이미 정의되어 있는 다항식 함수입니다.
이 두개를 correlation 계산을 해서 실수값 m을 계산합니다.
p와 q를 변경하면서 많개는 몇십개까지 추출하여 영상의 모양 정보를 표현하는 방법입니다.
x와 y 함수를 어떻게 정의하냐에 따라 모멘트를 여러가지 형태로 정의할 수 있습니다.
OpenCV에서는 Geomertic moments, Central moments, Normalized central moments 3가지 기능을 제공합니다.
Geometric moments 는 위의 식 대로 계산한 것입니다.
Central moments는 Geometric moments를 약간 변경해서 객체의 위치가 변경되어도 동일한 값의 특징 벡터를 추출하는 방법입니다.
Normalized central moments는 Central moments를 정규화한것 입니다.
객관적으로 보았을 때 이 3개의 성능이 좋은 편은 아닙니다.
성능이 아주 좋진 않지만 나름대로 원하는 객체를 찾는데 사용할 수 있습니다.
이외에도 Hu의 7개 불변 모멘트 기법도 있습니다.
Hu의 7개 불변 모멘트 - Hu's seven invariant moments
Hu의 7개 불변 모멘트는 Normalized central moments의 수식을 조합해서 어떤 객체가크기 변경, 회전, 대칭, 이동하더라도 모멘트 값은 유지됩니다.
이 방법을 이용하면 어떤 객체가 회전, 이동, 변경 되어도 모멘트는 변화가 없습니다.
객체와 객체의 모양을 비교할 때 이 방법을 이용하면 원하는 객체를 찾을 수 있습니다.
1. 모양 비교 함수 - cv2.matchShapes
내부적으로 휴의 7개 불변 모멘트를 계산해서 두 객체의 모양을 비교한 뒤에 distance 값을 반환합니다.
휴의 7개 불변 모멘트를 이용하여 두 외곽선 또는 영상의 모양을 비교합니다.
따라서 크기, 회전, 이동, 대칭 변환에 강합니다.
하지만 투시변환이나 warp를 한 객체는 좋은 결과를 나타내지 않습니다.
cv2.matchShapes(contour1, contour2, method, parameter) -> retval
• contour1: 첫 번째 외곽선 또는 그레이스케일 영상 - findcontour로 검출한 외곽선 정보를 입력해도 됩니다.
• contour2: 두 번째 외곽선 또는 그레이스케일 영상 - findcontour로 검출한 외곽선 정보를 입력해도 됩니다.
• method: 비교 방법 지정. cv2.CONTOURS_MATCH_I1, cv2.CONTOURS_MATCH_I2, cv2.CONTOURS_MATCH_I3 중 하나 사용.
• parameter: 사용되지 않음. 0 지정.
• retval: 두 외곽선 또는 그레이스케일 영상 사이의 거리(distance)
method 인자
3번째 방법이 정규화를 이용하므로 효과가 가장 좋다고 알려져 있습니다.
3번을 주로 사용합니다.
mi는 1부터 7까지의 휴 모멘트 값을 의미합니다.
a,b는 a객체, b객체를 의미합니다.
두번째 방법은 m1부터 m7까지의 차이값의 절대값을 반환하는 방법입니다.
retval
반환 값은 어떤 두 객체가 비슷하다고 판단하면 작은 값, 다르다고 판단하면 큰 값을 반환합니다.
2. 모멘트 기반 객체 검출 예제 코드
예제 코드 출처 : 황선규 박사님 github홈페이지
객체가 검은색, 배경이 흰색이라 findcontour을 이용할 때 반전해서 이용해야 합니다.
symbols 에서 spades를 찾아내는 것이 목적입니다.
# 영상 불러오기
# 2장의 영상을 사용합니다.
# 객체가 검은색, 배경이 흰색이라 findcontour을 이용할 때 반전해서 이용해야 합니다.
# symbols 에서 spades를 찾아내는 것이 목적입니다.
obj = cv2.imread('spades.png', cv2.IMREAD_GRAYSCALE) # 찾고 싶은거
src = cv2.imread('symbols.png', cv2.IMREAD_GRAYSCALE) # 대상
if src is None or obj is None:
print('Image load failed!')
sys.exit()
# 객체 영상 외곽선 검출
# 이진화, 반전
_, obj_bin = cv2.threshold(obj, 128, 255, cv2.THRESH_BINARY_INV)
# 외곽선 검출, EXTERNAL은 바깥 윤곽선, APPROX_NONE는 모든 외곽선 좌표 구하기
obj_contours, _ = cv2.findContours(obj_bon, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 외곽선 정보를 obj_pts에 저장 (객체 1개)
obj_pts = obj_contours[0]
# 입력 영상 분석
# src 영상에서 객체가 검은색이므로 반전해서 이진화
_, src_bin = cv2.threshold(src, 128, 255, cv2.THRESH_BINARY_INV)
# 모든 정보를 저장
contours, _ = cv2.findContours(src_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 결과 영상
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
# 입력 영상의 모든 객체 영역에 대해서 contours에 있는 각각의 점들의 집합을 검출
for pts in coutours:
if cv2.contourArea(pts) < 1000: # 영역 계산, 노이즈 제거
continue
# 외곽선 사각형 좌표 받아서 그리기
rc = cv2.boundingRect(pts) # 외곽선 좌표 입력하면 사각형 좌표 반환
cv2.rectangle(dst, rc, (255, 0, 0), 1)
# 두 개의 외곽선 정보를 비교해서 모양을 비교하는 용도로 사용
# 이미 변형이 생긴 모양을 비교할 때는 동작이 잘 안됌
# 기본적으로 회전, 크기 변환, 대칭, 이동
dist = cv2.matchSapes(obj_pts, pts, cv2.CONTOURS_MATCH_I3, 0)
# distance 값을 화면에 출력
# spades와 같은 모양은 0.1보다 작은값
cv2.putText(dst, str(round(dist, 4)), (rc[0], re[1] - 3),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 1, cv2.LINE_AA)
# 0.1 보다 작은 건 빨간생으로 사각형
if dist < 0.1:
cv2.rectangle(dst, rc, (0, 0, 255), 2)
cv2.imshow('obj', obj)
cv2.imshow('dst', dst)
cv2.waitKey(0)
황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.
OpenCV 튜토리얼 출처 : docs.opencv.org/4.3.0/d6/d00/tutorial_py_root.html