이 영역을 누르면 첫 페이지로 이동
컴퓨터와 수학, 몽상 조금 블로그의 첫 페이지로 이동

컴퓨터와 수학, 몽상 조금

페이지 맨 위로 올라가기

컴퓨터와 수학, 몽상 조금

컴퓨터공학, 딥러닝, 수학 등을 다룹니다.

[Python/OpenCV] 투영을 이용한 이미지 변환

  • 2023.02.22 15:37
  • Deep Learning/영상처리

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

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • 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
다른 글 더 둘러보기

정보

컴퓨터와 수학, 몽상 조금 블로그의 첫 페이지로 이동

컴퓨터와 수학, 몽상 조금

  • 컴퓨터와 수학, 몽상 조금의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록

카테고리

  • 분류 전체보기 (282)
    • Tech Trend (3)
    • Deep Learning (77)
      • 공부 노트 (21)
      • 논문 리뷰 (44)
      • 논문 스키밍 (1)
      • 영상처리 (11)
    • Engineering (3)
      • Tips (2)
      • Experiences (1)
    • Blog (48)
      • 회고 & 계획 (20)
      • 내 이야기 (9)
      • 리뷰 (3)
      • 군대에 간 공돌이 (10)
      • ML엔지니어 취업 도전기 (1)
      • 여행 (4)
    • 학부 수업 (141)
      • 머신러닝 (16)
      • C프로그래밍 (8)
      • 자료구조 (11)
      • 알고리즘 (17)
      • 디지털시스템 (25)
      • 컴퓨터구조 (11)
      • 확률과 통계 (21)
      • 선형대수학 (14)
      • 이산수학 (18)
      • 데이터시각화 (0)
    • 강의 (9)
      • 딥러닝 기초 (7)
      • Python (2)

공지사항

인기 글

정보

백지오의 컴퓨터와 수학, 몽상 조금

컴퓨터와 수학, 몽상 조금

백지오

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기

나의 외부 링크

  • profile
  • github
  • linkedin

방문자

  • 전체 방문자
  • 오늘
  • 어제
Powered by Tistory / Kakao. © 백지오. Designed by Fraccino.

티스토리툴바