了解tf.extract_image_patches以从图像中提取补丁

dee*_*igp 18 python neural-network tensorflow

我在tensorflow API中找到了以下方法tf.extract_image_patches,但我不清楚它的功能.

batch_size = 1,和图像大小225x225x3,我们想要提取大小的补丁32x32.

这个功能到底是怎么表现的?具体来说,文档提到了输出张量的维度[batch, out_rows, out_cols, ksize_rows * ksize_cols * depth],但未提及的是什么out_rowsout_cols未提及.

理想情况下,给定一个大小的输入图像张量1x225x225x3(其中1是批量大小),我希望能够获得Kx32x32x3输出,其中K是补丁的总数,并且32x32x3是每个补丁的维度.张量流中有什么东西已经实现了吗?

Nea*_*eal 40

以下是该方法的工作原理:

  • ksizes 用于确定每个补丁的尺寸,换句话说,每个补丁应包含多少像素.
  • strides 表示一个补丁的开始与原始图像内的下一个连续补丁的开始之间的间隙的长度.
  • rates是一个数字,实质上意味着我们的补丁应该rates在原始图像中按像素跳转到每个连续像素,最终在我们的补丁中.(以下示例有助于说明这一点.)
  • padding 是"有效",这意味着每个补丁必须完全包含在图像中,或"SAME",这意味着允许补丁不完整(剩余的像素将用零填充).

下面是一些带有输出的示例代码,以帮助演示它的工作原理:

import tensorflow as tf

n = 10
# images is a 1 x 10 x 10 x 1 array that contains the numbers 1 through 100 in order
images = [[[[x * n + y + 1] for y in range(n)] for x in range(n)]]

# We generate four outputs as follows:
# 1. 3x3 patches with stride length 5
# 2. Same as above, but the rate is increased to 2
# 3. 4x4 patches with stride length 7; only one patch should be generated
# 4. Same as above, but with padding set to 'SAME'
with tf.Session() as sess:
  print tf.extract_image_patches(images=images, ksizes=[1, 3, 3, 1], strides=[1, 5, 5, 1], rates=[1, 1, 1, 1], padding='VALID').eval(), '\n\n'
  print tf.extract_image_patches(images=images, ksizes=[1, 3, 3, 1], strides=[1, 5, 5, 1], rates=[1, 2, 2, 1], padding='VALID').eval(), '\n\n'
  print tf.extract_image_patches(images=images, ksizes=[1, 4, 4, 1], strides=[1, 7, 7, 1], rates=[1, 1, 1, 1], padding='VALID').eval(), '\n\n'
  print tf.extract_image_patches(images=images, ksizes=[1, 4, 4, 1], strides=[1, 7, 7, 1], rates=[1, 1, 1, 1], padding='SAME').eval()
Run Code Online (Sandbox Code Playgroud)

输出:

[[[[ 1  2  3 11 12 13 21 22 23]
   [ 6  7  8 16 17 18 26 27 28]]

  [[51 52 53 61 62 63 71 72 73]
   [56 57 58 66 67 68 76 77 78]]]]


[[[[  1   3   5  21  23  25  41  43  45]
   [  6   8  10  26  28  30  46  48  50]]

  [[ 51  53  55  71  73  75  91  93  95]
   [ 56  58  60  76  78  80  96  98 100]]]]


[[[[ 1  2  3  4 11 12 13 14 21 22 23 24 31 32 33 34]]]]


[[[[  1   2   3   4  11  12  13  14  21  22  23  24  31  32  33  34]
   [  8   9  10   0  18  19  20   0  28  29  30   0  38  39  40   0]]

  [[ 71  72  73  74  81  82  83  84  91  92  93  94   0   0   0   0]
   [ 78  79  80   0  88  89  90   0  98  99 100   0   0   0   0   0]]]]
Run Code Online (Sandbox Code Playgroud)

因此,例如,我们的第一个结果如下所示:

 *  *  *  4  5  *  *  *  9 10 
 *  *  * 14 15  *  *  * 19 20 
 *  *  * 24 25  *  *  * 29 30 
31 32 33 34 35 36 37 38 39 40 
41 42 43 44 45 46 47 48 49 50 
 *  *  * 54 55  *  *  * 59 60 
 *  *  * 64 65  *  *  * 69 70 
 *  *  * 74 75  *  *  * 79 80 
81 82 83 84 85 86 87 88 89 90 
91 92 93 94 95 96 97 98 99 100 
Run Code Online (Sandbox Code Playgroud)

如您所见,我们有2行和2列值的补丁,这是什么out_rowsout_cols是什么.


小智 13

介绍

在这里我想展示一个相当简单的演示来使用tf.image.extract_patches图像本身。我发现该方法的实现量相当小,具有适当的可视化的实际图像,所以就在这里。

我们将使用的图像尺寸为 (256, 256, 3)。我们将提取的面片形状为 (128, 128, 3)。这意味着我们将从图像中检索 4 个图块。

使用的数据

我将使用鲜花数据集。由于这个答案需要一些数据管道,因此我将在这里链接我的Kaggle 内核,其中讨论了如何使用 API 来使用数据集tf.data.Dataset

完成后,我们将浏览以下代码片段。

images, _ = next(iter(train_ds.take(1)))

image = images[0]
plt.imshow(image.numpy().astype("uint8"))
Run Code Online (Sandbox Code Playgroud)

花

在这里,我们从这批图像中取出一张图像并按原样将其可视化。

image = tf.expand_dims(image,0) # To create the batch information
patches = tf.image.extract_patches(images=image,
                                   sizes=[1, 128, 128, 1],
                                   strides=[1, 128, 128, 1],
                                   rates=[1, 1, 1, 1],
                                   padding='VALID')
Run Code Online (Sandbox Code Playgroud)

通过此代码片段,我们从大小为 (256,256) 的图像中提取大小为 (128,128) 的块。这直接意味着我希望将图像分成 4 个图块。

可视化

plt.figure(figsize=(10, 10))
for imgs in patches:
    count = 0
    for r in range(2):
        for c in range(2):
            ax = plt.subplot(2, 2, count+1)
            plt.imshow(tf.reshape(imgs[r,c],shape=(128,128,3)).numpy().astype("uint8"))
            count += 1
Run Code Online (Sandbox Code Playgroud)

花的分裂


Ken*_*iff 6

为了扩展 Neal 的详细答案,使用“SAME”时零填充有很多微妙之处,因为如果可能,extract_image_patches 会尝试将图像中的补丁居中。根据步幅,顶部和左侧可能有填充,也可能没有,第一个补丁不一定从左上角开始。

例如,扩展前面的例子:

print tf.extract_image_patches(images, [1, 3, 3, 1], [1, n, n, 1], [1, 1, 1, 1], 'SAME').eval()[0]
Run Code Online (Sandbox Code Playgroud)

当步长为 n=1 时,图像四周用零填充,第一个补丁从填充开始。其他步幅仅在右侧和底部填充图像,或者根本不填充。步幅为 n=10,单个补丁从元素 34(在图像的中间)开始。

tf.extract_image_patches 由本答案中所述的特征库实现。您可以研究该代码以准确了解补丁位置和填充是如何计算的。