Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

:)

와핑기법과 원근 변환 본문

ROS

와핑기법과 원근 변환

mihee 2022. 4. 10. 20:36

이미지의 기하학적 변형

  • 와핑(Warping)
    • '뒤틀림', '왜곡하다'를 의미
    • 영상시스템에서 말하는 Warping은 영상을 이동, 회전, 크기변환 등을 이용해 이미지를 찌그러뜨리거나 반대로 찌그러진 이미지를 복원하기 위한 처리 기법
  • 변환 (Transformations)
    • 좌표 x를 새로운 좌표 x`로 변환하는 함수
    • 사이즈 변경(Scaling), 위치변경(Translation), 회전(Rotation) 등
    (1) 강제변환(Rigid-Body) : 크기 및 각도가 보존되는 변환(ex. Translation, Rotation)
    (2) 유사변환(Similarity) : 크기는 변하고 각도는 보존되는 변환(ex. Scaling)
    (3) 선형변환(Linear) : Vector 공간에서의 이동
    (4) Affine : 선형변환과 이동변환까지 포함. 선의 수평성은 유지 (ex 사각형 -> 평행사변형)
    (5) Perspective : Affine 변환에 수평성도 유지되지 않음. 원근변환.

Translation 변환

  • 평행이동
    • 이미지를 이동하려면 원래 있던 좌표에서 이동시키려는 거리만큼 더하면 됨.
      • x_new = x_old + d1
      • y_new = y_old + d2

  • dst = cv2.warpAffine(src, matrix, dsize, dst, flags, borderMode, borderValue)
    • matrix : 2X3 변환 행렬, dtype = float32
    • dsize : 결과 이미지의 크기(width, height)
    • dst(optional)
    • flags(optional) : 보간법 알고리즘 플래그
      • cv2.INTER_LINEAR : default 값. 인접한 4개 픽셀 값에 거리 가중치 사용
      • cv2.INTER_NEAREST : 가장 가까운 픽셀 값 사용
      • cv2.INTER_AREA : 픽셀 영역 관계를 이용한 재샘플링
      • cv2.INTER_CUBIC : 인접한 16개 픽셀 값에 거리 가중치 사용
    • borderMode(optional) : 외곽영역 보정 플래그
      • cv2.BORDER_CONSTANT : 고정 색상 값
      • cv2.BORDER_REPLICATE : 가장자리 복제
      • cv2.BORDER_WRAP : 반복
      • cv2.BORDER_REFLECT : 반사
    • borderValue(optional) : 외곽영역 보정 플래그가 cv2.BORDER_CONSTANT 일 경우 사용할 색상 값 (default=0)
import cv2
import numpy as np



img = cv2.imread('girl.png')  
rows,cols = img.shape\[0:2\]  
dx, dy = 100, 50  
#변환 행렬 생성  
mtrx = np.float32(\[\[1, 0, dx\],  
\[0, 1, dy\]\])

dst = cv2.warpAffine(img, mtrx, (cols+dx, rows+dy))

# 탈락된 외곽 픽셀을 파랑색으로 보정

dst2 = cv2.warpAffine(img, mtrx, (cols+dx, rows+dy), None,  
cv2.INTER\_LINEAR, cv2.BORDER\_CONSTANT, (255,0,0) )

# 탈락된 외곽 픽셀을 원본을 반사 시켜서 보정

dst3 = cv2.warpAffine(img, mtrx, (cols+dx, rows+dy), None,  
cv2.INTER\_LINEAR, cv2.BORDER\_REFLECT)

cv2.imshow('original', img)  
cv2.imshow('trans', dst)  
cv2.imshow('BORDER\_CONSTATNT', dst2)  
cv2.imshow('BORDER\_REFLECT', dst3)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

translation 실행결과

확대축소

  • 일정 비율로 확대 및 축소
    • 기존 좌표에 특정 값을 곱함.

import cv2
import numpy as np

img = cv2.imread('girl.png')
height, width = img.shape[0:2]

m_small = np.float32([[0.5, 0, 0],
                      [0, 0.5, 0]])  

m_big = np.float32([[2, 0, 0],
                    [0, 2, 0]])  


dst1 = cv2.warpAffine(img, m_small, (int(height*0.5), int(width*0.5)))

# 보간법 적용한 축소
dst2 = cv2.warpAffine(img, m_small, (int(height*0.5), int(width*0.5)), \
                        None, cv2.INTER_AREA)

dst3 = cv2.warpAffine(img, m_big, (int(height*2), int(width*2)))
# 보간법 적용한 확대
dst4 = cv2.warpAffine(img, m_big, (int(height*2), int(width*2)), \
                        None, cv2.INTER_CUBIC)
cv2.imshow("original", img)
cv2.imshow("small", dst1)
cv2.imshow("small INTER_AREA", dst2)
cv2.imshow("big", dst3)
cv2.imshow("big INTER_CUBIC", dst4)
cv2.waitKey(0)
cv2.destroyAllWindows()

크기 조정 OpenCV 함수

  • cv2.resize(src, dsize, dst, fx, fy, interpolation)
    • dsize : 출력 영상 크기(확대/축소 목표 크기), 생략하면 fx, fy 배율을 적용
    • fx, fy : 크기 배율, dsize가 주어지면 dsize를 우선 적용
    • interpolation : 보간법 알고리즘 선택 플래그 (cv2.warpAffine()과 동일)
  • 확대/축소를 몇 픽셀로 할지 혹은 어떤 배율로 할지 선택 가능
    • dsize는 확대/축소를 원하는 목표 이미지의 크기
    • fx, fy는 변경할 배율
      • fx=2, fy=0.5 이면 x축으로 2배, y축으로 0.5배로 스케일링 한다는 뜻

resize 함수 사용 결과

회전

import cv2
import numpy as np

img = cv2.imread('girl.png')

rows,cols = img.shape[0:2]

# 회전 각조를 라디안 값으로 변경
d45 = 45.0 * np.pi / 180    
d90 = 90.0 * np.pi / 180    

# 45도 회전 행렬 (rows//2, cols//4 --> 회전축의 중심을 옮길때)
m45 = np.float32( [[ np.cos(d45), -1* np.sin(d45), rows//2],
                    [np.sin(d45), np.cos(d45), -1*cols//4]])

# 90도 회전 행렬
m90 = np.float32( [[ np.cos(d90), -1* np.sin(d90), rows],
                    [np.sin(d90), np.cos(d90), 0]])


r45 = cv2.warpAffine(img,m45,(cols,rows))
r90 = cv2.warpAffine(img,m90,(cols,rows))


cv2.imshow("origin", img)
cv2.imshow("45", r45)
cv2.imshow("90", r90)
cv2.waitKey(0)
cv2.destroyAllWindows()

회전 실행결과

회전 행렬 구하는 OpenCV 함수

  • mtrx = cv2.getRotationMatrix2D(center, angle, scale)
    • center : 회전축 중심 좌표(x,y)
    • Angle : 회전할 각도, 60진법
    • Scale : 확대 및 축소비욜
  • 회전 축을 정하고 + 회전 각도를 정하고, 확대/축소를 정ㅎㄹ 수 있음
    • 복합적인 행렬 만들기 가능
import cv2
import numpy as np

img = cv2.imread('girl.png')

rows,cols = img.shape[0:2]

# 회전축은 중앙, 45도 회전, 0.5배 축소 행렬
m45 = cv2.getRotationMatrix2D((cols/2,rows/2),45,0.5) 
print(m45)
# 회전축은 중앙, 90도 회전, 1.5배 확대 행렬
m90 = cv2.getRotationMatrix2D((cols/2,rows/2),90,1.5) 
print(m90)

r45 = cv2.warpAffine(img, m45,(cols, rows))
r90 = cv2.warpAffine(img, m90,(cols, rows))


cv2.imshow("origin", img)
cv2.imshow("45", r45)
cv2.imshow("90", r90)
cv2.waitKey(0)
cv2.destroyAllWindows()

getRotationMatrix2D 함수 사용 결과

아핀 변환 - Affine

  • Affine 변환 : 크기변환, 이동변환, 회전변환에서도 원래 평행했던 특성을 그래도 유지
  • Affine 변환 행렬 : cv2.getAffineTransform 함수를 통해서 얻을 수 있음. 2X3 행렬
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('chess.png')

rows,cols = img.shape[0:2]

# 변환전 3개 점의 좌표
pts1 = np.float32([[50,50],[200,50],[50,200]])

# 변환 후 3개 점의 좌표
pts2 = np.float32([[10,100],[200,50],[100,250]])

# 기존 점이 새로운 점으로 이동시킬 때 필요한 행렬 찾기
M = cv2.getAffineTransform(pts1,pts2)
print(M)

# 구해진 행렬을 적용하여 이미지 변환
dst = cv2.warpAffine(img,M,(cols,rows))

plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

warpAffine 실행 화면

원근 변환 - Perspective

  • Perspective 변환
    • 원근법을 적용한 변환
    • 직선의 성질만 유지 되고, 선의 평행성은 유지되지 않는 변환
    • 기차길은 서로 평행하지만 원근변환을 거치면 평행성은 유지되지 못하고 하나의 점에서 만나는 것처럼 보임
    • 반대의 변환도 가능 -> 차선 추출에 사용
  • Perspective 변환 행렬
    • cv2.getPerspectiveTransform 함수를 통해 얻을 수 있음
    • 이동할 4개 점의 좌표가 필요
    • 결과값은 3X3 행렬
  • cv2.warpPerspective() 함수에 변환 행렬값을 적용해서 이미지 변환
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('chess.png')

rows,cols = img.shape[0:2]

# 변환전 4개 점의 좌표
pts1 = np.float32([[20,20],[20,280],[380,20],[380,280]])
# 변환 후 4개 점의 좌표
pts2 = np.float32([[100,20],[20,280],[300,20],[380,280]])

# 4개 점의 위치에 다른 색깔로 원 그리기
cv2.circle(img, (20,20), 20, (255,0,0),-1)
cv2.circle(img, (20,280), 20, (0,255,0),-1)
cv2.circle(img, (380,20), 20, (0,0,255),-1)
cv2.circle(img, (380,280), 20, (0,255,255),-1)

# 4개 점의 이동 정보를 가지고 행렬 계산
M = cv2.getPerspectiveTransform(pts1, pts2)
print(M)

# 구해진 행렬을 적용하여 이미지 변환
dst = cv2.warpPerspective(img, M, (cols,rows))

plt.subplot(121),plt.imshow(img),plt.title('image')
plt.subplot(122),plt.imshow(dst),plt.title('Perspective')
plt.show()

perspective 실행 결과

 

'ROS' 카테고리의 다른 글

슬라이딩 윈도우 기반 차선 인식  (0) 2022.04.10
원근 변환과 슬라이딩 윈도우  (0) 2022.04.10
허프변환 기반 차선인식  (0) 2022.04.10
명도차 기반 차선 인식  (0) 2022.03.30
OpenCV 자이카 카메라 활용  (0) 2022.03.28
Comments