템플릿 매칭(Template matching)이란?
- 입력 영상에서(작은크기의) 템플릿 영상과 일치하는 부분을 찾는 기법
- 템플릿 : 찾을 대상이 되는 작은 영상. 패치(patch).
템플릿 매칭은 노이즈와 밝기 변화에 강하다. CCOFF 연산을 이용하여 밝기 보정을 해서 매칭하기 때문이다. 가우시안 노이즈의 경우에 correlation 방법이 잘 동작한다. 다만 기본적으로 같은 위치에 있는 픽셀 값들을 곱하고 더해서 유사도를 판단하는 방식이기 때문에 회전, 크기변환이 심하게 일어난 경우 찾고자하는 템플릿 영상의 위치를 제대로 찾을 수 없다. 다른 방법으로 키포인트 로컬 피쳐 매칭, 로컬 피쳐 포인트 매칭을 생각해볼 수 있다.
템플릿 동작 방식
필터링에서 동작하던 방식이랑 유사하다.
- 템플릿 영상을 입력 영상의 좌측 상단에서 시작해서 전체 영역을 스캔
- 템플릿 영상과 입력 영산간 유사도와 비유사도를 실수 형태의 행렬로 반환(거리의 개념으로 반환)
- 유사도와 비유사도를 조사하는지 선택에 따라 최댓값, 최솟값을 중 어떤 값을 봐야하는지 결정
- 반환값 행렬은 입력 영상보다 한픽셀 작은 형태로 유사도맵 또는 비유사도맵을 행렬의 형태로 출력
- 최댓값, 최솟값 위치를 마킹
✔︎ 템플릿 매칭 함수 - cv2.matchTemplate
result = cv2.matchTemplate(image, templ, method, result=None, mask=None)
- image : 입력 영상. 8비트 또는 32비트.
- templ : 템플릿 영상. image보다 같거나 작은 크기, 같은 타입.
- method : 비교 방법. cv2.TM_으로 시작하는 플래그 지정. (6가지)
- result : 비교 결과 행렬. numpy.ndarray. dtype=numpy.float32.
image의 크기가 W X H 이고, templ의 크기가 w X h 이면 result 크기는 (W - w + 1) X (H - h +1).
(가상의 픽셀이 가정되지 않기 때문)
입력 영상과 템플릿 영상의 크기를 동일하게 하면 1X1 행렬이 나온다. 이 행렬이 유사도 또는 비유사도를 판단하는 행렬이 된다.
템플릿 매칭 방법 - method 인자
method 인자는 유사도를 계산할건지 비유사도를 계산할 건지를 플래그로 지정할 수 있다.
템플릿 매칭 방법 비교
- CCORR 방식은 두 영상파일의 비교 부분 픽셀 값을 곱한 것으로 큰 값일 수록 비슷하다고 판단하므로 입력 영상의 밝은 부분은 무조건 큰 값을 띠게 되어 비슷하다고 판단됨
- 이외의 방식은 모두 제대로 템플릿 매칭에 성공
유사도 및 비유사도 행렬 그레이스케일로 표현
- 템플릿 매칭 함수의 결과값 (유사도 및 비유사도 값) 행렬을 그레이스케일로 변환
- SQDIFF 방식은 비유사도 방식이므로 가장 비슷한 부분에 0에 가까운 값을 나타냄
- 나머지는 유사도 방식이기 때문에 비슷할 수록 밝은 점으로 나타남
💬 탬플릿 매칭 예제
import sys
import numpy as np
import cv2
# 입력 영상 & 템플릿 영상 불러오기
src = cv2.imread('circuit.bmp', cv2.IMREAD_GRAYSCALE)
templ = cv2.imread('crystal.bmp', cv2.IMREAD_GRAYSCALE)
if src is None or templ is None:
print('Image load failed!')
sys.exit()
# 입력 영상 밝기 50증가, 가우시안 잡음(sigma=10) 추가
noise = np.zeros(src.shape, np.int32)
cv2.randn(noise, 50, 10)
src = cv2.add(src, noise, dtype=cv2.CV_8UC3)
# 템플릿 매칭 & 결과 분석
res = cv2.matchTemplate(src, templ, cv2.TM_CCOEFF_NORMED)
res_norm = cv2.normalize(res, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
_, maxv, _, maxloc = cv2.minMaxLoc(res)
print('maxv:', maxv)
print('maxloc:', maxloc)
# 매칭 결과를 빨간색 사각형으로 표시
th, tw = templ.shape[:2]
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
cv2.rectangle(dst, maxloc, (maxloc[0] + tw, maxloc[1] + th), (0, 0, 255), 2)
# 결과 영상 화면 출력
cv2.imshow('res_norm', res_norm)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
오른쪽의 회로 영상 파일에서 왼쪽의 크리스탈을 검출
⬇︎
'OpenCV' 카테고리의 다른 글
[OpenCV with Python] 영상 분할과 객체 검출 : 캐스케이드 분류기 - 얼굴 검출 (0) | 2022.02.05 |
---|---|
[OpenCV with Python] 영상 분할과 객체 검출 : 템플릿 매칭2 - 인쇄체 숫자 인식 (0) | 2022.02.04 |
[OpenCV with Python] 영상 분할과 객체 검출 : 모멘트 기반 객체 검출 (0) | 2022.02.04 |
[OpenCV with Python] 영상 분할과 객체 검출 : 그랩컷 - cv2.grabCut (0) | 2022.02.04 |
[OpenCV with Python] 이진 영상 처리 : 다양한 외곽선 함수 (0) | 2022.02.04 |