Template Matching
์ด๋ฏธ์ง ํ ํ๋ฆฟ ๋งค์นญ์ ๋์ ์ด๋ฏธ์ง์์ ์์ ์ด๋ฏธ์ง(ํ ํ๋ฆฟ)๋ฅผ ์ฐพ๋ ๊ธฐ์ ๋ก, ์ปดํจํฐ ๋น์ ๋ถ์ผ์์ ๋ง์ด ์ฌ์ฉ๋๋ ๊ธฐ์ ์ค ํ๋์ด๋ค. OpenCV์์๋ cv2.matchTemplate() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง ํ ํ๋ฆฟ ๋งค์นญ์ ์ํํ ์ ์๋๋ฐ, ์ด ํจ์๋ ์ ๋ ฅ ์ด๋ฏธ์ง์ ํ ํ๋ฆฟ ์ด๋ฏธ์ง๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ์์, ์ ๋ ฅ ์ด๋ฏธ์ง์์ ํ ํ๋ฆฟ๊ณผ ๊ฐ์ฅ ์ ์ฌํ ๋ถ๋ถ์ ์ฐพ์ ๋ฐํํ๋ค.
๋ฅ๋ฌ๋์ ์ฌ์ฉํ ๋ฐฉ๋ฒ์ฒ๋ผ ๊ฐ์ฒด์ deformation์ด ์๋ ๊ฒฝ์ฐ์๋ ์ ๋งค์นญ๋๋ ์๊ณ ๋ฆฌ์ฆ์ ์๋์ง๋ง ํ ํ๋ฆฟ ์ด๋ฏธ์ง์ ์์ฃผ ์ ์ฌํ ๋ถ๋ถ์ด ์ ๋ ฅ ์ด๋ฏธ์ง์ ์๋ ๊ฒฝ์ฐ์๋ ์ฌ์ฉํ๊ธฐ ์ข์ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
๊ฐ์ฅ ํฐ ๋จ์ ์ opencv์ ํ ํ๋ฆฟ ๋งค์นญ์ ํ ํ๋ฆฟ ์ด๋ฏธ์ง๋ก ๋์ ์ด๋ฏธ์ง๋ฅผ ์ฌ๋ผ์ด๋ฉ ํ๋๋ฐ, ์ด๋ ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฌ์ด์ฆ๋ฅผ ๋ฐ๋ก ์ง์ ํ ์ ์๊ณ ์ ๋ ฅ ์ด๋ฏธ์ง์ ํ ํ๋ฆฟ ์ด๋ฏธ์ง์ ํฌ๊ธฐ์ ๋ฐ๋ผ ์๋์ผ๋ก ๊ฒฐ์ ๋๋ค๋ ๊ฒ์ด๋ค. ๋๋ฌธ์ ํ ํ๋ฆฟ ์ด๋ฏธ์ง์ ์ ๋ ฅ ์ด๋ฏธ์ง์ ๋น์จ์ ์์์ ์... ์กฐ์ ํด์ผ ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
OpenCV ํ ํ๋ฆฟ ๋งค์นญ
- cv2.matchTemplate() ํจ์๋ ๋ค์๊ณผ ๊ฐ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ๋๋ค.
- image: ๋์ ์ด๋ฏธ์ง
- template: ์ฐพ๊ณ ์ ํ๋ ์์ ์ด๋ฏธ์ง(ํ ํ๋ฆฟ)
- method: ๋งค์นญ ๋ฐฉ๋ฒ
- cv2.TM_CCOEFF: ์๊ด๊ด๊ณ ๊ณ์๋ฅผ ์ด์ฉํ ๋งค์นญ
- cv2.TM_CCOEFF_NORMED: ์ ๊ทํ๋ ์๊ด๊ด๊ณ ๊ณ์๋ฅผ ์ด์ฉํ ๋งค์นญ
- cv2.TM_CCORR: ํฝ์ ํฉ์ ์ด์ฉํ ๋งค์นญ
- cv2.TM_CCORR_NORMED: ์ ๊ทํ๋ ํฝ์ ํฉ์ ์ด์ฉํ ๋งค์นญ
- cv2.TM_SQDIFF: ์ ๊ณฑ ์ฐจ์ด ํฉ์ ์ด์ฉํ ๋งค์นญ
- cv2.TM_SQDIFF_NORMED: ์ ๊ทํ๋ ์ ๊ณฑ ์ฐจ์ด ํฉ์ ์ด์ฉํ ๋งค์นญ
cv2.matchTemplate() ํจ์๋ ๋งค์นญ ๊ฒฐ๊ณผ๋ฅผ ํํธ๋งต์ผ๋ก ๋ฐํํ๋ค. ํํธ๋งต์ ๋์ ์ด๋ฏธ์ง์ ๊ฐ ํฝ์ ๋ง๋ค ํ ํ๋ฆฟ๊ณผ์ ๋งค์นญ ์ ๋๋ฅผ ๋ํ๋ด๋ ๊ฐ์ ๊ฐ์ง๋ ์ด๋ฏธ์ง๋ก ์ด ํํธ๋งต์์ ๊ฐ์ฅ ๊ฐ์ด ํฐ ์์น๋ฅผ ์ฐพ์ผ๋ฉด ๋์ ์ด๋ฏธ์ง์์ ํ ํ๋ฆฟ๊ณผ ๊ฐ์ฅ ์ผ์นํ๋ ์์น๋ฅผ ์ฐพ์ ์ ์๋ค. ๋ํ, OpenCV์์๋ cv2.minMaxLoc() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํํธ๋งต์์ ์ต๋๊ฐ, ์ต์๊ฐ์ ์์น๋ฅผ ์ฝ๊ฒ ์ฐพ์ ์ ์๋ค.
ํ ํ๋ฆฟ ๋งค์นญ ์์
- ์ค์ฌ์นด์ ์ฌํ ๊ฐ์ ์ดฌ์ํ ๋ํค๋ณด๋ฆฌ ์ฌ์ง์์ ๊ธ๋ฆฌ์ฝ์์ ์ผ๊ตด๋ง ํฌ๋กญํด์ ํ ํ๋ฆฟ ์ด๋ฏธ์ง๋ก ์ฌ์ฉํ๊ณ , ๊ตฌ๊ธ์์ ์ฐพ์ ๋ํค๋ณด๋ฆฌ ์ฌ์ง์์ ๊ธ๋ฆฌ์ฝ์ ์ผ๊ตด์ ์ฐพ๋ ์์
- ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฌ์ด์ฆ๊ฐ ์ ๋ ฅ ์ด๋ฏธ์ง์ ํ ํ๋ฆฟ ์ด๋ฏธ์ง์ ์ฌ์ด์ฆ์ ์ํด ์๋์ผ๋ก ๊ฒฐ์ ๋๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ๋ฒ์ ์๋ ๋์ ๊ฐ์ฅ ์ ์ ํ ๋น์จ์ ์ฐพ์ ๊ฒฐ๊ณผ์ด๋ค (์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฌ์ด์ฆ ์กฐ์ ์ ์ํด ์ ๋ ฅ ์ด๋ฏธ์ง ๋ณ๋ก ํ ํ๋ฆฟ ์ด๋ฏธ์ง๋ฅผ ๋ฆฌ์ฌ์ด์ง)
import cv2
image_list = [cv2.imread('๊ธ๋ฆฌ์ฝ์1.jpg'), cv2.imread('๊ธ๋ฆฌ์ฝ์2.webp'), cv2.imread('๊ธ๋ฆฌ์ฝ์3.jpg')]
template = cv2.imread('๊ธ๋ฆฌ์ฝ์๋จธ๋ฆฌ.png')
template_list = [cv2.resize(template, (40, 40)), cv2.resize(template, (20,20)), cv2.resize(template, (80,80))]
cv2.imshow('template', template)
for i in range(len(image_list)):
img_draw = image_list[i].copy()
template_image = template_list[i]
th, tw = template_image.shape[:2]
# ํ
ํ๋ฆฟ ๋งค์นญ
res = cv2.matchTemplate(image_list[i], template_image, cv2.TM_CCOEFF_NORMED)
# ํํธ๋งต์์์ ์ต์๊ฐ, ์ต๋๊ฐ ๊ตฌํ๊ธฐ
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = max_loc
match_val = max_val
# ๋งค์นญ๋ ์์ญ ํ์
bottom_right = (top_left[0] + tw, top_left[1] + th)
cv2.rectangle(img_draw, top_left, bottom_right, (0,0,255),2)
cv2.putText(img_draw, str(match_val), top_left, cv2.FONT_HERSHEY_PLAIN, 2,(0,255,0), 1, cv2.LINE_AA)
cv2.imshow('output', img_draw)
cv2.waitKey(0)
cv2.destroyAllWindows()
๊ฒฐ๊ณผ ์ด๋ฏธ์ง
- ํ ํ๋ฆฟ ์ด๋ฏธ์ง : ๊ธ๋ฆฌ์ฝ์ ์ผ๊ตด
- ์ ๋ ฅ ์ด๋ฏธ์ง : ๊ตฌ๊ธ์์ ๊ฒ์ํ ๋ํค๋ณด๋ฆฌ
# ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฌ์ด์ฆ๊ฐ ์ต์ ํ ๋ ๊ฒฝ์ฐ (ํ ํ๋ฆฟ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง O)
# ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฌ์ด์ฆ๊ฐ ์ต์ ํ ๋์ง ์์ ๊ฒฝ์ฐ (ํ ํ๋ฆฟ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง X)
์ต์ ํ๋ ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฌ์ด์ฆ์์ ํ ํ๋ฆฟ ๋งค์นญ ์ค์ฝ์ด ๋๊ธฐ ๋๋ฌธ์ ๋ค์ํ ํฌ๊ธฐ์ ์ฌ๋ผ์ด๋ฉ ์๋์ฐ๋ฅผ ์ํํ๋ฉด์ ๊ฐ์ฅ ๋์ ์ค์ฝ์ด๋ฅผ ์ฐพ๋๋ค๋ฉด ์ ์ ํ ์๋์ฐ ์ฌ์ด์ฆ๋ฅผ ์ฐพ์ ์ต์ ์ ํ ํ๋ฆฟ ๋งค์นญ์ ์ํํ ์๋ ์์ง ์์๊น?