영상처리를 하면서 많이 사용되는 패키지들의 차이를 알아보고 각각의 데이터 구조를 살펴보고 서로간의 데이터 전환을 하는 방법을 정리한다.
OpenCV
그동안 제일 익숙한 패키지이다.
OpenCV는 기본 적으로 BGR 채널을 사용한다. 내부적으로 Numpy 를 기반으로 데이터 접근이 가능하다.
import cv2
from PIL import Image
# Load an image with OpenCV
image_cv = cv2.imread('path_to_your_image.jpg') # replace with your image path
# Convert from BGR to RGB
image_cv = cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB)
# Convert to a PIL Image
image_pil = Image.fromarray(image_cv)
PILImage
Python 에서 사용하는 pillow 패키지의 이미지 데이터이이다.
PILImage로 이미지를 로드하면 RGB 채널로 불러온다.
OpenCV 나 Tensor 로 변환하기 위해서는 numpy 로 먼저 변환을 해야한다.
import numpy as np
import cv2
from PIL import Image
# Open an image file with PIL
image_pil = Image.open('path_to_your_image.jpg') # replace with your image path
# Convert the PIL Image to a numpy array (in RGB order)
image_np = np.array(image_pil)
# Convert from RGB to BGR
image_cv = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)
Image Tensor
Tensor는 0~1사이의 실수 값이며 (Channel, Height, Width) 3차원으로 데이터를 저장하며, 채널은 PILImage와 같이 RGB이다.
PILImage 와는 같지만 OpenCV 와는 다르기 때문에 주의해야한다.
torchvision의 transform의 ToTensor() 을 사용하면 바로 Tensor 로 변환이 가능하다.
ToTensor를 사용하면 numpy 의 채널이 (H,W,C)이지만 자동으로 (C,H,W)로 변환한다.
import cv2
import torchvision.transforms as transforms
from PIL import Image
import numpy as np
# Open an image file with OpenCV
img_cv = cv2.imread('path_to_your_image.jpg') # replace with your image path
# Convert the OpenCV image (BGR order) to RGB order
img_cv = cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)
# Convert the OpenCV image (which is a numpy array now in RGB order) to a PyTorch tensor
img_tensor_cv = transforms.ToTensor()(img_cv)
# Open the same image file with PIL
img_pil = Image.open('path_to_your_image.jpg') # replace with your image path
# Convert the PIL image to a PyTorch tensor
img_tensor_pil = transforms.ToTensor()(img_pil)
# Compare the tensors
print("Are the tensors equal?", np.allclose(img_tensor_cv.numpy(), img_tensor_pil.numpy()))
비교 테이블
Numpy | OpenCV | PILImage | Tensor | |
Color | - | BGR | RGB | RGB |
Dimensions | (H,W,C) | (H,W,C) | (X,Y,C) | (C,H,W) |
to Numpy | - | np.array(img_pil) | tensor.numpy() | |
to Tensor | torch.from_numpy() | convert BGR to RGB transforms.ToTensor() |
transforms.ToTensor() | - |
여기에서 주의할 것은 torch.from_numpy()와 transforms.ToTensor()는 비슷하지만 약간의 다른 특징이 있다.
from_numpy는 메모리를 공유하므로 tensor에서 값을 변경하면 numpy 에서도 같이 변경된다. 또한, numpy 의 shape을 그대로 가져가며 scale 도 변경하지 않는다.
반면, ToTensor는 image shape (H,W,C)->(C,H,W)로 변경하면서 [0,255] -> [0.0,1.0] 으로 normalized 변환을 한다.
동작테스트 코드
tensor_cv = transforms.ToTensor()(img_cv) #BGR
tensor_img = transforms.ToTensor()(img) #RGB
tensor_np_from_numpy = torch.from_numpy(img_np) #RGB
tensor_np_ToTensor = transforms.ToTensor()(img_np) #RGB
img_np_tr = img_np.transpose(2,0,1)
tensor_np_from_numpy_tr = torch.from_numpy(img_np_tr)
print(tensor_cv.shape)
print(tensor_img.shape)
print(tensor_np_from_numpy.shape)
print(img_np_tr.shape)
print(tensor_np_from_numpy_tr.shape)
print()
print('ToTensor share memory test')
print('before:', tensor_np_ToTensor[0,0,0],'-', img_np[0,0,0])
tensor_np_ToTensor[0,0,0] = 150
print('after tensor=150:', tensor_np_ToTensor[0,0,0],'-', img_np[0,0,0])
print('from_numpy share memory test')
print('before:',tensor_np_from_numpy_tr[0,0,0],'-', img_np_tr[0,0,0])
tensor_np_from_numpy_tr[0,0,0] = 150
print('after tensor=150:',tensor_np_from_numpy_tr[0,0,0],'-', img_np_tr[0,0,0])