从文件夹中的图像序列获取一个numpy数组

时间:2018-12-08 01:27:21

标签: python numpy image-processing keras python-imaging-library

我有一个文件夹,说video1,其中包含frame_00.png, frame_01.png, ...顺序的一堆图像

我想要的是格式为(number of frames, w, h, 3)

的4D numpy数组

这是我所做的,但是我认为它很慢,有没有更快或更有效的方法来实现同一目标?

folder = "video1/"

import os
images = sorted(os.listdir(folder)) #["frame_00", "frame_01", "frame_02", ...]

from PIL import Image 
import numpy as np 

video_array = []
for image in images:
    im = Image.open(folder + image)
    video_array.append(np.asarray(im)) #.transpose(1, 0, 2))

video_array = np.array(video_array)
print(video_array.shape)
#(75, 50, 100, 3)

3 个答案:

答案 0 :(得分:1)

关于这个主题,有一个older SO thread涉及了很多细节(也许有些过多)。与其投票否决以重复的方式结束这个问题,不如让我快速总结一下该线程的主要要点:

  • 最快的常用图像读取功能是Async软件包中的imread
  • 读取图像,然后将它们添加到普通的Python列表中(就像您已经做的那样)是读取大量图像的最快方法。
  • 但是,考虑到最终要将图像列表转换为图像阵列,构建图像阵列的每种可能方法几乎都与其他方法一样快
    • 尽管有趣的是,如果您采用将图像直接分配给预分配的数组的方法,那么实际上对于获得最佳性能分配给哪个索引(即哪个维度)很重要。

因此,基本上,使用纯单线程Python时,您将无法获得更快的速度。从切换到cv2(代替cv2.imread)可能会有所帮助。

答案 1 :(得分:1)

PNG是一种非常慢的格式,因此,如果您几乎可以使用其他任何格式,都会看到很大的加速。

例如,这是您的程序的opencv版本,该版本从命令行args获取文件名:

#!/usr/bin/python3

import sys
import cv2
import numpy as np

video_array = []
for filename in sys.argv[1:]:
    im = cv2.imread(filename)
    video_array.append(np.asarray(im)) 

video_array = np.array(video_array)
print(video_array.shape)

我可以这样运行它:

$ mkdir sample
$ for i in {1..100}; do cp ~/pics/k2.png sample/$i.png; done
$ time ./readframes.py sample/*.png
(100, 2048, 1450, 3)

real    0m6.063s
user    0m5.758s
sys 0m0.839s

因此6秒钟即可读取100个PNG图像。如果我改用TIFF:

$ for i in {1..100}; do cp ~/pics/k2.tif sample/$i.tif; done
$ time ./readframes.py sample/*.tif
(100, 2048, 1450, 3)

real    0m1.532s
user    0m1.060s
sys 0m0.843s

1.5秒,因此快了四倍。

使用pyvips可能会加快速度:

#!/usr/bin/python3

import sys
import pyvips
import numpy as np

# map vips formats to np dtypes
format_to_dtype = {
    'uchar': np.uint8,
    'char': np.int8,
    'ushort': np.uint16,
    'short': np.int16,
    'uint': np.uint32,
    'int': np.int32,
    'float': np.float32,
    'double': np.float64,
    'complex': np.complex64,
    'dpcomplex': np.complex128,
}   

# vips image to numpy array
def vips2numpy(vi):
    return np.ndarray(buffer=vi.write_to_memory(),
                      dtype=format_to_dtype[vi.format],
                      shape=[vi.height, vi.width, vi.bands])

video_array = []
for filename in sys.argv[1:]:
    vi = pyvips.Image.new_from_file(filename, access='sequential')
    video_array.append(vips2numpy(vi)) 

video_array = np.array(video_array)
print(video_array.shape)

我知道:

$ time ./readframes.py sample/*.tif
(100, 2048, 1450, 3)

real    0m1.360s
user    0m1.629s
sys 0m2.153s

另外10%左右。

最后,正如其他张贴者所说,您可以并行加载框架。这对TIFF并没有多大帮助,但肯定会提高PNG。

答案 2 :(得分:-1)

否,没有直接方法可以从文件夹中拍摄图像。您需要像遍历一样遍历每个文件并将其转换为numpy数组。