[OpenCV] 04-8. Image Pyramids
🐍Python/OpenCV

[OpenCV] 04-8. Image Pyramids

728x90
반응형

< 4-8. Image Pyramids >

이번 챕터에서는,

  • Image Pyramids에 대해 배우고
  • 새로운 과일인 Orapple을 만들기 위해 Image Pyramids를 사용할 것이다.
  • cv2.pyrUp(), cv2.pyrDown()

Theory

일반적으로, 변함없는 사이즈의 이미지를 사용했었다. 하지만 어떠한 상황에서는, 같은 이미지이지만 다른 해상도에서 작업할 필요가 있다. 예를 들어서, 이미지내에서 얼굴 과 같은 무언가를 찾을 때, 우리는 그 물체가 이미지에 어떤 크기로 나타날지 확신할 수 없다. 이 경우, 우리는 서로 다른 해상도의 이미지 세트를 생성하고 모든 이미지에 대해 객체를 찾아야한다. 이 서로 다른 해상도의 이미지셋을 “Image Pyramids”라고 부른다. (큰 것부터 작은 것이 아래서 위로 쌓여있는 모양이 피라미드 같아서)

Image Pyramids에는 두 가지 종류가 있다.

1) Gaussian Pyramids
2) Laplacian Pyramids

하위 단계 (고해상도)이미지에서 연속적인 행과 열을 제거하여 Gaussian Pyramid의 상위 단계(저해상도)가 형성된다. 그러면 상위 단계의 각 픽셀은 가우시안 가중치를 가진 기본 레벨의 5픽셀의 기여에 의해 형성된다. 그러면 M x N 이미지는 M/2 x N/2 이미지가 된다. 그래서 면적이 원래 면적의 4분의 1로 줄어든다. 이를 옥타브라고 부른다. 피라미드 상층부로 올라갈 때와 같은 패턴이 계속된다.(해상도가 감소한다) 마찬가지로 확장하는 동안 영역은 각 수준에서 4배가 된다. cv2.pyrDown(), cv2.pyrUp()을 이용하여 가우시안 피라미드를 구성할 수 있다.

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('./images/golden.jpg')
low_res = cv2.pyrDown(img)
low_res2 = cv2.pyrDown(low_res)

plt.figure(figsize=(12,8))
plt.subplot(1,3,1),plt.imshow(img[:,:,::-1])
plt.title('Original Size = {0}X{1}'.format(img.shape[1],img.shape[0]))
plt.subplot(1,3,2),plt.imshow(low_res[:,:,::-1])
plt.title('Low Resolution Size = {0}X{1}'.format(low_res.shape[1],low_res.shape[0]))
plt.subplot(1,3,3),plt.imshow(low_res2[:,:,::-1])
plt.title('Low Resolution2 Size = {0}X{1}'.format(low_res2.shape[1],low_res2.shape[0]))
plt.show()


cv2.pyrUp() 함수를 이용하면 이미지 피라미드 하단을 구성할 수 있다. 해상도를 낮추면 정보를 놓치기 때문에 각 단계별로는 같지 않다.

high_res = cv2.pyrUp(low_res2)
high_res2 = cv2.pyrUp(high_res)
high_res3 = cv2.pyrUp(high_res2)

plt.figure(figsize=(12,4))
plt.subplot(1,3,1),plt.imshow(high_res[:,:,::-1])
plt.title('High Resolution Size = {0}X{1}'.format(high_res.shape[1],high_res.shape[0]))
plt.subplot(1,3,2),plt.imshow(high_res2[:,:,::-1])
plt.title('High Resolution2 Size = {0}X{1}'.format(high_res2.shape[1],high_res2.shape[0]))
plt.subplot(1,3,3),plt.imshow(high_res3[:,:,::-1])
plt.title('High Resolution3 Size = {0}X{1}'.format(high_res3.shape[1],high_res3.shape[0]))
plt.show()



업샘플링했지만 약간 이미지가 블러링 된 모습을 볼 수 있다.

Laplacian Pyramids는 Gaussian Pyramids로 부터 형성된다. 라플라시안 피라미드 이미지는 이미지에서 가장자리만 남은 모습이다. 많은 요소들이 0으로 형성된다. 이미지 압축에 사용이 된다. 라플라시안 피라미드의 레벨은 가우스 피라미드의 레벨과 가우스 피라미드의 상위 레벨의 확장 버전의 차이에 의해 형성된다. 라플라시안의 레벨의 3가지 레벨은 아래처럼 보일 것이다.

lap = cv2.Laplacian(cv2.subtract(high_res,low_res),0)
plt.imshow(lap)


매우 흐릿하게 선이 흰색 선이 보인다. 약간 Canny Edge Detection의 결과와 유사하다.

Image Blending using Pyramids

피라미드의 응용 중 하나는 이미지 블렌딩이다. 예를 들어, 이미지를 붙일 때, 두 개의 이미지를 함께 쌓아야 하지만, 이미지간 불연속 때문에 좋게 보이지 않을 수 있다. 이 경우에, 피라이드를 이용한 이미지 블렌딩을 하면 이미지에 많은 데이터를 남기지 않고도 매끄럽게 합칠 수 있다. 이것이 앞서 말한 새로운 과일을 만드는 방법인데, 이를 사람 얼굴을 합치는 것을 해보겠다!

  1. 두 사진을 로드한다.
  2. 두 사진에 대해 가우시안 피라미드를 찾는다(6레벨까지)
  3. 가우시안 피라미드에서 라플라시안 피라미드를 찾아라.
  4. 이제 하나의 사진의 반과 다른 사진의 반을 라플라시안 피라미드의 각 레벨에 넣어라
  5. 마지막으로 이 공동 이미지 피라미드로부터, 원래의 이미지를 재구성한다.

아래에 코드가 있다!

suzy = cv2.imread('./images/suzy.png',cv2.IMREAD_COLOR)
irene = cv2.imread('./images/irene.png',cv2.IMREAD_COLOR)

plt.figure(figsize=(12,8))
plt.subplot(2,2,1), plt.imshow(suzy[:,:,::-1])
plt.axis('off'), plt.title("Original Suzy")
plt.subplot(2,2,2), plt.imshow(irene[:,:,::-1])
plt.axis('off'), plt.title('Original Irene')


# 수지 사진의 가우시안 피라미드를 생성한다.
G = suzy.copy()
gpSuzy = [G]
for i in range(6):
    G = cv2.pyrDown(gpSuzy[i])
    gpSuzy.append(G)

# 아이린 사진의 가우시안 피라미드를 생성한다.
G = irene.copy()
gpIrene = [G]
for i in range(6):
    G = cv2.pyrDown(gpIrene[i])
    gpIrene.append(G)

# 수지 사진의 라플라시안 피라미드를 생성한다.
lpSuzy = [gpSuzy[5]]
for i in range(5,0,-1):
    size = (gpSuzy[i-1].shape[1], gpSuzy[i-1].shape[0])
    GE = cv2.pyrUp(gpSuzy[i],dstsize=size)
    L = cv2.subtract(gpSuzy[i-1],GE)
    lpSuzy.append(L)

# 아이린 사진의 라플라시안 피라미드를 생성한다.
lpIrene = [gpIrene[5]]
for i in range(5,0,-1):
    size = (gpIrene[i-1].shape[1], gpIrene[i-1].shape[0])
    GE = cv2.pyrUp(gpIrene[i],dstsize=size)
    L = cv2.subtract(gpIrene[i-1],GE)
    lpIrene.append(L)    

# 각 레벨에서 이미지좌측과 우측의 반을 더한다
LS = []
for suzy_h,irene_h in zip(lpSuzy,lpIrene):
    rows,cols,dpt = suzy_h.shape
    ls = np.hstack((suzy_h[:,0:cols//2], irene_h[:,cols//2:]))
    LS.append(ls)

# 새로 재구성한다.
ls_ = LS[0]
for i in range(1,6):
    size = (LS[i].shape[1], LS[i].shape[0])
    ls_ = cv2.pyrUp(ls_,dstsize=size)
    ls_ = cv2.add(ls_,LS[i])

# 이미지를 그냥 반반 합친 것
real = np.hstack((suzy[:,:cols//2],irene[:,cols//2:]))

plt.subplot(2,2,3),plt.imshow(real[:,:,::-1])
plt.axis('off'), plt.title("Simple Blending")
plt.subplot(2,2,4),plt.imshow(ls_[:,:,::-1])
plt.axis('off'), plt.title('Blending with Pyramids')
plt.show()


(좌) 수지 / (우) 아이린


(좌) 아이린 / (우) 수지


각 사진의 화질도 다르고 얼굴 형태가 달라서 붙이기가 힘들었다.. 최대한 규격을 맞췄지만 이미지가 뿌옇게 변하는 것은 resolution을 더 높혀야 해결이 될 것 같다.(그냥 cv2.pyrUp은 해봤는데 비슷했고, super-resolution 쪽으로 해봐야하지 않나 싶다..)

728x90
반응형