Tensorflow - 有没有一种方法来实现张量级的图像剪切/旋转/平移?

5
我正在尝试进行不同种类的(图像)数据增强以训练神经网络。
我知道tf.image提供了一些增强函数,但它们太简单了 - 例如,我只能将图像旋转90度,而不能设置任意角度。
我也知道tf.keras.preprocessing.image提供了随机旋转、随机剪切、随机移位和随机缩放。但这些方法只适用于numpy数组,而不是张量。
我知道我可以先读取图像,使用tf.keras.preprocessing.image的函数进行增强,然后将这些增强的numpy数组转换为张量。
但是,我想知道是否有一种方法可以实现张量级的增强,这样我就不需要麻烦的“图像文件->张量->numpy数组->张量”过程。

如果您想知道如何应用变换,请参考以下更新:

如需详细的源代码,请查看tf.contrib.image.transformtf.contrib.image.matrices_to_flat_transforms

这是我的代码:

def transformImg(imgIn,forward_transform):
    t = tf.contrib.image.matrices_to_flat_transforms(tf.linalg.inv(forward_transform))
    # please notice that forward_transform must be a float matrix,
    # e.g. [[2.0,0,0],[0,1.0,0],[0,0,1]] will work
    # but [[2,0,0],[0,1,0],[0,0,1]] will not
    imgOut = tf.contrib.image.transform(imgIn, t, interpolation="BILINEAR",name=None)
    return imgOut

基本上,以上代码是在做以下操作:

enter image description here 对于imgIn中的每个点(x,y)执行。

例如,沿x轴平移的剪切变换如下所示:

enter image description here

因此,我们可以像这样实现剪切变换(使用上面定义的 transformImg()函数):
def shear_transform_example(filename,shear_lambda):
    image_string = tf.read_file(filename)
    image_decoded = tf.image.decode_jpeg(image_string, channels=3)
    img = transformImg(image_decoded, [[1.0,shear_lambda,0],[0,1.0,0],[0,0,1.0]])
    return img
img = shear_transform_example("white_square.jpg",0.1)

原始图片: 输入图像描述

变换后: 输入图像描述

(请注意,img是一个张量,转换张量为图像文件的代码未包含在内。)

P.S.

以上代码适用于tensorflow 1.10.1版本,可能无法适用于未来的版本。

说实话,我真的不知道为什么他们设计tf.contrib.image.transform的方式,我们还需要使用另一个函数(tf.linalg.inv)才能得到我们想要的结果。我真的希望他们可以改变tf.contrib.image.transform以更加直观的方式工作。

2个回答

4

1
这个可行。非常感谢!对于任何想使用这个库的人,请注意这个变换是将输出映射到输入的变换。为了摆脱这个令人烦恼的“反转”变换,您可以使用tf.linalg.inv。 - user10253771

0

我通常使用 tf.data.DatasetDataset.maptf.py_func。如果 Dataset.prefetch 表示通常没有时间成本(只要在 CPU 上的预处理时间比在 GPU 上运行网络的时间短)。如果您在多个 GPU 上操作,您可能需要重新考虑,但以下内容在单 GPU 系统上运行良好。

为简单起见,假设您所有的图像都保存在单独的文件中,尽管可以轻松地适应 zip 存档或其他格式,如 hdf5(不适用于 .tar 文件 - 不确定为什么,但我认为这也不是一个好主意)。

import tensorflow as tf
from PIL import Image


def map_tf(path_tensor, label_tensor):
    # path_tensor and label_tensor correspond to a single example

    def map_np(path_str):
        # path_str is just a normal string here
        image = np.array(Image.load(path_str), dtype=np.uint8)
        image = any_cv2_or_numpy_augmentations(image)
        return image,

    image, = tf.py_func(
        map_np, (path_tensor,), Tout=(tf.uint8,), stateful=False)
    # any tensorflow operations here.
    image = tf.cast(image, tf.float32) / 255

    image.set_shape((224, 224, 3))
    return image, label


paths, labels = load_image_paths_and_labels()
dataset = tf.data.Dataset.from_tensor_slices((paths, labels))
if is_training:
    shuffle_buffer = len(paths)  # full shuffling - can be shorter
    dataset = dataset.shuffle(shuffle_buffer).repeat()
dataset = dataset.map(map_tf_fn, num_parallel_calls=8)
dataset = dataset.batch(batch_size)

dataset = dataset.prefetch(1)
# play with the following if you want - not finalized API, and only in
# more recent version of tensorflow
# dataset = dataset.apply(tf.contrib.data.prefetch_to_device('/gpu:0'))

image_batch, label_batch = dataset.make_one_shot_iterator().get_next()

你也可以在tensorflow中进行解码,并直接在py_func中使用any_cv2_or_numpy_augmentations(尽管你无法避免你在问题中提到的张量-> numpy->张量舞蹈)。我怀疑你不会注意到两种方法之间的性能差异。

查看此答案以获取更多选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接