Python/OpenCV

[OpenCV] Image Registration Processing

언킴 2023. 7. 5. 09:58
반응형

Image Registration은 동일한 장면의 서로 다른 이미지를 정렬하는데 사용하는 기술 중 하나이다. 고정된 이미지(Fixed Image)가 있고, 움직인 이미지가 있다면, 움직인 이미지를 고정된 위치로 옮기는 것을 말한다. 이미지가 회전되어 있거나, 일부 잘려있거나 할 때도 사용이 가능하다. 

 

Image Registration을 수행하기 위해 MVTec AD Dataset을 예시로 가지고 왔다. 

import os, sys, cv2, glob

import matplotlib.pyplot as plt 

paths = glob.glob(os.path.join('dataset/hazelnut/train/good/*.png'))

path = paths[0]

imgs = cv2.imread(path)
imgs = cv2.cvtColor(imgs, cv2.COLOR_BGR2RGB)

plt.imshow(imgs);

h, w = imgs.shape[:2]
x_c, y_c = (w//2, h//2)

M = cv2.getRotationMatrix2D((x_c, y_c), 90, 1.0)
rotated_imgs = cv2.warpAffine(imgs, M, (w, h))

plt.imshow(rotated_imgs);

OpenCV의 경우 RGB 형식이 아닌 BGR 형식으로 불러오기 때문에, 이미지 처리를 할 때에는 BGR을 RGB 형식으로 변환하는 과정이 필요하다. 제대로 Registration이 되는지 확인하기 위해 이미지를 90도 회전한 값도 불러온다.

 

ORB Registration

Registraion 의 가장 기본은 두 이미지 내에 존재하는 특징점을 추출하고, 이를 바탕으로 매칭 시켜주는 방식이다. 이러한 매칭 방식을 Brute-Force 매칭이라고 하며, OpvenCV에서는 cv2.BFMatcher를 통해 이용할 수 있다.  BFMacher는 두 가지 인자를 받는다. 첫 번째는 어떤 거리 함수를 사용하여 매칭할 것인가를 의미하고, 두 번째는 Cross Checking을 할 것인가에 대한 것을 의미한다.

orb_detector = cv2.ORB_create()

imgs = cv2.normalize(imgs, None, 0, 255, cv2.NORM_MINMAX).astype('uint8')
rotated_imgs = cv2.normalize(rotated_imgs, None, 0, 255, cv2.NORM_MINMAX).astype('uint8')

k1, d1 = orb_detector.detectAndCompute(imgs, None)
k2, d2 = orb_detector.detectAndCompute(rotated_imgs, None)

bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)

matches = bf.match(d1, d2)
matches = sorted(matches, key=lambda x: x.distance)

out_images = cv2.drawMatches(imgs, k1, rotated_imgs, k2, matches, None, flags=2)

plt.imshow(out_images);

 

matches = matches[:int(len(matches))]
no_of_matches = len(matches)

p1 = np.zeros((no_of_matches, 2))
p2 = np.zeros((no_of_matches, 2))

for i in range(len(matches)):
    p1[i, :] = k1[matches[i].queryIdx].pt
    p2[i, :] = k2[matches[i].trainIdx].pt
    
    
# 이상치가 있을 경우 RANSAC, RHO를 사용.
# homography 행렬 계산 방법 중 하나임.
homography, mask = cv2.findHomography(p2, p1, cv2.RANSAC)


transformed_img = cv2.warpPerspective(rotated_imgs, homography, (1024, 1024))

plt.imshow(transformed_img);

Rotate된 이미지를 원래 이미지 상태로 되돌린 경우 제대로 위치를 찾아간 것을 확인할 수 있다. 헤이즐넛의 경우 특징점들 간 잘 매칭된 것을 볼 수 있다. 그러나 유사한 헤이즐넛 이미지에 적용한 경우 제대로 매칭이 되지 않는다.

imgs2 = cv2.imread(paths[-1])
imgs2 = cv2.cvtColor(imgs2, cv2.COLOR_BGR2RGB)

orb_detector = cv2.ORB_create()

imgs2 = cv2.normalize(imgs2, None, 0, 255, cv2.NORM_MINMAX).astype('uint8')

k1, d1 = orb_detector.detectAndCompute(imgs, None)
k2, d2 = orb_detector.detectAndCompute(imgs2, None)

bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)

matches = bf.match(d1, d2)
matches = sorted(matches, key=lambda x: x.distance)

out_images = cv2.drawMatches(imgs, k1, imgs2, k2, matches[:10], None, flags=2)

plt.imshow(out_images);





matches = matches[:int(len(matches)*0.9)]
no_of_matches = len(matches)

p1 = np.zeros((no_of_matches, 2))
p2 = np.zeros((no_of_matches, 2))

for i in range(len(matches)):
    p1[i, :] = k1[matches[i].queryIdx].pt
    p2[i, :] = k2[matches[i].trainIdx].pt
    
    
# 이상치가 있을 경우 RANSAC, RHO를 사용.
# homography 행렬 계산 방법 중 하나임.
homography, mask = cv2.findHomography(p2, p1, cv2.RANSAC)


transformed_img = cv2.warpPerspective(imgs2, homography, (1024, 1024))

plt.imshow(transformed_img);

 

특징점 매칭이 제대로 되지 않은 상태로 이미지를 복원할 경우 이처럼 이상한 이미지가 생성된다. 

 

코드 참조: https://github.com/ceo21ckim/OpenCV-tutorial/blob/main/Registration.ipynb

'Python > OpenCV' 카테고리의 다른 글

[OpenCV] Image Cropping  (0) 2023.07.06