๐ ๊ณต๋ถํ๋ ์ง์ง์ํ์นด๋ ์ฒ์์ด์ง?
[v0.27]์์์ฒ๋ฆฌ_์ด๋ฏธ์ง ๋งค์นญ (Image Matching) ๋ณธ๋ฌธ
[v0.27]์์์ฒ๋ฆฌ_์ด๋ฏธ์ง ๋งค์นญ (Image Matching)
์ง์ง์ํ์นด 2022. 1. 13. 00:32220113 ์์ฑ
<๋ณธ ๋ธ๋ก๊ทธ๋ ๊ทํ์ด ์์ฌ๋์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํด์ ๊ณต๋ถํ๋ฉฐ ์์ฑํ์์ต๋๋ค>
1. ์ด๋ฏธ์ง ๋งค์นญ(Image Matching)
: ์๋ก ๋ค๋ฅธ ๋ ์ด๋ฏธ์ง๋ฅผ ๋น๊ตํด์ ์ง์ด ๋ง๋ ๊ฐ์ ํํ์ ๊ฐ์ฒด๊ฐ ์๋์ง ์ฐพ์๋ด๋ ๊ธฐ์
: ์ด๋ฏธ์ง์์ ๊ฐ์ฒด๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ์ ์ด๋ฏธ์ง์์ ์๋ฏธ ์๋ ํน์ง๋ค์ ์ ์ ํ ์ซ์๋ก ๋ณํํ๊ณ
๊ทธ ์ซ์๋ค์ ์๋ก ๋น๊ตํด์ ์ผ๋ง๋ ๋น์ทํ์ง ํ๋จํ๋ ๊ฒ
: ๋ ์ด๋ฏธ์ง ๊ฐ ์ ์ฌ๋๋ฅผ ์ธก์
: ํน์ง์ ๋ํํ ์ ์๋ ์ซ์๋ฅผ ํน์ง ๋ฒกํฐ ํน์ ํน์ง ๋์คํฌ๋ฆฝํฐ
2. ํ๊ท ํด์ ๋งค์นญ(Average Hash Matching)
: ์ด๋ฏธ์ง ๋งค์นญ์ ํ ๊ธฐ๋ฒ
: ํน์ง ๋ฒกํฐ๋ฅผ ๊ตฌํ๊ธฐ ์ํด ํ๊ท ๊ฐ์ ์ฌ์ฉ
: ๋ ์ด๋ฏธ์ง ์ฌ์ด์์ ๋น์ทํ ๊ทธ๋ฆผ์ ์ฐพ๊ธฐ ์ ์ ์ฐพ๊ณ ์ ํ๋ ๊ทธ๋ฆผ์ ํน์ง ๋ฒกํฐ๋ฅผ ๊ตฌํ๋ ๋ฐฉ๋ฒ
1) ์ด๋ฏธ์ง๋ฅผ ๊ฐ๋ก ์ธ๋ก ๋น์จ๊ณผ ๋ฌด๊ดํ๊ฒ ํน์ ํ ํฌ๊ธฐ๋ก ์ถ์
2) ํฝ์ ์ ์ฒด์ ํ๊ท ๊ฐ์ ๊ตฌํด์ ๊ฐ ํฝ์ ์ ๊ฐ์ด ํ๊ท ๋ณด๋ค ์์ผ๋ฉด 0, ํฌ๋ฉด 1๋ก ๋ฐ๊พธ๊ธฐ
3) ๋๋ 1๋ก๋ง ๊ตฌ์ฑ๋ ๊ฐ ํฝ์ ๊ฐ์ 1ํ 1์ด๋ก ๋ณํ (์ด๋ ํ ๊ฐ์ 2์ง์ ์ซ์๋ก ๋ณด๊ธฐ)
: ๋น๊ต๋ฅผ ํ๊ณ ์ ํ๋ ๋ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ํฌ๊ธฐ๋ก ์ถ์
: 0๊ณผ 1์ ๊ฐ์๋ ๋์ผ (2์ง์๋ก ํํํ์ ๋ ๋นํธ ๊ฐ์๊ฐ ๊ฐ๋ค)
# ๊ถ์ด์ ํ๊ท ํด์๋ก ๋ณํ
import cv2
#์์ ์ฝ์ด์ ๊ทธ๋ ์ด ์ค์ผ์ผ๋ก ๋ณํ
img = cv2.imread('img/pistol.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 8x8 ํฌ๊ธฐ๋ก ์ถ์ ---โ
gray = cv2.resize(gray, (16,16))
# ์์์ ํ๊ท ๊ฐ ๊ตฌํ๊ธฐ ---โก
avg = gray.mean()
# ํ๊ท ๊ฐ์ ๊ธฐ์ค์ผ๋ก 0๊ณผ 1๋ก ๋ณํ ---โข
bin = 1 * (gray > avg)
print(bin)
# 2์ง์ ๋ฌธ์์ด์ 16์ง์ ๋ฌธ์์ด๋ก ๋ณํ ---โฃ
dhash = []
for row in bin.tolist():
s = ''.join([str(i) for i in row])
dhash.append('%02x'%(int(s,2)))
dhash = ''.join(dhash)
print(dhash)
cv2.namedWindow('pistol', cv2.WINDOW_GUI_NORMAL)
cv2.imshow('pistol', img)
cv2.waitKey(0)
1) ์ด๋ฏธ์ง๋ฅผ 16 x 16 ์ฌ์ด์ฆ๋ก ์กฐ์
2) ํฝ์ ์ ์ ์ฒด ํ๊ท ๊ฐ์ ๊ตฌํ๊ณ ๊ทธ ํ๊ท ๊ฐ๋ณด๋ค ํฐ ํฝ์ ์ 1, ์์ ํฝ์ ์ 0์ผ๋ก ๋ฐ๊พธ๊ธฐ
3) ๊ฒฐ๊ณผ, 0๊ณผ 1๋ก ๊ตฌ์ฑ๋ ๋ฐฐ์ด
4) 0์ผ๋ก ๊ตฌ์ฑ๋ ๋ถ๋ถ์ด ๊ถ์ด ๋ชจ์์ ๋ฎ์์
5) ๊ถ์ด์ ๊ฒ์์์ด๋ฏ๋ก ํฝ์ ๊ฐ์ด 0์ ๊ฐ๊น๊ณ , ๋ฐฐ๊ฒฝ์ ํฝ์ ๊ฐ์ด 255์ ๊ฐ๊น๋ค
6) ์ ์ฒด ํฝ์ ์ ํ๊ท ๊ฐ๋ณด๋ค ์์ ๋ถ๋ถ์ 0, ํฐ ๋ถ๋ถ์ 1๋ก ๋ฐ๋ ๊ฒ
- ๋ค๋ฅธ ์ด๋ฏธ์ง์ ๊ฒ๊ณผ ๋น๊ตํด์ ์ผ๋ง๋ ๋น์ทํ์ง๋ฅผ ์์๋ด์ผ ํ๋ค
- ๋น์ทํ ์ ๋๋ฅผ ์ธก์ ํ๋ ๋ฐฉ๋ฒ
- ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ(Euclidian distance)
- ๋ ๊ฐ์ ์ฐจ์ด๋ก ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐ
- ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ๊ฐ ์์์๋ก ๋ ์๋ ๋น์ทํ ์
- 5์ ๋น๊ตํ ๊ฐ์ผ๋ก 1๊ณผ 7์ด ์๋ค๋ฉด 5์ 1์ ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ๋ 5-1 = 4, 5์ 7์ ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ๋ 7-5 = 2
- ํด๋ฐ ๊ฑฐ๋ฆฌ(Hamming distance)
- ๋ ๊ฐ์ ๊ธธ์ด๊ฐ ๊ฐ์์ผ ๊ณ์ฐ
- ๋ ์์ ๊ฐ์ ์๋ฆฌ ๊ฐ ์ค ์๋ก ๋ค๋ฅธ ๊ฒ์ด ๋ช ๊ฐ์ธ์ง๋ฅผ ํ๋จํ์ฌ ์ ์ฌ๋๋ฅผ ๊ณ์ฐ
- 12345์ ๋น๊ตํ ๊ฐ์ผ๋ก 12354์ 92345๊ฐ ์์ ๋ 12345์ 12354์ ๋ง์ง๋ง ์๋ฆฌ๊ฐ 45์ 54๋ก ๋ค๋ฅด๋ฏ๋ก ํด๋ฐ ๊ฑฐ๋ฆฌ๋ 2์ ๋๋ค. ๋ฐ๋ฉด 12345์ 92345๋ 1๊ณผ 9 ํ์๋ฆฌ๋ง ๋ค๋ฅด๋ฏ๋ก ํด๋ฐ ๊ฑฐ๋ฆฌ๋ 1
: ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ๋ ์๋ฆฟ์๊ฐ ๋์์๋ก ์ฐจ์ด๊ฐ ํฌ๊ฒ ๋ฒ์ด์ง๋ค
: ํด๋ฐ ๊ฑฐ๋ฆฌ๋ ๋ช ๊ฐ์ ์ซ์๊ฐ ๋ค๋ฅธ๊ฐ๋ง์ ๊ณ ๋ ค
: ์ด๋ฏธ์ง๋ฅผ ๋น๊ตํ๋๋ฐ ํ๊ท ํด์ ์ซ์์ ํฌ๊ธฐ๊ฐ ์ค์ํ๊ธฐ๋ณด๋ค๋ ์ผ๋ง๋ ์ ์ฌํ ์๋ฆฟ์๊ฐ ๋ง์์ง๊ฐ ๋ ์ค์
# ์ฌ๋ฌผ ์ด๋ฏธ์ง ์ค์์ ๊ถ์ด ์ด๋ฏธ์ง ์ฐพ๊ธฐ
import cv2
import numpy as np
import glob
# ์์ ์ฝ๊ธฐ ๋ฐ ํ์
img = cv2.imread('img/pistol.jpeg')
cv2.imshow('query', img)
# ๋น๊ตํ ์์๋ค์ด ์๋ ๊ฒฝ๋ก ---โ
search_dir = 'img/101_ObjectCategories'
# ์ด๋ฏธ์ง๋ฅผ 16x16 ํฌ๊ธฐ์ ํ๊ท ํด์ฌ๋ก ๋ณํ ---โก
def img2hash(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.resize(gray, (16, 16))
avg = gray.mean()
bi = 1 * (gray > avg)
return bi
# ํด๋ฐ๊ฑฐ๋ฆฌ ์ธก์ ํจ์ ---โข
def hamming_distance(a, b):
a = a.reshape(1,-1)
b = b.reshape(1,-1)
# ๊ฐ์ ์๋ฆฌ์ ๊ฐ์ด ์๋ก ๋ค๋ฅธ ๊ฒ๋ค์ ํฉ
distance = (a !=b).sum()
return distance
# ๊ถ์ด ์์์ ํด์ฌ ๊ตฌํ๊ธฐ ---โฃ
query_hash = img2hash(img)
# ์ด๋ฏธ์ง ๋ฐ์ดํ ์
๋๋ ํ ๋ฆฌ์ ๋ชจ๋ ์์ ํ์ผ ๊ฒฝ๋ก ---โค
img_path = glob.glob(search_dir+'/**/*.jpg')
for path in img_path:
# ๋ฐ์ดํ ์
์์ ํ๊ฐ ์ฝ์ด์ ํ์ ---โฅ
img = cv2.imread(path)
cv2.imshow('searching...', img)
cv2.waitKey(5)
# ๋ฐ์ดํ ์
์์ ํ๊ฐ์ ํด์ ---โฆ
a_hash = img2hash(img)
# ํด๋ฐ ๊ฑฐ๋ฆฌ ์ฐ์ถ ---โง
dst = hamming_distance(query_hash, a_hash)
if dst/256 < 0.25: # ํด๋ฐ๊ฑฐ๋ฆฌ 25% ์ด๋ด๋ง ์ถ๋ ฅ ---โจ
print(path, dst/256)
cv2.imshow(path, img)
cv2.destroyWindow('searching...')
cv2.waitKey(0)
cv2.destroyAllWindows()
- ๊ถ์ด ์ด๋ฏธ์ง๋ฅผ ๋น๊ตํ์ฌ ๊ถ์ด๊ณผ ์ ์ฌํ ์ด๋ฏธ์ง๋ฅผ ์ฐพ์๋ด๊ธฐ
- ๊ถ์ด์ ํ๊ท ํด์์ ๋น๊ตํ์ฌ ํด๋ฐ ๊ฑฐ๋ฆฌ๊ฐ 25% ์ด๋ด์ธ ์ด๋ฏธ์ง๋ฅผ ์ถ๋ ฅ
- ๋ง์๊ฒฝ ๋์๋ฝ,,!!
3. ํ ํ๋ฆฟ ๋งค์นญ (Template Matching)
: ํน์ ๋ฌผ์ฒด์ ๋ํ ์ด๋ฏธ์ง๋ฅผ ์ค๋นํด ๋๊ณ ๊ทธ ๋ฌผ์ฒด๊ฐ ํฌํจ๋์ด ์์ ๊ฒ์ด๋ผ๊ณ
์์ํ ์ ์๋ ์ด๋ฏธ์ง์ ๋น๊ตํ์ฌ ๋งค์นญ ๋๋ ์์น๋ฅผ ์ฐพ๋ ๊ฒ
: ๋ฏธ๋ฆฌ ์ค๋นํ ์ด๋ฏธ์ง๋ฅผ ํ ํ๋ฆฟ ์ด๋ฏธ์ง
: ํ ํ๋ฆฟ ์ด๋ฏธ์ง๋ ๋น๊ตํ ์ด๋ฏธ์ง๋ณด๋ค ํฌ๊ธฐ๊ฐ ํญ์ ์์์ผํจ
result = cv2.matchTemplate(img, templ, method, result, mask)
: ์ ๋ ฅ ์ด๋ฏธ์ง(img)์์ ํ ํ๋ฆฟ ์ด๋ฏธ์ง(templ)๋ฅผ ์ฌ๋ผ์ด๋ฉํ๋ฉด์ ์ฃผ์ด์ง ๋ฉ์๋์ ๋ฐ๋ผ ๋งค์นญ์ ์ํ
: ๋ฐํ ๊ฐ์ (W - w + 1) x (H - h + 1) ํฌ๊ธฐ์ 2์ฐจ์ ๋ฐฐ์ด
: ์ด ๋ฐฐ์ด์ ์ต๋, ์ต์ ๊ฐ์ ๊ตฌํ๋ฉด ์ํ๋ ์ต์ ์ ๋งค์นญ ๊ฐ๊ณผ ๋งค์นญ์ ์ ๊ตฌํ๋ค
- img : ์
๋ ฅ ์ด๋ฏธ์ง
- templ : ํ
ํ๋ฆฟ ์ด๋ฏธ์ง
- method : ๋งค์นญ ๋ฉ์๋
- cv2.TM_SQDIFF : ์ ๊ณฑ ์ฐจ์ด ๋งค์นญ, ์๋ฒฝ ๋งค์นญ : 0, ๋์ ๋งค์นญ : ํฐ ๊ฐ
- cv2.TM_SQDIFF_NORMED : ์ ๊ณฑ ์ฐจ์ด ๋งค์นญ์ ์ ๊ทํ
- cv2.TM_CCORR : ์๊ด๊ด๊ณ ๋งค์นญ, ์๋ฒฝ ๋งค์นญ : ํฐ ๊ฐ, ๋์ ๋งค์นญ : 0
- cv2.TM_CCORR_NORMED : ์๊ด๊ด๊ณ ๋งค์นญ์ ์ ๊ทํ
- cv2.TM_CCOEFF : ์๊ด๊ณ์ ๋งค์นญ, ์๋ฒฝ ๋งค์นญ : 1, ๋์ ๋งค์นญ : -1
- cv2.TM_CCOEFF_NORMED : ์๊ด๊ณ์ ๋งค์นญ์ ์ ๊ทํ
- result(optional) : ๋งค์นญ ๊ฒฐ๊ณผ, (W - w + 1) x (H - h + 1) ํฌ๊ธฐ์ 2์ฐจ์ ๋ฐฐ์ด
[์ฌ๊ธฐ์ W, H๋ ์ ๋ ฅ ์ด๋ฏธ์ง์ ๋๋น์ ๋์ด, w, h๋ ํ ํ๋ฆฟ ์ด๋ฏธ์ง์ ๋๋น์ ๋์ด]
- mask(optional) : TM_SQDIFF, TM_CCORR_NORMED์ธ ๊ฒฝ์ฐ ์ฌ์ฉํ ๋ง์คํฌ
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(src, mask)
: ์ ๋ ฅ ๋ฐฐ์ด์์์ ์ต์, ์ต๋ ๊ฐ๋ฟ๋ง ์๋๋ผ ์ต์ ๊ฐ, ์ต๋ ๊ฐ์ ์ขํ๋ ๋ฐํ
- src : ์
๋ ฅ 1 ์ฑ๋ ๋ฐฐ์ด
- minVal, maxVal : ๋ฐฐ์ด ์ ์ฒด์์์ ์ต์ ๊ฐ, ์ต๋ ๊ฐ
- minLoc, maxLoc : ์ต์ ๊ฐ๊ณผ ์ต๋ ๊ฐ์ ์ขํ (x, y)
# ํ
ํ๋ฆฟ ๋งค์นญ์ผ๋ก ๊ฐ์ฒด ์์น ๊ฒ์ถ
import cv2
import numpy as np
# ์
๋ ฅ์ด๋ฏธ์ง์ ํ
ํ๋ฆฟ ์ด๋ฏธ์ง ์ฝ๊ธฐ
img = cv2.imread('img/figures.jpg')
template = cv2.imread('img/taekwonv1.jpg')
th, tw = template.shape[:2]
cv2.imshow('template', template)
# 3๊ฐ์ง ๋งค์นญ ๋ฉ์๋ ์ํ
methods = ['cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR_NORMED', \
'cv2.TM_SQDIFF_NORMED']
for i, method_name in enumerate(methods):
img_draw = img.copy()
method = eval(method_name)
# ํ
ํ๋ฆฟ ๋งค์นญ ---โ
res = cv2.matchTemplate(img, template, method)
# ์ต๋, ์ต์๊ฐ๊ณผ ๊ทธ ์ขํ ๊ตฌํ๊ธฐ ---โก
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(method_name, min_val, max_val, min_loc, max_loc)
# TM_SQDIFF์ ๊ฒฝ์ฐ ์ต์๊ฐ์ด ์ข์ ๋งค์นญ, ๋๋จธ์ง๋ ๊ทธ ๋ฐ๋ ---โข
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
match_val = min_val
else:
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(method_name, img_draw)
cv2.waitKey(0)
cv2.destroyAllWindows()
- cv2.TM_SQDIFF_NORMED : ์ ๊ณฑ ์ฐจ์ด ๋งค์นญ์ ์ ๊ทํ
=> ์ต์๊ฐ์ด ์ข์ ๋งค์นญ
- cv2.TM_CCORR_NORMED : ์๊ด๊ด๊ณ ๋งค์นญ์ ์ ๊ทํ
- cv2.TM_CCOEFF_NORMED : ์๊ด๊ณ์ ๋งค์นญ์ ์ ๊ทํ
ํํ...
'๐ฉโ๐ป IoT (Embedded) > Image Processing' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[v0.29]์์์ฒ๋ฆฌ_ํน์ง ๋์คํฌ๋ฆฝํฐ ๊ฒ์ถ๊ธฐ (0) | 2022.01.15 |
---|---|
[v0.28]์์์ฒ๋ฆฌ_์ด๋ฏธ์ง์ ํน์ง์ , ํน์ง์ ๊ฒ์ถ๊ธฐ (0) | 2022.01.15 |
[v0.26]์์์ฒ๋ฆฌ_์ฐ์ ์์ญ ๋ถํ (0) | 2022.01.12 |
[v0.25]์์์ฒ๋ฆฌ_ํํ ๋ณํ (0) | 2022.01.12 |
[v0.24]์์์ฒ๋ฆฌ_์ปจํฌ์ด (์์๋ถํ ๋ฐฉ๋ฒ) (0) | 2022.01.12 |