728x90
반응형
< Template Matching >
이번 장에서는
- 템플릿 매칭을 이용하여 이미지 내에서 객체를 찾기
- cv2.matchTemplate(), cv2.minMaxLoc() 함수
에 대해서 배울 것이다!
Theory
탬플릿 매칭은 커다란 이미지 내에서 모형 이미지의 위치를 찾고 탐색하는 방법이다. OpenCV는 이를 위해 cv2.matchTemplate()를 제공한다. 2D 컨볼루션처럼, 간단하게 템플릿 이미지가 입력 이미지 위를 지나다니면서 입력 이미지의 템플릿과 조각을 비교하는 것이다. 여러 비교 방법들이 OpenCV에 구현되어있다. 이는 흑백 스케일의 이미지를 반환하고, 각 픽셀은 픽셀의 인접 영역이 템플릿과 얼마나 일치하는지 나타낸다.
만약 입력 이미지의 크기가 (WxH), 템플릿 이미지의 크기가 (wxh)라면, 결과 이미지의 크기는 (W-w+1,H-h+1)일 것이다. 결과를 얻었다면, cv2.minMaxLoc() 함수를 사용하여 최대/최솟값을 찾을 수 있다.
** cv2.TM_SQDIFF를 비교 방법으로 사용한다면, 최솟값은 최적의 매칭을 제공한다.
Template Matching in OpenCV
여기 예제를 보자. 슈퍼마리오에 나오는 아이템 박스사진이다. 템플릿을 아래처럼 만들었다.
박스사진1
모든 비교 방법들을 시도해볼 것이고 결과는 아래에서 확인하자!
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
img = cv2.imread('./images/mario.jpg',0)
img2 = img.copy()
template = cv2.imread('./images/mariobox.jpg',0)
w,h = template.shape[::-1]
# 비교를 위한 리스트에 있는 모든 6가지 방법
methods = ['cv2.TM_CCOEFF','cv2.TM_CCOEFF_NORMED','cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED','cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED']
for i,meth in enumerate(methods):
img = img2.copy()
method = eval(meth)
# 템플릿 매칭 적용하기
res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc,max_loc = cv2.minMaxLoc(res)
# 만약 방법이 TM_SQDIFF나 TM_SQDIFF_NORMED라면, 최소를 취한다
if method is [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img,top_left,bottom_right,255,2)
plt.figure(figsize=(12,8))
plt.subplot(121), plt.imshow(res,cmap='gray')
plt.title("Matching Result"), plt.axis('off')
plt.subplot(122), plt.imshow(img,cmap='gray')
plt.title("Detected Point"), plt.axis('off')
plt.suptitle(meth)
plt.savefig('total_res{0}.jpg'.format(i))
plt.show()
아래 결과를 보자
cv2.TM_CCORR이 예상처럼 좋은 결과를 못보여주는 것을 볼 수 있다.
Template Matching with Multiple Objects
이전에는 동전박스를 하나만 찾았었다. 다수의 물체를 찾는다면 cv2.minMaxLoc()는 적합하지 않다.(위치를 제공X) 그 경우, 임계값을 사용할 것이다. 그래서 이 예제에서는 마리오의 동전 박스를 다 찾아볼 것이다.
import cv2
import numpy as np
import matplotlib.pyplot as plt
img_rgb = cv2.imread('./images/mario.jpg')
img_gray = cv2.cvtColor(img_rgb,cv2.COLOR_BGR2GRAY)
template = cv2.imread('./images/mariobox.jpg',0)
w,h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res>threshold)
for pt in zip(*loc[::-1]):
cv2.rectangle(img_rgb,pt,(pt[0]+w,pt[1]+h),(0,255,0),2)
cv2.imwrite('mario_res.png',img_rgb)
초록색으로 표시가 된 부분을 보면 제대로 찾았음을 알 수 있다.
728x90
반응형