Keras .ImageDataGenerator图像增强用法大全以及如何和模型结合起来(有代码)

图像增强

在做图像任务时,我们常常需要图像增强。今天来讲解下keras中的图像增强

ImageDataGenerator

官网
https://keras.io/api/preprocessing/image/

keras.preprocessing.image.ImageDataGenerator(
    featurewise_center=False, #输入值按照均值为0进行处理
    samplewise_center=False, #每个样本的均值按0处理
    featurewise_std_normalization=False, #输入值按照标准正态化处理
    samplewise_std_normalization=False, #每个样本按照标准正态化处理 
    zca_whitening=False, # 是否开启增白
    zca_epsilon=1e-06, 
    rotation_range=0, #图像随机旋转一定角度,最大旋转角度为设定值
    width_shift_range=0.0, #图像随机水平平移,最大平移值为设定值。若值为小于1的float值,则可认为是按比例平移,若大于1,则平移的是像素;若值为整型,平移的也是像素;假设像素为2.0,则移动范围为[-1,1]之间
    height_shift_range=0.0, #图像随机垂直平移,同上
    brightness_range=None, # 图像随机亮度增强,给定一个含两个float值的list,亮度值取自上下限值间
    shear_range=0.0, # 图像随机修剪
    zoom_range=0.0, # 图像随机变焦 
    channel_shift_range=0.0, 
    fill_mode='nearest', #填充模式,默认为最近原则,比如一张图片向右平移,那么最左侧部分会被临近的图案覆盖
    cval=0.0, 
    horizontal_flip=False, #图像随机水平翻转
    vertical_flip=False, #图像随机垂直翻转
    rescale=None, #缩放尺寸
    preprocessing_function=None, 
    data_format=None, 
    validation_split=0.0, 
    dtype=None)

可能用到的函数fit

fit(x, augment=False, rounds=1):计算依赖于数据的变换所需要的统计信息(均值方差等),只有使用featurewise_center,featurewise_std_normalization或zca_whitening时需要此函数。 
X:numpy array,样本数据,秩应为4.在黑白图像的情况下channel轴的值为1,在彩色图像情况下值为3

augment:布尔值,确定是否使用随即提升过的数据

round:若设augment=True,确定要在数据上进行多少轮数据提升,默认值为1

seed: 整数,随机数种子

用到的函数flow

flow:
flow(self, X, y, batch_size=32, shuffle=True, seed=None, save_to_dir=None, save_prefix='', save_format='png'):接收numpy数组和标签为参数,生成经过数据提升或标准化后的batch数据,并在一个无限循环中不断的返回batch数据

x:样本数据,秩应为4.在黑白图像的情况下channel轴的值为1,在彩色图像情况下值为3

y:标签

batch_size:整数,默认32

shuffle:布尔值,是否随机打乱数据,默认为True

save_to_dir:None或字符串,该参数能让你将提升后的图片保存起来,用以可视化

save_prefix:字符串,保存提升后图片时使用的前缀, 仅当设置了save_to_dir时生效

save_format:"png""jpeg"之一,指定保存图片的数据格式,默认"jpeg"

yields:形如(x,y)tuple,x是代表图像数据的numpy数组.y是代表标签的numpy数组.该迭代器无限循环.

seed: 整数,随机数种子

用到的函数flow_from_directory :

flow_from_directory(directory):

以文件夹路径为参数,生成经过数据提升/归一化后的数据,在一个无限循环中无限产生batch数据

  • directory: 目标文件夹路径,对于每一个类,该文件夹都要包含一个子文件夹.子文件夹中任何JPG、PNG、BNP、PPM的图片都会被生成器使用.详情请查看此脚本
  • target_size: 整数tuple,默认为(256, 256). 图像将被resize成该尺寸
  • color_mode: 颜色模式,为"grayscale",“rgb"之一,默认为"rgb”.代表这些图片是否会被转换为单通道或三通道的图片.
  • classes: 可选参数,为子文件夹的列表,如[‘dogs’,‘cats’]默认为None. 若未提供,则该类别列表将从directory下的子文件夹名称/结构自动推断。每一个子文件夹都会被认为是一个新的类。(类别的顺序将按照字母表顺序映射到标签值)。通过属性class_indices可获得文件夹名与类的序号的对应字典。
  • class_mode: “categorical”, “binary”, "sparse"或None之一. 默认为"categorical. 该参数决定了返回的标签数组的形式, "categorical"会返回2D的one-hot编码标签,"binary"返回1D的二值标签."sparse"返回1D的整数标签,如果为None则不返回任何标签, 生成器将仅仅生成batch数据, 这种情况在使用model.predict_generator()和model.evaluate_generator()等函数时会用到.
  • batch_size: batch数据的大小,默认32
  • shuffle: 是否打乱数据,默认为True
  • seed: 可选参数,打乱数据和进行变换时的随机数种子
  • save_to_dir: None或字符串,该参数能让你将提升后的图片保存起来,用以可视化
  • save_prefix:字符串,保存提升后图片时使用的前缀, 仅当设置了save_to_dir时生效
  • save_format:“png"或"jpeg"之一,指定保存图片的数据格式,默认"jpeg”
  • flollow_links: 是否访问子文件夹中的软链接

flow_from_directory(directory)伪代码如下

xm,y=getDataIndex()#获取所有文件夹中所有图片索引,以及文件夹名也即标签

while(True):
    if shuffle==True:
        shuffle(xm,y)#打乱图片索引及其标签
    for i in range(0,len(x),batch_size):
        xm_batch=xm[i:i+batch_size]#文件索引
        y_batch=y[i:i+batch_size]
        x_batch=getImg(xm_batch)#根据文件索引,获取图像数据
        ImagePro(x_batch)#数据增强
        #保存提升后的图片
        #saveToFile()
        yield (x_batch,y_batch)

算例flow

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import numpy as np

datagen = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    rescale=1/255.0,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest'
)


from keras.preprocessing import image
import matplotlib.pyplot as plt
img_path1 = 'meinv.jpg'

img1 = image.load_img(img_path1) # plt格式的图片。

x = img_to_array(img1)
x = np.expand_dims(x, 0)#扩展维度

y_train = [1]  # 标签

# [生成图片]: 其中,gen可以作为生成器,用model.fit_generate(generate,)中来训练。
#datagen.fit(x, y_train) #fit这里用不上
gen = datagen.flow(x, y_train, batch_size=2)  # x_train —— 要求类型:numpy.array; 要求形状: (image_num, 长, 宽, 通道)
                                                          # y_train —— 要求类型:numpy.array; 要求形状: (image_num)
    # 注: (1) 每个batch中生成的图片是 从数据集的所有图片中,随机抽取一张并进行图片尺寸大小啥的变换后放入batch中, 这样抽取batch_size张图片后就形成一个batch。
    #    (2) 对图片进行旋转尺寸大小变换后的图片,图片大小[不会]改变。

for i in range(9):
    plt.subplot(3,3,i+1)
    x,y=next(gen)
    print(x.shape)

    i=np.squeeze(x)#降维
    i==np.array(i,dtype=np.uint8)#转换为图像格式,必须使用==
    plt.imshow(i)
plt.show()

结果

多图

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import numpy as np

datagen = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    rescale=1/255.0,

)


from keras.preprocessing import image
import matplotlib.pyplot as plt
img_path1 = 'meinv.jpg'
img_path2 = 'meinv1.jpg'
img1 = image.load_img(img_path1) # plt格式的图片。
img2 = image.load_img(img_path2) # plt格式的图片。
x1 = np.array(img1)
x1=np.resize(x1,(600,400,3))

x2 = np.array(img2)
x2=np.resize(x2,(600,400,3))

x_train=np.array([x1,x2])#多图,必须统一尺寸
y_train = [1,2]  # 标签

#print(x_train.shape)#(2, 400, 400, 3)

gen = datagen.flow(x_train, y_train, batch_size=2)  # x_train —— 要求类型:numpy.array; 要求形状: (image_num, 长, 宽, 通道)
                                                          # y_train —— 要求类型:numpy.array; 要求形状: (image_num)
    # 注: (1) 每个batch中生成的图片是 从数据集的所有图片中,随机抽取一张并进行图片尺寸大小啥的变换后放入batch中, 这样抽取batch_size张图片后就形成一个batch。
    #    (2) 对图片进行旋转尺寸大小变换后的图片,图片大小[不会]改变。

for i in range(3):

    x,y=next(gen)
    print(y)

    print(x.shape)

    photo1=np.squeeze(x[0])#降维
    photo2=np.squeeze(x[1])#降维
    photo1==np.array(photo1,dtype=np.uint8)#转换为图像格式,必须使用==
    photo2 == np.array(photo2, dtype=np.uint8)  # 转换为图像格式,必须使用==
    plt.subplot(3,2,(i+1)*2-1)
    plt.imshow(photo1)
    plt.subplot(3,2, (i+1)*2)
    plt.imshow(photo2)

plt.show()

批量生成保存到文件夹中


# -*- coding: utf-8 -*-

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import numpy as np

datagen = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    rescale=1/255.0,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest'
)

import os

for root ,dirs,files in os.walk(r'C:\Users\Shineion\Desktop\新建文件夹'):
    for name in files:
        file_path=os.path.join(root,name)#包含路径的文件
        print(file_path)

        img = load_img(file_path)
        x = img_to_array(img)
        #print(x.shape)

        x = np.expand_dims(x, 0)
        #print(x.shape)

        i = 0
        for batch in datagen.flow(x, batch_size=1, save_to_dir='C:\\Users\\Shineion\\Desktop\\新建文件夹',
                                  save_prefix='new_photo', save_format='png'):
            i += 1
            if i == 20:
                break
        print('finished!')



原始文件夹

结果文件夹42张图

算例flow_from_directory

原始文件夹

cat dog文件夹里有图

relult文件夹无图

from keras.preprocessing.image import ImageDataGenerator

path = r'C:\\Users\\Shineion\\Desktop\\新建文件夹\catdog'  # 类别子文件夹的上一级
dst_path = r'C:\Users\Shineion\Desktop\新建文件夹\result'  # save path

# 增强方式
datagen = ImageDataGenerator(rotation_range=5, width_shift_range=0.02, horizontal_flip=True, )

gen = datagen.flow_from_directory(path, target_size=(200, 200), batch_size=1,
                                  classes=['cat'],  # 可选对那几个文件夹进行数据增强,如classes=['1','2'],我只针对cat
                                  save_to_dir=dst_path,  # 生成后的图像保存路
                                  save_prefix='arg', save_format='jpg')
total_num = 12  # 增强的总数目
for i in range(total_num):
    gen.next()

结果

在模型中使用图像数据增强

还是使用上例中的文件夹,不同的是我扩充啦猫狗的数据集
猫和狗各有30张左右图

用到的知识点
对于小型,简单化的数据集,使用Keras的.fit函数是完全可以接受的。

这些数据集通常不是很具有挑战性,不需要任何数据增强。

但是,真实世界的数据集很少这么简单:

真实世界的数据集通常太大而无法放入内存中
它们也往往具有挑战性,要求我们执行数据增强以避免过拟合并增加我们的模型的泛化能力,这时候我们需要用到利用Keras的.fit_generator函数

fit_generator(self, generator,            
                    steps_per_epoch=None, 
                    epochs=1, 
                    verbose=1, 
                    callbacks=None, 
                    validation_data=None, 
                    validation_steps=None,  
                    class_weight=None,
                    max_queue_size=10,   
                    workers=1, 
                    use_multiprocessing=False, 
                    shuffle=True, 
                    initial_epoch=0)

优点:通过Python generator产生一批批的数据用于训练模型。generator可以和模型并行运行,例如,可以使用CPU生成批数据同时在GPU上训练模型。

  • generator:一个generator或Sequence实例,为了避免在使用multiprocessing时直接复制数据。
  • steps_per_epoch:从generator产生的步骤的总数(样本批次总数)。通常情况下,应该等于数据集的样本数量除以批量的大小。(即一次多少样本)
  • epochs:整数,在数据集上迭代的总数。
  • works:在使用基于进程的线程时,最多需要启动的进程数量。
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
import keras


#定义模型
def define_model():
    model = Sequential()

    model.add(Conv2D(filters=16,
                     kernel_size=(5, 5),
                     padding='same',
                     input_shape=(200, 200, 3),
                     activation='relu'))  # 卷积层1

    model.add(MaxPooling2D(pool_size=(2, 2)))  # 池化层2
    model.add(Dropout(0.25))

    model.add(Flatten())  # 平坦层
    model.add(Dense(10,activation='relu'))  # 隐藏层
    model.add(Dense(2, activation='softmax'))  # 输出层
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])#
    model.summary()
    return model


model = define_model()

#图片数据增强

from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing import image
path = r'C:\\Users\\Shineion\\Desktop\\新建文件夹\catdog'  # 类别子文件夹的上一级
dst_path = r'C:\Users\Shineion\Desktop\新建文件夹\result'  # save path

# 增强方式
datagen = ImageDataGenerator(rotation_range=5, width_shift_range=0.02, horizontal_flip=True )

#训练集增强
train_generator = datagen.flow_from_directory(path, target_size=(200, 200), batch_size=10,
                                  classes=['cat','dog'] # 可选对那几个文件夹进行数据增强,如classes=['1','2'],我只针对cat
                              ,class_mode='categorical')

#测试集增强
validation_generator = datagen.flow_from_directory(path, target_size=(200, 200), batch_size=10,
                                  classes=['cat','dog'] # 可选对那几个文件夹进行数据增强,如classes=['1','2'],我只针对cat
                              ,class_mode='categorical')
model.fit_generator(generator=train_generator,steps_per_epoch=10,epochs=2,validation_data=validation_generator,validation_steps=10)
model.save('猫狗分类1.h5')

代码可以运行

预测代码

from matplotlib import image as mping
from matplotlib import  pyplot as plt
import numpy as np
img=mping.imread(r'C:\Users\Shineion\Desktop\新建文件夹\catdog\dog\dog.3.jpg')#image.read()
plt.imshow(img)#图片显示
plt.show()#画布显示

img=np.array(img)
img=np.resize(img,(200, 200, 3))
img=np.expand_dims(img, 0)#扩展维度

predict=model.predict(img)
print(predict)

结果

为狗的概率0.49
我只有几十张图,当然准确度低

注意问题
在把数据增强和模型结合起来时容易出现这个问题
IOError: broken data stream when reading image file
这是因为数据在增强时出现损坏。
我还未研究如何解决,可能有些增强操作会造成文件损坏。
为保证万无一失,我还是倾向于先数据增强,把图保存到文件夹中。再使用模型,这样做的缺点是占内存。存储需要内存的

更多模型代码
下面代码来源于keras ImageDataGenerator用法

使用flow

(x_train, y_train), (x_test, y_test) = cifar10.load_data()
y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)

datagen = ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True)

# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(x_train)

# fits the model on batches with real-time data augmentation:
model.fit_generator(datagen.flow(x_train, y_train, batch_size=32),
                    steps_per_epoch=len(x_train), epochs=epochs)

# here's a more "manual" example
for e in range(epochs):
    print 'Epoch', e
    batches = 0
    for x_batch, y_batch in datagen.flow(x_train, y_train, batch_size=32):
        loss = model.train(x_batch, y_batch)
        batches += 1
        if batches >= len(x_train) / 32:
            # we need to break the loop by hand because
            # the generator loops indefinitely
            break

使用flow_from_directory(directory)

train_datagen = ImageDataGenerator(
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
        'data/train',
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
        'data/validation',
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')

model.fit_generator(
        train_generator,
        steps_per_epoch=2000,
        epochs=50,
        validation_data=validation_generator,
        validation_steps=800)

在这里插入图片描述
作者:重庆电网准新人-余登武
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/kobeyu652453/article/details/109690923