[Python/OpenCV] 투영을 이용한 이미지 변환
2D 이미지의 Projective(Homography) Transformation을 이용하면 이미지에 대한 다양한 변환을 수행할 수 있다.
기본적인 2D 시점 변환
이미지 내부에 존재하는 2D 평면을 마치 스캔한 것처럼 보이게 시점 변환을 수행해보자.
위 자판기 사진의 옆면의 각 모서리에 점을 지정하고, 해당 평면을 복원하는 변환을 수행해보겠다.
(사진과 점이 정확하지 않아 약간 대충 찍은 것은 감안해주기 바란다.)
y_pos = img.shape[0]
x_pos = img.shape[1]
original_coord = np.float32([[122, 30], [370, 0], [190, 800], [370, 960]])
warped_coord = np.float32([[0, 0], [x_pos, 0], [0, y_pos], [x_pos, y_pos]])
원래 이미지에서 각 모서리의 좌표와, 해당 모서리들이 변환 후 위치할 좌표들을 잡는다.
mat = cv2.getPerspectiveTransform(original_coord, warped_coord)
warped_img = cv2.warpPerspective(img, mat, (x_pos, y_pos))
좌표들을 이용해 변환을 위한 행렬을 계산하고, 변환을 수행하였다.
기준점을 정확히 찍지 않아 조금 삐뚤지만, 시점 변환이 되었다!
예제 코드
다른 이미지를 활용한 전체 코드를 살펴보자.
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread("./street.jpg", cv2.IMREAD_COLOR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
y_pos = 500
x_pos = 1200
original_coord = np.float32([[75, 270], [970, 570], [40, 820], [980, 685]])
warped_coord = np.float32([[0, 0], [x_pos, 0], [0, y_pos], [x_pos, y_pos]])
mat = cv2.getPerspectiveTransform(original_coord, warped_coord)
warped_img = cv2.warpPerspective(img, mat, (x_pos, y_pos))
2D 평면은 아니지만, 2D에 가까운 가게 정면을 펼쳐 보았다.
투영(Homography)이란
위에서 보인 2가지 변환은 모두 투영기하학(Homography)을 이용한 변환이다.
투영이란 쉽게 말해, 2D 평면 상의 어떤 사각형을 다른 사각형으로 매핑하는 것을 의미한다.
원본 이미지의 각 픽셀 $\mathbf{x}= (x, y, 1)^T$(1은 행렬곱 연산을 위해 추가된 값으로, 무시하여도 된다.)에 대하여 투영 변환 $H$를 가하여 새로운 좌표 $\mathbf{x}' = (x', y', w)^T$로 변환하게 된다.
이를 식으로 나타내면 다음과 같다.
$$ \mathbf{x}' = H\mathbf{x} $$
이때, H는 변환을 위한 $3\times 3$ 행렬이며, $\mathbf{x}$는 위에서 언급하였듯이 $3 \times 1$ 행렬이다.
변환을 위한 행렬 $H$는 위 코드처럼 임의의 점이나 값들로부터 설정할 수 있다.
투영 변환을 이용한 파노라마 사진 만들기
투영을 이용해 여러 장의 사진을 자연스럽게 이어붙여 파노라마 사진을 만들 수 있다.
위에 한 장소에서 각기 다른 각도를 찍은 3장의 사진이 있다.
세장을 연결하면 넓은 풍경을 촬영한 멋진 사진이 되겠지만, 보다시피 사진들의 각도가 각각 달라 자연스럽게 이어지지 않는다.
이때, 기준이 될 사진(중앙의 사진으로 하자.)에 맞춰 붙일 사진들을 투영하여 이어 붙이면 아주 자연스럽게 이미지를 붙일 수 있다.
Direct Linear Transformation
두 이미지를 이어붙이기 위해서는 기준이 되는 이미지위의 기준점과 이어붙일 이미지의 점들이 같은 픽셀에 위치해야 한다.
(예를들어, 위 이미지에서 중앙 이미지의 처마 끝과 왼쪽 이미지의 처마 끝이 같은 픽셀에 위치하도록 왼쪽 이미지를 변환해야 한다.)
즉, 변환된 이미지 위의 점 $H\mathbf{x}$과 기준이 되는 이미지 위의 점 $\mathbf{x}'$이 같은 방향을 가져야 한다.
이를 식으로 나타내면 다음과 같다.
$$ \mathbf{x}' \times H\mathbf{x} = 0$$
우리는 이 변환을 가능하게 하는 $H$ 행렬을 구하고자 한다. 기준 이미지와 변환하고자 하는 이미지 내부의 기준점 쌍들을 만들고, ($\mathbf{x}$와 $\mathbf{x}'$의 쌍) 이를 이용해 $H$에 대한 연립 방정식을 풀어 $H$를 구할 수 있다.
그러나, 이 쌍이 완벽할 수는 없기 때문에, 우리는 정확한 $H$를 구하는 것이 아니라 위 식이 0에 가까워지는 근사값을 구할 것이다.
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img_left = cv2.imread("./left2.jpg", cv2.IMREAD_COLOR)
img_left=cv2.cvtColor(img_left, cv2.COLOR_BGR2RGB)
img_right = cv2.imread("./right2.jpg", cv2.IMREAD_COLOR)
img_right=cv2.cvtColor(img_right, cv2.COLOR_BGR2RGB)
먼저, 각 이미지를 불러온다.
sift = cv2.SIFT_create()
keypoints_l, descriptor_l = sift.detectAndCompute(img_left, None)
keypoints_r, descriptor_r = sift.detectAndCompute(img_right, None)
SIFT 추출기를 이용해 이미지의 특징점들을 추출한다.
다음과 같이 이미지 내부에 특징적인 부분들을 뽑아낸 것을 확인할 수 있다.
bf = cv2.BFMatcher()
matches = bf.match(descriptor_l,descriptor_r)
sorted_matches = sorted(matches, key = lambda x : x.distance)
BF Matcher를 통해 두 이미지에 공통된 특징점들을 매칭한다.
point_img1 = []
point_img2 = []
for m in sorted_matches:
idx_left = m.queryIdx
idx_right = m.trainIdx
point_img2.append(keypoints_l[idx_left].pt)
point_img1.append(keypoints_r[idx_right].pt)
point_img1 = np.asarray(point_img1)
point_img2 = np.asarray(point_img2)
retval, mask = cv2.findHomography(point_img1, point_img2, method=cv2.RANSAC)
생성한 특징점 쌍들을 이용해 Homography 행렬 $H$를 계산한다.
다른 이미지에 맞춰 조정된 이미지를 확인할 수 있다.
warped_img[0 : img_left.shape[0], 0 : img_right.shape[1]] = img_left
plt.figure(figsize=(18, 10))
imshow(warped_img)
마지막으로 기준 이미지에 변형된 이미지를 합쳐준다!
약간 어색하지만, 합쳐진 이미지를 확인할 수 있다!
'Deep Learning > 영상처리' 카테고리의 다른 글
코너 검출 (Corner Detection) (0) | 2023.03.08 |
---|---|
Line Fitting (RANSAC, HOUGH transform) (0) | 2023.03.08 |
엣지와 그래디언트 (Edge and Gradient) (0) | 2023.03.07 |
이미지 필터링 (Image Filtering) (0) | 2023.03.07 |
Camera 시스템 (0) | 2023.03.06 |
댓글
이 글 공유하기
다른 글
-
Line Fitting (RANSAC, HOUGH transform)
Line Fitting (RANSAC, HOUGH transform)
2023.03.08 -
엣지와 그래디언트 (Edge and Gradient)
엣지와 그래디언트 (Edge and Gradient)
2023.03.07 -
이미지 필터링 (Image Filtering)
이미지 필터링 (Image Filtering)
2023.03.07 -
Camera 시스템
Camera 시스템
2023.03.06