본문 바로가기
Study/Python

Python에서 이미지 채널 BGR 에서 RGB로 변환하기

by 개발새-발 2021. 7. 3.
반응형

어느 날 사용할 예제 사진이 없어 전역 후 처음 먹었던 싸이 버거를 찍은 사진을 예제 사진으로 쓰기로 했었다. 평소보다도 더 환상적으로 맛있었던 그 싸이 버거를 추억하기 위해 cv2.imread()로 불러와 plt.imshow()를 이용하여 출력하였더니... 입맛을 떨어지게 하여 다이어트에 효과적이라는 파란색 음식 사진을 볼 수 있었다.

이 글에선 BGR 이미지를 RGB 이미지로 변경해 본다.

import numpy as np
import matplotlib.pyplot as plt
import cv2

from pathlib import Path

imgpath = Path('.') / 'img.jpg'
img = cv2.imread(str(imgpath))
plt.imshow(img)
<matplotlib.image.AxesImage at 0x1d50f2c1160>

이미지를 불러오는 다양한 방법들이 있다. 이때, opencv와 같은 라이브러리를 사용하는 경우가 있다. 위처럼 opencv에서 불러온 사진을 matplotlib을 이용하여 출력을 하는 경우 색이 이상하게 나오는 경우가 존재한다. 이는 사진을 불러오고 numpy배열에 저장하고, 이 배열을 읽는 방법이 opencvmatplotlib가 다르기 때문이다.

opencv의 imread는 BGR의 순서로 numpy 배열에 채널별로 저장한다. 그러나 이렇게 저장된 배열을 matplotlib에선 RGB의 채널 순서로 읽는다. 결국 R과 B의 값이 뒤바뀐 채로 이미지가 출력되는 것이다. 이를 해결하는 방법은 간단하다. numpy 배열에 저장된 값에서 채널을 재배열하면 된다.

cv2.cvtColor()

opencv에선 이미 관련 기능을 제공하고 있다. cv2.cvtColor() 로 BGR 이미지를 RGB이미지로 변환하는 것뿐만 아니라, 흑백 이미지로 만들고 hsv 색상 공간으로도 변환할 수 있다.

# BGR2RGB
img_cv2 = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
plt.imshow(img_cv2)
<matplotlib.image.AxesImage at 0x1d50fa51640>

내 추억의 싸이버거가 본연의 색을 되찾았다. BGR에서 흑백사진(grayscale)으로도 변경해보자.

# BGR2GRAY
img_cv2_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
print(img_cv2_gray.shape)
plt.imshow(img_cv2_gray,cmap='gray')
(1692, 1692)
<matplotlib.image.AxesImage at 0x1d511ebf340>

cv2.cvtColor()는 dst를 지정해서 결과가 들어갈 배열을 정해줄 수 있다.

# BGR2RGB with destination
dest = np.empty(img.shape,dtype=np.uint8)
cv2.cvtColor(img,cv2.COLOR_BGR2RGB,dest)
plt.imshow(dest)
<matplotlib.image.AxesImage at 0x1d512a32910>

numpy 배열 직접 조작

numpy 배열을 직접 조작하여 이미지의 채널을 변경할 수도 있다.

img_np1 = img[...,::-1]
plt.imshow(img_np1)
<matplotlib.image.AxesImage at 0x1d5132d3dc0>

img_np2 = img[...,[2,1,0]]
plt.imshow(img_np2)
<matplotlib.image.AxesImage at 0x1d5143c68e0>

주의해야 할 점

numpy 배열을 직접 조작하는 방식으로 이미지를 변환할 때 주의해야 하는 점이 있다. cvtColor를 이용하거나 numpy배열의 fancy indexing을 사용하는 경우에는 생성되는 결과물이 원본 배열과 다른 배열을 만들어서 생성된다. 그러나 채널 읽는 순서를 반대로 읽도록 indexing을 하는 방법 ([...,::-1])은 메모리상 같은 배열을 사용하고 있고, 메모리상에서 읽는 순서만 달라진 것이기 때문에 이 이미지를 수정하면 원본 이미지도 변하게 된다.

아래 코드를 보면 각각의 변형된 이미지들의 base가 원본 이미지와 같은지 확인할 수 있다.

# with cv2.cvtColor
print(img_cv2.base is img)

# with [...,::-1]
print(img_np1.base is img)

# with [...,[2,1,0]] (fancy indexing)
print(img_np2.base is img)
False
True
False

base가 같은 이미지를 조작하자 원본 이미지도 수정됨을 볼 수 있다.

img_np1[:700,:700] = 0
plt.imshow(img_np1)
plt.show()
plt.imshow(img)
plt.show()

 

반응형

댓글