OpenCV Python:3通道float32图像读取的快速解决方案?

时间:2017-08-25 22:30:58

标签: python image performance opencv image-processing

我需要类型为float32的3通道RBG排序彩色图像,每个颜色通道的值为[0.0, 1.0]

这是我目前的解决方案:

def read_images(imagelist):
    buffer = list()
    for f in imagelist:
        # load single image, convert to float32
        img = cv2.imread(f).astype(np.float32)
        # change interval from [0, 255] to [0.0, 1.0]
        img /= 255.0
        # leave out alpha channel, if any
        if img.shape[2] == 4:
           img = img[:, :, 0:3]
        buffer.append(img)
    return np.array(buffer)

之后,在图像处理程序中,我将BGR更改为RGB排序(因为cv2的{​​{1}}默认以BGR顺序读取图像。)

对于大型图像集来说,此过程非常耗时:我正在加载数千张图像进行预处理,然后将图像提供给TensorFlow中实现的某些神经网络。

有没有办法改善这种方法的表现?

1 个答案:

答案 0 :(得分:10)

通过这种方法,您可以做的不是太多,以加快您的图像阅读速度。我想Matplotlib可能会更快,因为它直接读取浮点数并按RGB顺序读取,但即使在转换类型和通道顺序后,它也会像OpenCV一样慢三倍。 PIL比Matplotlib快一点,但速度仍然是OpenCV的两倍,所以没有帮助,scikit-image与PIL速度大致相同:

import matplotlib.image as mpimg
import cv2
import numpy as np
from skimage import io
from PIL import Image

import timeit
times = range(1000)

# matplotlib
start_time = timeit.default_timer()
for t in times:
    img = mpimg.imread('img1.png')
print("mpimg.imread(): ", timeit.default_timer() - start_time, "s")

# OpenCV
start_time = timeit.default_timer()
for t in times:
    img = cv2.cvtColor(
        cv2.imread('img1.png'), cv2.COLOR_BGR2RGB).astype(np.float32)/255.0
print("cv2.imread(): ", timeit.default_timer() - start_time, "s")

# scikit-image
start_time = timeit.default_timer()
for t in times:
    img = io.imread('img1.png').astype(np.float32)/255.0
print("io.imread(): ", timeit.default_timer() - start_time, "s")

# PIL
start_time = timeit.default_timer()
for t in times:
    img = np.asarray(Image.open('img1.png')).astype(np.float32)/255.0
print("Image.open(): ", timeit.default_timer() - start_time, "s")
  

mpimg.imread():37.68960806101677 s
  cv2.imread():13.830177563999314 s
  io.imread():29.395271296001738 s
  Image.open():26.633562815986807 s

相反,通过读取所有图像并将它们保存为更好的读取格式(即直接从字节读取)而不是使用图像读取器来预处理可能更好。您可以将图像序列化(pickle)为.p.pickle文件,然后将数据直接加载到列表中。这样你就必须只进行一次慢速加载。正如下面评论中的Dan Mašek所述,挑选文件意味着将它们解压缩为原始数据,因此文件大小更大。您可以使用正确的类型和通道顺序创建与现在相同的列表(缓冲区),然后选择列表;当你需要训练时,你可以加载泡菜文件;它的方式更快,更简单:

with open(training_file, mode='rb') as f:
    training_data = pickle.load(f)