Python 이미지 읽기 및 쓰기 방법 비교

  시각 관련 신경망 모델을 훈련 할 때 항상 이미지 읽기 및 쓰기가 사용됩니다. matplotlib, cv2, PIL 등과 같은 많은 방법이 있습니다. 다음은 훈련 속도를 향상시키는 가장 빠른 방법을 선택하기 위해 여러 가지 읽기 및 쓰기 방법을 비교합니다.

실험 표준

  학습에 사용되는 프레임 워크는 Pytorch이므로 읽기에 대한 실험 표준은 다음과 같습니다.

  1. 해상도가 1920x1080 인 5 장의 사진 (PNG 형식으로 1 장, jpg 형식으로 4 장)을 읽고 배열에 저장합니다.

  2. 읽기 배열을 차원 순서가 CxHxW 인 Pytorch 텐서로 변환하고 비디오 메모리에 저장합니다 (교육용 GPU 사용). 여기서 3 개 채널의 순서는 RGB입니다.

  3. 위 작업에서 각 방법에 소요 된 시간을 기록합니다. png 형식의 이미지 크기는 jpg 형식의 이미지 크기보다 품질이 약간 다르지만 거의 10 배이므로 데이터 세트는 일반적으로 png로 저장되지 않으므로 두 형식 간의 읽기 시간 차이는 비교되지 않습니다.

  작성된 실험 표준은 다음과 같습니다.

  1. 5 개의 1920x1080 이미지에 해당하는 Pytorch 텐서를 해당 방법에서 사용할 수있는 데이터 유형의 배열로 변환합니다.

  2. 5 장의 사진을 jpg 형식으로 저장합니다.

  3. 사진을 저장하기 위해 각 방법에 소요 된 시간을 기록합니다.

실험적 상황

cv2

  GPU 때문에 cv2에는 그림을 읽는 두 가지 방법이 있습니다.

  1. 먼저 모든 그림을 numpy 배열로 읽은 다음 GPU에 저장된 pytorch 텐서로 변환합니다.

  2. GPU에 저장된 pytorch 텐서를 초기화 한 다음 각 이미지를이 텐서에 직접 복사합니다.

  첫 번째 방법의 실험 코드는 다음과 같습니다.

import os, torch
import cv2 as cv 
import numpy as np 
from time import time 
 
read_path = 'D:test'
write_path = 'D:test\\write\\'
 
# cv2读取 1
start_t = time()
imgs = np.zeros([5, 1080, 1920, 3])
for img, i in zip(os.listdir(read_path), range(5)): 
  img = cv.imread(filename=os.path.join(read_path, img))
  imgs[i] = img   
imgs = torch.tensor(imgs).to('cuda')[...,[2,1,0]].permute([0,3,1,2])/255 
print('cv2 读取时间1:', time() - start_t) 
# cv2保存
start_t = time()
imgs = (imgs.permute([0,2,3,1])[...,[2,1,0]]*255).cpu().numpy()
for i in range(imgs.shape[0]): 
  cv.imwrite(write_path + str(i) + '.jpg', imgs[i])
print('cv2 保存时间:', time() - start_t) 

  실험 결과:

cv2 读取时间1: 0.39693760871887207
cv2 保存时间: 0.3560612201690674

  두 번째 방법의 실험 코드는 다음과 같습니다.

import os, torch
import cv2 as cv 
import numpy as np 
from time import time 
 
read_path = 'D:test'
write_path = 'D:test\\write\\'
 
 
# cv2读取 2
start_t = time()
imgs = torch.zeros([5, 1080, 1920, 3], device='cuda')
for img, i in zip(os.listdir(read_path), range(5)): 
  img = torch.tensor(cv.imread(filename=os.path.join(read_path, img)), device='cuda')
  imgs[i] = img   
imgs = imgs[...,[2,1,0]].permute([0,3,1,2])/255 
print('cv2 读取时间2:', time() - start_t) 
# cv2保存
start_t = time()
imgs = (imgs.permute([0,2,3,1])[...,[2,1,0]]*255).cpu().numpy()
for i in range(imgs.shape[0]): 
  cv.imwrite(write_path + str(i) + '.jpg', imgs[i])
print('cv2 保存时间:', time() - start_t) 

  실험 결과:

cv2 读取时间2: 0.23636841773986816
cv2 保存时间: 0.3066873550415039

matplotlib

  동일한 두 가지 읽기 방법, 첫 번째 코드는 다음과 같습니다.

import os, torch 
import numpy as np
import matplotlib.pyplot as plt 
from time import time 
 
read_path = 'D:test'
write_path = 'D:test\\write\\'
 
# matplotlib 读取 1
start_t = time()
imgs = np.zeros([5, 1080, 1920, 3])
for img, i in zip(os.listdir(read_path), range(5)): 
  img = plt.imread(os.path.join(read_path, img)) 
  imgs[i] = img    
imgs = torch.tensor(imgs).to('cuda').permute([0,3,1,2])/255  
print('matplotlib 读取时间1:', time() - start_t) 
# matplotlib 保存
start_t = time()
imgs = (imgs.permute([0,2,3,1])).cpu().numpy()
for i in range(imgs.shape[0]):  
  plt.imsave(write_path + str(i) + '.jpg', imgs[i])
print('matplotlib 保存时间:', time() - start_t) 

  실험 결과:

matplotlib 读取时间1: 0.45380306243896484
matplotlib 保存时间: 0.768944263458252

  코드를 실험하는 두 번째 방법 :

import os, torch 
import numpy as np
import matplotlib.pyplot as plt 
from time import time 
 
read_path = 'D:test'
write_path = 'D:test\\write\\'
 
# matplotlib 读取 2
start_t = time()
imgs = torch.zeros([5, 1080, 1920, 3], device='cuda')
for img, i in zip(os.listdir(read_path), range(5)): 
  img = torch.tensor(plt.imread(os.path.join(read_path, img)), device='cuda')
  imgs[i] = img    
imgs = imgs.permute([0,3,1,2])/255  
print('matplotlib 读取时间2:', time() - start_t) 
# matplotlib 保存
start_t = time()
imgs = (imgs.permute([0,2,3,1])).cpu().numpy()
for i in range(imgs.shape[0]):  
  plt.imsave(write_path + str(i) + '.jpg', imgs[i])
print('matplotlib 保存时间:', time() - start_t) 

  실험 결과:

matplotlib 读取时间2: 0.2044532299041748
matplotlib 保存时间: 0.4737534523010254

  png 형식 그림을 읽는 matplotlib에서 얻은 배열의 값은 $ [0, 1] $ 범위의 부동 소수점 숫자이고 jpg 형식 그림은 $ [0, 255] $ 범위의 정수입니다. 따라서 데이터 세트의 이미지 형식이 일치하지 않는 경우 읽기 전에 동일하게 변환하도록주의하십시오. 그렇지 않으면 데이터 세트의 전처리가 번거로울 것입니다.

PIL

  PIL의 읽기와 쓰기는 pytorch tensor 나 numpy array를 직접 사용할 수 없습니다. 먼저 Image type으로 변환해야하므로 매우 번거 롭습니다. 시간 복잡도는 확실히 불리하므로 실험하지 않겠습니다.

횃불

  torchvision提供了直接从pytorch张量保存图片的功能,和上面读取最快的matplotlib的方法结合,代码如下:

import os, torch  
import matplotlib.pyplot as plt 
from time import time 
from torchvision import utils 

read_path = 'D:test'
write_path = 'D:test\\write\\'
 
# matplotlib 读取 2
start_t = time()
imgs = torch.zeros([5, 1080, 1920, 3], device='cuda')
for img, i in zip(os.listdir(read_path), range(5)): 
  img = torch.tensor(plt.imread(os.path.join(read_path, img)), device='cuda')
  imgs[i] = img    
imgs = imgs.permute([0,3,1,2])/255  
print('matplotlib 读取时间2:', time() - start_t) 
# torchvision 保存
start_t = time() 
for i in range(imgs.shape[0]):   
  utils.save_image(imgs[i], write_path + str(i) + '.jpg')
print('torchvision 保存时间:', time() - start_t) 

  实验结果:

matplotlib 读取时间2: 0.15358829498291016
torchvision 保存时间: 0.14760661125183105

  可以看出这两个是最快的读写方法。另外,要让图片的读写尽量不影响训练进程,我们还可以让这两个过程与训练并行。另外,utils.save_image可以将多张图片拼接成一张来保存,具体使用方法如下:

utils.save_image(tensor = imgs,     # 要保存的多张图片张量 shape = [n, C, H, W]
                 fp = 'test.jpg',   # 保存路径
                 nrow = 5,          # 多图拼接时,每行所占的图片数
                 padding = 1,       # 多图拼接时,每张图之间的间距
                 normalize = True,  # 是否进行规范化,通常输出图像用tanh,所以要用规范化 
                 range = (-1,1))    # 规范化的范围

추천

출처blog.csdn.net/qq_37189298/article/details/109699749