๐ ๋ณธ ์์ ๋ Window10์ VSCode, Python3.11.0๋ก ์์ฑ๋์์ต๋๋ค.
ํด๋ฆฌ์ค ์ฝ๋ ๊ฒ์ถ(Harris Corner Detection)
ํด๋ฆฌ์ค ์ฝ๋ ๊ฒ์ถ์ ์ด๋ฏธ์ง์์ ์ฝ๋๋ฅผ ๊ฒ์ถํ๋ ๊ธฐ๋ฒ์ผ๋ก, ์ฃผ๋ก ํน์ง์ ๊ฒ์ถ์ ์ฌ์ฉ๋๋ค.
import cv2
import numpy as np
image = cv2.imread("window.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
# ํด๋ฆฌ์ค ์ฝ๋ ๊ฒ์ถ
dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)
# ๊ฒฐ๊ณผ ์ด๋ฏธ์ง๋ฅผ ๋ณต์ฌํ์ฌ ์ฝ๋ ํ์
image[dst > 0.01 * dst.max()] = [0, 0, 255] # ์ฝ๋ ๋ถ๋ถ์ ๋นจ๊ฐ์์ผ๋ก ํ์
cv2.imshow("Harris",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
FAST ์ฝ๋ ๊ฒ์ถ
FAST(Features from Accelerated Segment Test) ์ฝ๋ ๊ฒ์ถ ์๊ณ ๋ฆฌ์ฆ์ ๋น ๋ฅด๊ณ ํจ์จ์ ์ธ ํน์ง์ ๊ฒ์ถ ๊ธฐ๋ฒ์ด๋ค.
Features from accelerated segment test - Wikipedia
From Wikipedia, the free encyclopedia Features from accelerated segment test (FAST) is a corner detection method, which could be used to extract feature points and later used to track and map objects in many computer vision tasks. The FAST corner detector
en.wikipedia.org
import cv2
import numpy as np
image = cv2.imread("window.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# FAST ์ฝ๋ ๊ฒ์ถ๊ธฐ ์ด๊ธฐํ
fast = cv2.FastFeatureDetector_create()
# ์ฝ๋ ๊ฒ์ถ
keypoints = fast.detect(gray, None)
# ๊ฒ์ถ๋ ํคํฌ์ธํธ๋ฅผ ์ด๋ฏธ์ง์ ํ์
image_with_keypoints = cv2.drawKeypoints(image, keypoints, None, (0, 255, 0), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("FAST",image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
ํฌ๊ธฐ ๋ถ๋ณ ํน์ง์ ๊ฒ์ถ - SIFT
์ด์ ์๊ณ ๋ฆฌ์ฆ์ ํตํ ์ฝ๋๋ ์์์ด ํ์ ๋์ด๋ ์ฌ์ ํ ์ฝ๋๋ก ๊ฒ์ถ๋๋ค. ์ฝ๋๋ ํ์ ๋ถ๋ณ ํน์ง์ ์ด๋ผ๊ณ ํ ์ ์๋ค.
๊ทธ๋ฌ๋ ์์์ ํฌ๊ธฐ๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ ๋์ด์ ์ฝ๋๋ก ๊ฒ์ถ๋์ง ์์ ์ ์๋ค.
ํฌ๊ธฐ๊ฐ ๋ณํด๋ ์ง์์ ์ผ๋ก ์ฝ๋๋ฅผ ๊ฒ์ถํ๋ ์๊ณ ๋ฆฌ์ฆ์ด ์ฐ๊ตฌ ๋์๋ค.
๊ทธ ์ค ๊ฐ์ฅ ๋ํ์ ์๊ณ ๋ฆฌ์ฆ์ด SIFT๋ก Scale Invariant Feature Transform์ ์ฝ์์ด๋ค.
SIFT๋ ์ด๋ฏธ์ง์ ๋ค์ํ ์ค์ผ์ผ์์ ํน์ง์ ์ ๊ฒ์ถํ๊ธฐ ์ํด Gaussian Blur๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ก ์ค์ผ์ผ์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. ์ด๋ฅผ ํตํด ์ด๋ฏธ์ง์ ๋ค์ํ ํฌ๊ธฐ์์ ํน์ง์ ์ ํ์งํ ์ ์๋ค.
๊ฐ ์ค์ผ์ผ์์ DoG(Difference of Gaussian) ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ๊ทน๋๊ฐ(์ต๋๊ฐ)๊ณผ ๊ทน์๊ฐ(์ต์๊ฐ)์ ์ฐพ์ ํน์ง์ ์ ๊ฒ์ถํ๋ค. ์ด ๋จ๊ณ์์ ๊ฒ์ถ๋ ํฌ์ธํธ๋ ์ ์ฌ์ ์ธ ํน์ง์ ์ผ๋ก ๊ฐ์ฃผ๋๋ค.
๊ฒ์ถ๋ ํน์ง์ ์ ์์น๋ฅผ ์ ๋ฐํ๊ฒ ์กฐ์ ํ๊ณ ๊ฐ ํน์ง์ ์ ๋ํด ์ฃผ ๋ฐฉํฅ์ ์ค์ ํ์ฌ ํ์ ๋ถ๋ณ์ฑ์ ๋ถ์ฌํ๋ค.
์ด ๋ฐฉํฅ์ ์ฃผ๋ณ ํฝ์ ์ ๊ธฐ์ธ๊ธฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ณ์ฐ๋๋ค.
๊ฐ ํน์ง์ ์ ์ฃผ๋ณ ํฝ์ ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ค๋ช ์๋ฅผ ์์ฑํ๋ค.
์ผ๋ฐ์ ์ผ๋ก 16x16 ํฝ์ ์์ญ์ 4x4 ๊ทธ๋ฆฌ๋๋ก ๋๋๊ณ , ๊ฐ ๊ทธ๋ฆฌ๋์ ๋ฐฉํฅ ํ์คํ ๊ทธ๋จ์ ๊ณ์ฐํ์ฌ ํน์ง์ ํํํ๋ค.
์ด ์ค๋ช ์๋ ๊ณ ์ ํ ํน์ง์ ์ "์ง๋ฌธ"์ญํ ์ ํ๊ณ ๋น๊ต ๋งค์นญ์ ์ฌ์ฉ๋๋ค.
๋ค๋ฅธ ์ด๋ฏธ์ง์์ ๊ฒ์ถ๋ SIFT ํน์ง์ ๊ณผ ์ค๋ช ์๋ฅผ ๋น๊ตํ์ฌ ๋งค์นญํ๋ค. ์ฃผ๋ก ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ ๋๋ ์ ์ฌ๋ ๊ธฐ๋ฐ์ผ๋ก ๋งค์นญ์ ์ํํ๋ค.
ํฌ๊ธฐ ๋ถ๋ณ ํน์ง์ ๊ฒ์ถ - SURF
SIFT๋ ๊ณ์ฐ ๋น์ฉ์ด ๋๋ค. ์ด๋ฅผ ๊ฐ์ ๋์ด ๋์จ ์๊ณ ๋ฆฌ์ฆ์ด SURF(Speeded Up Robust Features)์ด๋ค.
SURF๋ Gaussian ํํฐ ๋์ Haar ์จ์ด๋ธ๋ซ์ ์ฌ์ฉํ์ฌ ์ค์ผ์ผ ๊ณต๊ฐ์ ์์ฑํ๋ค.
์ด๋ฅผ ํตํด ์๋๊ฐ ํฅ์๋๋ค.
์ดํ ์ด๋ฏธ์ง์ ๊ฐ ์ค์ผ์ผ์์ Hessian ํ๋ ฌ์ ์ฌ์ฉํ์ฌ ํน์ง์ ์ ๊ฒ์ถํ๋ค.
ํน์ง์ ์ ๋ํด ์ฃผ๋ฐฉํฅ์ ๊ณ์ฐํ์ฌ ํ์ ๋ถ๋ณ์ฑ์ ์ ๊ณตํ๋ค.
SIFT์ ๋์ผํ๊ฒ ๋ฐฉํฅ์ ์ฃผ๋ณ ํฝ์ ์ ๊ธฐ์ธ๊ธฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ณ์ฐ๋๋ค.
SURF์ ์ค๋ช ์ ์์ฑ์ 64์ฐจ์ ๋๋ 128์ฐจ์์ ์ค๋ช ์๋ฅผ ์์ฑํ๋ค.
ํน์ง์ ์ฃผ๋ณ์ Haar ์จ์ด๋ธ๋ ์๋ต์ ๊ธฐ๋ฐ์ผ๋ก ๋ฐฉํฅ ํ์คํ ๊ทธ๋จ์ ๊ณ์ฐํ์ฌ ํน์ง์ ์ ํํํ๋ค.
SIFT์์์ ๊ฐ์ด ๋ค๋ฅธ ์ด๋ฏธ์ง์์ ๊ฒ์ถ๋ ํน์ง์ ๊ณผ ๋น๊ตํ์ฌ ๋งค์นญํ๋ค. ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ ๋๋ ์ ์ฌ๋ ๊ธฐ๋ฐ ๋ฉํธ๋ฆญ์ ์ฌ์ฉํ๋ค.
ํฌ๊ธฐ ๋ถ๋ณ ํน์ง์ ๊ฒ์ถ - ORB
ORB(Oriented FAST and Rotated BRIEF)๋ SIFT์ SURF์ ๋ณต์กํ ์ฐ์ฐ์ ํด๊ฒฐํ๊ธฐ ์ํด ๋์์ผ๋ก ์ ์๋ ํน์ง์ ๊ฒ์ถ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
ORB๋ FAST ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ํน์ง์ ์ ๋น ๋ฅด๊ฒ ๊ฒ์ถํ๋ฉฐ ์ด๋ ์ค์๊ฐ ์์ฉ์ ์ ํฉํ ์๋๋ฅผ ์ ๊ณตํ๋ค.
์ฃผ๋ฐฉํฅ ๊ณ์ฐ์ ํตํ ํ์ ๋ถ๋ณ์ฑ ์ ๊ณต์ SIFT, SURF์ ๋์ผํ๋ค.
BRIEF(Binary Robust Invariant Scalable Keypoints) ์ค๋ช ์๋ฅผ ์ฌ์ฉํ์ฌ ํน์ง์ ํํํ๋ค.
BRIEF๋ ์ด์ง ์ค๋ช ์๋ก, ๋น ๋ฅธ ๋งค์นญ์ด ๊ฐ๋ฅํ๋๋ก ์ค๊ณ๋์๋ค.
ORB๋ BRIEF๋ฅผ ํ์ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค์ด, ์ค๋ช ์๊ฐ ํ์ ์ ๊ฐํ๊ฒ ๋๋ค.
ORB์ ํน์ง์ ์ ๋ค๋ฅธ ์ด๋ฏธ์ง์ ํน์ง์ ๊ณผ ์ด์ง ์ค๋ช ์๋ฅผ ๋น๊ตํ์ฌ ๋งค์นญ๋๊ณ ์ผ๋ฐ์ ์ผ๋ก ํด๋ฐ ๊ฑฐ๋ฆฌ(Hamming Distance)๋ฅผ ์ฌ์ฉํ์ฌ ๋งค์นญ์ ์ ์ฌ์ฑ์ ๊ณ์ฐํ๋ค.
import cv2
import numpy as np
# ์ด๋ฏธ์ง ์ฝ๊ธฐ
image = cv2.imread("window.jpg")
# ORB ๊ฐ์ฒด ์์ฑ
orb = cv2.ORB_create()
# ํค ํฌ์ธํธ ๋ฐ ์ค๋ช
์ ๊ฒ์ถ
keypoints, descriptors = orb.detectAndCompute(image, None)
# ํค ํฌ์ธํธ๋ฅผ ์ด๋ฏธ์ง์ ๊ทธ๋ฆฌ๊ธฐ
image_with_keypoints = image.copy()
# ๋๋ค ์์์ผ๋ก ํค ํฌ์ธํธ ๊ทธ๋ฆฌ๊ธฐ
for kp in keypoints:
# ๋๋ค ์์ ์์ฑ (BGR ํ์)
random_color = np.random.randint(0, 256, size=3).tolist()
# ํค ํฌ์ธํธ ์์น์ ํฌ๊ธฐ์ ๋ฐ๋ผ ์ ๊ทธ๋ฆฌ๊ธฐ
cv2.circle(image_with_keypoints, (int(kp.pt[0]), int(kp.pt[1])), int(kp.size / 2), random_color, 1)
# ๊ฒฐ๊ณผ ์ด๋ฏธ์ง ํ์
cv2.imshow('Keypoints with Random Colors', image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
Homography
ํคํฌ์ธํธ ๋งค์นญ์ ํ๊ณ ํธ๋ชจ๊ทธ๋ํผ๋ฅผ ๊ณ์ฐํ์ฌ ๊ฐ์ฒด ๊ฒ์ถ์ ํ ์ ์๋ค.
ํธ๋ชจ๊ทธ๋ํผ(Homography)๋ 3์ฐจ์ ๊ณต๊ฐ์์ ํ๋ฉด์ ์๋ก ๋ค๋ฅธ ์์ ์์ ๋ฐ๋ผ๋ดค์ ๋ ํ๋๋๋ ์์ ์ฌ์ด์ ๊ด๊ณ๋ฅผ ๋ํ๋ด๋ ์ฉ์ด์ด๋ค.
import cv2
import sys
import numpy as np
# ์ด๋ฏธ์ง ์ฝ๊ธฐ
src1 = cv2.imread('cat_head.png', cv2.IMREAD_GRAYSCALE)
src1 = cv2.resize(src1,(int(src1.shape[1]//2),int(src1.shape[0]//2)),interpolation=cv2.INTER_LANCZOS4)
src2 = cv2.imread('cat.png', cv2.IMREAD_GRAYSCALE)
src2 = cv2.resize(src2,(int(src2.shape[1]//2),int(src2.shape[0]//2)),interpolation=cv2.INTER_LANCZOS4)
if src1 is None or src2 is None:
print('Image load failed!')
sys.exit()
# ํน์ง์ ์๊ณ ๋ฆฌ์ฆ ๊ฐ์ฒด ์์ฑ (KAZE, AKAZE, ORB ๋ฑ)
feature = cv2.KAZE_create() # ๊ธฐ๋ณธ๊ฐ์ธ L2๋ ์ด์ฉ
# feature = cv2.AKAZE_create()
# feature = cv2.ORB_create()
# ํน์ง์ ๊ฒ์ถ ๋ฐ ๊ธฐ์ ์ ๊ณ์ฐ
kp1, desc1 = feature.detectAndCompute(src1, None)
kp2, desc2 = feature.detectAndCompute(src2, None)
# ํน์ง์ ๋งค์นญ
matcher = cv2.BFMatcher_create()
matches = matcher.match(desc1, desc2)
# ์ข์ ๋งค์นญ ๊ฒฐ๊ณผ ์ ๋ณ
matches = sorted(matches, key=lambda x: x.distance)
good_matches = matches[:80]
print('# of kp1:', len(kp1))
print('# of kp2:', len(kp2))
print('# of matches:', len(matches))
print('# of good_matches:', len(good_matches))
# ํธ๋ชจ๊ทธ๋ํผ ๊ณ์ฐ
pts1 = np.array([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2).astype(np.float32)
pts2 = np.array([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2).astype(np.float32) # ์์ ๋ ๋ถ๋ถ
H, _ = cv2.findHomography(pts1, pts2, cv2.RANSAC) # pts1๊ณผ pts2์ ํ๋ ฌ ์ฃผ์ (N,1,2)
# ํธ๋ชจ๊ทธ๋ํผ๋ฅผ ์ด์ฉํ์ฌ ๊ธฐ์ค ์์ ์์ญ ํ์
dst = cv2.drawMatches(src1, kp1, src2, kp2, good_matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
(h, w) = src1.shape[:2]
# ์
๋ ฅ ์์์ ๋ชจ์๋ฆฌ 4์ ์ขํ
corners1 = np.array([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2).astype(np.float32)
# ์
๋ ฅ ์์์ ํธ๋ชจ๊ทธ๋ํผ H ํ๋ ฌ๋ก ํฌ์ ๋ณํ
corners2 = cv2.perspectiveTransform(corners1, H)
# corners2๋ ์
๋ ฅ ์์์ ์ขํ๊ฐ ํํ๋์์ผ๋ฏ๋ก ์
๋ ฅ์์์ ๋์ด ๋งํผ ์ฌํํธ
corners2 = corners2 + np.float32([w, 0])
# ๋ค๊ฐํ ๊ทธ๋ฆฌ๊ธฐ
cv2.polylines(dst, [np.int32(corners2)], True, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow('Homography', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
์์ ์ด์ด ๋ถ์ด๊ธฐ(Image Stitching)
์์ ์ด์ด ๋ถ์ด๊ธฐ๋ ์ฌ๋ฌ ์ฅ์ ์์์ ์๋ก ์ด์ด ๋ถ์ฌ์ ํ๋์ ํฐ ์์์ ๋ง๋๋ ๊ธฐ๋ฒ์ด๋ค.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง ์์์ ํ๋ ธ๋ผ๋ง ์์(Panorama Image)๋ผ๊ณ ํ๋ค.
import cv2
# ์ด๋ฏธ์ง ์ฝ๊ธฐ
img1 = cv2.imread('cat1.png')
img1 = cv2.resize(img1,(int(img1.shape[1]//2),int(img1.shape[0]//2)),interpolation=cv2.INTER_LANCZOS4)
img2 = cv2.imread('cat2.png')
img2 = cv2.resize(img2,(int(img2.shape[1]//2),int(img2.shape[0]//2)),interpolation=cv2.INTER_LANCZOS4)
img3 = cv2.imread('cat3.png')
img3 = cv2.resize(img3,(int(img3.shape[1]//2),int(img3.shape[0]//2)),interpolation=cv2.INTER_LANCZOS4)
img_list = [img1,img2,img3]
stitcher = cv2.Stitcher.create()
status,stitched = stitcher.stitch(img_list)
# ๊ฒฐ๊ณผ ์ด๋ฏธ์ง ์ถ๋ ฅ
cv2.imshow("img1",img1)
cv2.imshow("img2",img2)
cv2.imshow("img3",img3)
cv2.imshow("Stiched Image",stitched)
cv2.waitKey(0)
cv2.destroyAllWindows()
'AI > Computer Vision' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Computer Vision] IoU(Intersection over Union) (0) | 2024.09.12 |
---|---|
[Computer Vision] PIL(Python Image Library) (0) | 2024.09.08 |
[Computer Vision] ๊ฐ์ฒด ๊ฒ์ถ๊ณผ ์์ฉ (0) | 2024.09.06 |
[Computer Vision] ๋ ์ด๋ธ๋ง๊ณผ ์ธ๊ฐ์ ๊ฒ์ถ (0) | 2024.09.04 |
[Computer Vision] ์์์ ์ด์งํ์ ๋ชจํด๋ก์ง (0) | 2024.09.03 |