如何通过keras中的键加载图像数据?

时间:2017-03-03 17:05:41

标签: keras

我一直致力于将图像作为输入的顺序模型。然而,不同的是输入图像实际上是由键确定的 例如,训练序列是(您可以假设 fi 是视频的帧ID)

{ f1, f2, f3, ..., fn }

并且相应的图像序列是

{ M[f1], M[f2], M[f3], ..., M[fn] }

其中M是存储{ fi->图像}映射的地图 假设在下一批中,我的训练序列成为

{ f2, f3, ..., fn+1 }  

,图像序列变为

{ M[f2], M[f3], M[f4], ..., M[fn+1] }

如您所见,如果我直接将图像序列保存到磁盘中,则存在大量冗余(在上述情况下,M [f2]到M [fn]被保存两次)。因此,似乎有必要通过键引用图像,因此不能使用imagedataloader类 [修改]
我的模型是 2级分类器,将图像序列作为输入,其中图像使用帧ID fi )进行映射。在 data_preprocess 代码中预先生成图像序列是正还是负 正面样本可能如下所示:

{f3,  f4,  f5,  f6,  f7}     1
{f4,  f5,  f6,  f7,  f8}     1
{f5,  f6,  f7,  f8,  f9}     1
...

否定样本如下所示:

{f1,  f2,  f3,  f4,  f5}     0
{f2,  f3,  f4,  f5,  f6}     0
{f10, f11, f12, f13, f14}    0
...

因此,它不像图像分类问题,其中图像具有完全固定的标签。在我的情况下,每个图像将被使用多次,它们的正面或负面由整个序列决定,但不是由它自己决定。
[ EDIT II ]
图像是N个视频的帧,并存储在磁盘上,如下所示:

|-data_root/
  |-Video 1/
  | |-frame_1_1.jpg
  | |-frame_1_2.jpg
  | ...
  |-Video 2/
  | |-frame_2_1.jpg
  | |-frame_2_2.jpg
  | ...
  ...
  ...
  |-Video N/
  | |-frame_N_1.jpg
  | |-frame_N_2.jpg
    ...

我想做的是,给定两个场景的帧/图像序列,模型预测两个场景是否属于同一类型。
由于视频可能包含每个场景的长时间跨度,因此我将场景的整个序列划分为多个非重叠子序列(省略视频索引):

Sequence of scene i: frame_1,  frame_2,  frame_3,  ..., frame_n
Sub-sequence i_1:    frame_1,  frame_2,  frame_3,  ..., frame_10
Sub-sequence i_2:    frame_11, frame_12, frame_13, ..., frame_20
Sub-sequence i_3:    frame_21, frame_22, frame_23, ..., frame_30
...

然后,我随机生成阳性样本Pi(由相同序列生成的子序列对),如:

   <Pair of sub-sequences>                 <Labels>
P1 {sub-sequence i_4, sub-sequence i_2},      1
P2 {sub-sequence i_3, sub-sequence i_5},      1
...                                       ...

对于阴性样本,我从不同的场景中生成子序列(Ni):

   <Pair of sub-sequences>                 <Labels>
N1 {sub-sequence i_1, sub-sequence j_6},      0
N2 {sub-sequence i_2, sub-sequence j_4},      0
...                                       ...

很明显,一个帧/图像可以在不同的训练样本中多次出现。例如。在上述情况下,N2和P1都包含子序列i_2。因此,我选择按帧ID序列( fi )保存生成的样本对,并在训练期间,按帧ID( fi )获取序列的相应帧/图像。
我应该如何优雅地与Keras一起做?

1 个答案:

答案 0 :(得分:4)

不确定如何构建序列但是您是否考虑过使用ImageDataGenerator from keras.preprocessing.image

使用所需的任何参数构建此对象后,可以使用flow_from_directory(directory_path)方法。完成此操作后,您可以使用此对象的filename属性:

my_generator = ImageDataGenerator(...)
my_generator.flow_from_directory(path_dir)
list_of_file_names = my_generator.filename

现在,您可以在列表的索引和列表的元素(= file_paths)之间建立映射。

我希望这有帮助吗?

编辑:

由此,您可以构建一个映射字典

map_images = {str(os.path.splitext(os.path.split(file_path)[1])[0]): file_path for file_path in list_of_file_names}

这将使用ImageDataGenerator从您的图像文件夹中检索file_path,它会提取文件名,删除文件扩展名并将文件名转换为string,这是您的frame_id。

您现在可以在frame_idfile_path之间使用load_img() and img_to_array() from keras.preprocessing.image

函数load_img()定义如下并返回PIL图像实例:

  

def load_img(path, grayscale=False, target_size=None): """Loads an image into PIL format. # Arguments path: Path to image file grayscale: Boolean, whether to load the image as grayscale. target_size: Either 'None' (default to original size) or tuple of ints '(img_height, img_width)'. # Returns A PIL Image instance. # Raises ImportError: if PIL is not available. """

然后img_to_array()定义如下并返回一个3D numpy数组来提供模型:

  

def img_to_array(img, dim_ordering='default'): """Converts a PIL Image instance to a Numpy array. # Arguments img: PIL Image instance. dim_ordering: Image data format. # Returns A 3D Numpy array. # Raises ValueError: if invalid 'img' or 'dim_ordering' is passed. """

总结一下:1在frame_id和相应文件的路径之间建立一个映射。然后使用img_load()img_to_array()加载文件。我希望我能正确理解你的问题!

编辑2:

看到您的新编辑,现在我了解了您的文件系统的结构,我们甚至可以在您的字典中添加这样的视频:

# list of video_id of each frame
videos = my_generator.classes
# mapping of the frame_id to path_of_file and vid_id
map_images = {str(os.path.splitext(os.path.split(file_path)[1])[0]): (file_path, vid_id) for file_path,vid_id in zip(list_of_file_names,videos) }