如何将图像获取到数组,Tensorflow 1.9

How to get an image to array, Tensorflow 1.9

因此,出于系统特定原因,我必须使用 Tensorflow 1.9。 我想用包含图像的自定义数据集训练 cnn。 文件夹结构看起来非常像这样:

./
  + circles
    - circle-0.jpg
    - circle-1.jpg
    - ...
  + hexagons
    - hexagon-0.jpg
    - hexagon-1.jpg
    - ...
  + ... 

因此我必须使用的示例使用 MNIST 并具有以下两行特定代码:

mnist_dataset = tf.keras.datasets.mnist.load_data('mnist_data')
(x_train, y_train), (x_test, y_test) = mnist_dataset

在我的工作中,我也不得不使用这种数据格式(x_train, y_train), (x_test, y_test),这似乎是很常见的。据我目前所知,这些数据集的格式是:(image_data, label),类似于 ((60000, 28, 28), (60000,)),至少 MNIST 数据集是这样。这里的 image_data 应该是 dtype uint8according to this post). I was able to find out, that a tf.data.Dataset() 对象看起来像我在这里需要的元组 (image_data, label).


到目前为止一切顺利。但是从这些信息中出现了一些我还没有弄清楚的问题,我想请求你的帮助:

  1. (60000, 28, 28) 表示 60k 一个 28 x 28 图像值数组,对吗?
  2. 如果 1. 是正确的,我如何将我的图像(如我上面描述的目录结构中的图像)转换为这种格式?有没有一个函数可以生成一个我可以这样使用的数组?
  3. 我知道我需要某种生成器函数来获取所有带有标签的图像,因为在 Tensorflow 1.9tf.keras.utils.image_dataset_from_directory() 似乎还不存在。
  4. 标签实际是什么样子的?例如,对于我的目录结构,我会有这样的东西:

(一)

File Label
circle-0.jpg circle
circle-233.jpg circle
hexagon-1.jpg hexagon
triangle-12.jpg triangle

或 (B)

File Label
circle-0.jpg circle-0
circle-233.jpg circle-233
hexagon-1.jpg hexagon-1
triangle-12.jpg triangle-12

,相应的图像已经转换为“(60000, 28, 28)”格式?似乎我需要自己创建所有函数,因为似乎没有一个好的函数将像我这样的目录结构带到可以被 Tensorflow 1.9[=60= 使用的数据集],还是有?。我知道 tf.keras.preprocessing.image.ImageDataGenerator and image_dataset_from_directory as well as flow_from_directory(),但是,它们似乎都没有给我带来我想要的数据集值元组格式。

非常感谢任何帮助!

您必须为此构建自定义数据生成器。如果您有两个数组,train_paths 包含图像的路径,train_labels 包含图像的标签,那么此函数 (datagen) 将生成图像作为数组及其各自的标签作为元组 (image_array, label).
我还添加了一种方法 integer-encode 你的标签,用字典 encode_label

例如,train_pathstrain_labels 应如下所示:

train_paths = np.array(['path/to/image1.jpg','path/to/image2.jpg','path/to/image3.jpg'])
train_labels = np.array(['circle','square','hexagon'])

路径'path/to/image1.jpg'的图片标签为'circle',路径'path/to/image2.jpg'的图片标签为'square'。

此生成器函数将 return 数据作为批处理,您也可以编写自定义增强技术(在 augment 函数内)

import tensorflow as tf

# Hyperparameters
HEIGHT = 224 # Image height
WIDTH = 224 # Image width
CHANNELs = 3 # Image channels

# This function will encode your labels
encode_label = {'hexagon':0, 'circle':1, 'square':2}


def augment(image):
    # All your augmentation techniques are done here
    return image

def encode_labels(labels):
    encoded = []
    for label in labels:
        encoded.append(encode_label[label])
    return encoded

def open_images(paths):
    '''
    Given a list of paths to images, this function loads
    the images from the paths, then augments them, then returns it as a batch
    '''
    images = []
    for path in paths:
        image = tf.keras.preprocessing.image.load_img(path, target_size=(HEIGHT, WIDTH, CHANNELS))
        image = np.array(image)
        image = augment(image)
        images.append(image)
    return np.array(images)

# This is the data generator
def datagen(paths, labels, batch_size=32):
    for x in range(0,len(paths), batch_size):
        # Load batch of images
        batch_paths = paths[x:x+batch_size]
        batch_images = open_images(batch_paths)
        # Load batch of labels
        batch_labels = labels[x:x+batch_size]
        batch_labels = encode_labels(batch_labels)
        batch_labels = np.array(batch_labels, dtype='float').reshape(-1)
        
        yield batch_images, batch_labels

如果您无法 tf.keras.preprocessing.image.load_img 在您的 tensorflow 版本中工作,请尝试使用替代方法加载图像并调整其大小。另一种方法是使用 matplotlib 加载图像,然后使用 skimage 调整它的大小。所以 open_images 函数是这样的:

import matplotlib
from skimage.transform import resize

def open_images(paths):
    '''
    Given a list of paths to images, this function loads
    the images from the paths, then augments them, then returns it as a batch
    '''
    images = []
    for path in paths:
        image = matplotlib.image.imread(path)
        image = np.array(image)
        image = resize(image, (HEIGHT, WIDTH, CHANNELS))
        image = augment(image)
        images.append(image)
    return np.array(images)