python - 使用 TensorFlow 和 tf.data.Dataset 从文件夹中采样一系列图像
问题描述
考虑一个具有文件夹名称和相应标签的数据框。每个文件夹包含来自视频文件的任意数量的图像。我正在寻找一种方法来从文件夹中采样一系列图像tf.data.Dataset
来训练动作识别模型。像这样的东西:
ds = tf.data.Dataset.from_tensor_slices(list_of_folders)
def read_and_preprocess_images_from_folder(folder):
list_of_image_names = some_function_to_list_files(folder)
list_length = len(list_of_image_names)
upper_boundary = list_length - sequence_length
random_start_index = tf.random_uniform(shape=[], minval=0, maxval=upper_boundary, dtype=tf.int64)
random_sequence = list_of_image_names[random_start_index:random_start_index+sequence_length]
return convert_sequence_to_image_tensor(random_sequence)
到目前为止我所做的:
df = pd.DataFrame({'folder': ['folder_0', 'folder_1'], 'target': [0, 1]})
ds = tf.data.Dataset.from_tensor_slices((df.folder.values, df.target.values))
def load_and_preprocess_image_sequence(folder):
x = tf.io.matching_files('/path/to/folders/' + folder + '/*.jpg')
x = tf.map_fn(lambda x: preprocess_image(tf.read_file(x)), x, dtype=tf.float32)
return x
def preprocess_image(x):
x = tf.image.decode_jpeg(x, channels=3)
x = tf.image.resize_images(x, size=(IMAGE_SIZE,IMAGE_SIZE))
return x
def load_and_preprocess_from_folder_label(folder, label):
return load_and_preprocess_image_sequence(folder), label
train_ds = train_ds.map(load_and_preprocess_from_folder_label)
我得到:
<DatasetV1Adapter shapes: ((?, 224, 224, 3), ()), types: (tf.float32, tf.int64)>
问题是tf.io.matching_files
与 一起使用时返回一个没有形状的张量tf.data.Dataset
。它仅在急切执行期间返回定义的形状。
我试图以不同的方式解决这个问题。知道每个文件夹中的每个图像都具有['0001.jpg', '0002.jpg']
我尝试使用的相同结构,np.random.randint
但问题是np.random.randint
每次都会产生相同的结果:
def load_and_preprocess_image_sequence(folder):
random_start_index = np.random.randint(0,upper_boundary)
x = []
for i in range(random_start_index, random_start_index+sequence_length):
x.append('/path/to/folders/' + folder + f'/{i:04d}.jpg')
x = [tf.read_file(i) for i in x]
x = [preprocess_image(i) for i in x]
x = tf.stack(x, axis=0)
return x
它工作正常,除了random_start_index
每次都一样。为了解决随机性问题,我必须使用tf.random_uniform
:
def load_and_preprocess_image_sequence(folder):
random_start_index = tf.random_uniform(shape=[], minval=0, maxval=upper_boundary, dtype=tf.int64)
range = tf.map_fn(lambda x: x + random_start_index, tf.range(sequence_length, dtype=tf.int64))
我得到一个连续数字的张量,从随机开始,长度等于sequence_length
. 现在的问题是它tf.strings.format
有点有限,不能产生与 python 格式相当的结果,例如f'{i:04d}.jpg'
.
解决方案
我能够解决这个问题。这是一个例子:
x = tf.io.matching_files(folder + '/*.jpg')
max_start_index = tf.cast(len(x) - SEQUENCE_LEN, tf.int64)
if max_start_index == 0:
random_start_index = max_start_index
else:
random_start_index = tf.random.uniform(shape=[], minval=0, maxval=max_start_index, dtype=tf.int64)
x = x[random_start_index:random_start_index + SEQUENCE_LEN]
x = tf.map_fn(lambda x: load_image(x), x, dtype=tf.uint8)
推荐阅读
- docker - 如何使用 docker-compose 将 /var/run/docker.sock usr/bin/docker 挂载到 docker 容器?
- python - X 轴上的年份值
- ios - 如何访问 childByAutoID 下的 Firebase 数据?
- c# - C# 基本类型列表添加通用子实例
- actionscript-3 - 使用 AS3 循环播放 MP4 视频
- python - 使用python检测图像中的文本
- android - 数据绑定使用 Glide 和 kotlin 找不到符号
- testing - Jmeter继续读取多个用户的多行
- c++ - 我们如何通过键盘而不是鼠标单击来控制 VC6 gui 中的按钮?
- javascript - 我想获取 javascript 数组范围之间的值