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

OpenCV Python:3通道浮点32图像读取的快速解决方案?,python,image,performance,opencv,image-processing,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 inte

我需要类型为
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
imread
以BGR顺序读取图像)

对于大型图像集来说,这个过程相当耗时:我加载数千幅图像进行预处理,然后将图像输入到TensorFlow中实现的一些神经网络中


有没有办法提高这种方法的性能?

使用这种方法,您可能无法做太多事情来加快图像读取速度。我认为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
文件中,然后将数据直接加载到列表中。这样你只需要一次又一次的缓慢加载。正如下面注释中所述,酸洗文件意味着将其解压缩为原始数据,因此文件的大小将大得多。您可以使用正确的类型和通道顺序创建与现在相同的列表(缓冲区),然后pickle该列表;当需要培训时,您可以加载pickle文件;它的速度快得多,而且超级简单:

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

我建议您不要将所有图像附加到缓冲区,只需对单个图像执行此过程,然后再将其传递到您的神经网络。问题是,批处理(即图像的4D张量,如
(4,600,800,3)
,用于4个尺寸为800x600、具有3个颜色通道的图像)可以轻松地在GPU上并行运行,因此,神经网络的性能得到了极大的提升。此外,它还有利于网络的权重更新。这就是为什么我想同时传递多个图像的原因。良好的性能测试和使用pickle是有意义的。谢谢@daniel451还将整个图像集的加载分散在多个线程之间,这应该也会有所帮助。此外,请记住,预处理的数据将a)不使用压缩b)大4倍,因此结果将更重于I/O。@DanMašek非常好的观点,我也将在文章中记录这一点。