[原]基于Keras对图像随机裁剪并同时变换image和mask的数据增广方法(适用于图割)

基于Keras对图像随机裁剪并同时变换image和mask的数据增广方法

  总所周知,Keras自带对图像数据进行预处理的函数,但是该函数是对整张图像进行预处理。在进行图像的语义分割的网络中,当图像尺寸较小,且数据量足够的时候确实可以直接进行resize,投入到网络进行训练。但到图像太大,且数据量不多时,显然不能这样做。比如遥感的语义分割图像,一般的尺寸都是几千乘以几千,且图像的数量并不是很多,这时候就需要先对图像和mask同时进行裁剪成相同的大小,并可以进行适当的数据增广以便使网络具有更好的泛化性能。

  第一种方法是每对数据裁剪一次就进行一次数据增广的操作:
from PIL import Image
from keras.preprocessing.image import ImageDataGenerator
import numpy as np
from tqdm import tqdm
import random 
import os


img_w = 256  
img_h = 256  #要切割的图像尺寸
'''
读取指定文件夹下的图像名称
'''
def file_name(file_dir):   
    L=[]   
    for root, dirs, files in os.walk(file_dir):  
        for file in files:   
            img_name = os.path.split(file)[1]    
            L.append(img_name)

    return L 

'''
image_num:生成裁剪图像的总数量
src_url:原图路径
label_url:对应的label路径
''' 
def creat_dataset(image_num ,src_url,label_url):
    #Keras图片生成器具体方法和参数可以自己设置
    data_gen_args = dict(featurewise_center=True,
                     featurewise_std_normalization=True,
                     width_shift_range=0.2,
                     height_shift_range=0.2,
                     rotation_range=45,
                     horizontal_flip=True,
                     zoom_range=0.2)
    
    image_datagen = ImageDataGenerator(**data_gen_args)
    mask_datagen = ImageDataGenerator(**data_gen_args)

    seed = 1
    print('creating dataset...')
    image_sets=file_name(src_url);
    image_each = image_num /len(image_sets)
    g_count=1
    for i in tqdm(range(len(image_sets))):
        count = 0
        src_img = Image.open(src_url+'/' + image_sets[i])  # 3 channels
        label_img = Image.open(label_url+'/' + image_sets[i]) # 3 channels
        while count < image_each:
            #对图像进行随机裁剪
            width1 = random.randint(0, src_img.size[0] - img_w)
            height1 = random.randint(0, src_img.size[1] - img_h)
            width2 = width1 + img_w
            height2 = height1 + img_h              
            src_roi=src_img.crop((width1, height1, width2, height2))
            label_roi=label_img.crop((width1, height1, width2, height2))                  
            src=np.asarray(src_roi)
            src = src.reshape((1,) + src.shape) #增加维度,将(256,256,3)变成(1,256,256,3)
            label=np.asarray(label_roi)
            label = label.reshape((1,) + label.shape) 
          
#            print('src_shape:{},label_shape:{}'.format(src.shape,label.shape))
            
            i=0  #对每张裁剪的图片进行增广的次数,这里是2次,所以最终生成的图像数据应该是image_num*i
            for src_batch in image_datagen.flow(src, batch_size=1,save_to_dir='./data/train_src/',save_prefix=g_count, save_format='tif', seed=seed):
                i+=1
                if i>=2:
                    break
            j=0
            for mask_batch in mask_datagen.flow(label,batch_size=1,save_to_dir='./data/train_label/',save_prefix=g_count, save_format='tif', seed=seed):
                j+=1
                if j>=2:
                    break
            count += 1
            g_count+=1

if __name__=='__main__':
    creat_dataset(20,'./data/src','./data/label')

结果:

裁剪的图像对应的mask

  第二种方法是先将裁剪的数据存储到numpy中,从numpy中读取数据在进行数据增广:

# -*- coding: utf-8 -*-
"""
Created on Tue Mar 12 16:46:20 2019

@author: 伊
"""

from PIL import Image
from keras.preprocessing.image import ImageDataGenerator
import numpy as np
from tqdm import tqdm
import random 
import os

img_w = 256  
img_h = 256  
'''
读取指定文件夹下的图像名称
'''
def file_name(file_dir):   
    L=[]   
    for root, dirs, files in os.walk(file_dir):  
        for file in files:   
            img_name = os.path.split(file)[1]    
            L.append(img_name)

    return L  
'''
image_num:生成裁剪图像的总数量
src_url:原图路径
label_url:对应的label路径
''' 
def creat_dataset(image_num ,src_url,label_url):
    
    image_sets=file_name(src_url);
    image_each = image_num /len(image_sets)
    src=[]
    label=[]
    for i in tqdm(range(len(image_sets))):
        count = 0
        src_img = Image.open(src_url+'/' + image_sets[i])  # 3 channels
        label_img = Image.open(label_url+'/' + image_sets[i]) # 3 channels
        while count < image_each:
             #对图像进行随机裁剪
            width1 = random.randint(0, src_img.size[0] - img_w)
            height1 = random.randint(0, src_img.size[1] - img_h)
            width2 = width1 + img_w
            height2 = height1 + img_h  
            
            src_roi=src_img.crop((width1, height1, width2, height2))
            label_roi=label_img.crop((width1, height1, width2, height2))                  
            src_roi=np.asarray(src_roi)
            label_roi=np.asarray(label_roi)
            
            src.append(src_roi)
            label.append(label_roi)
            
            count+=1
            
    src=np.asarray(src)
    label=np.asarray(label)
    print('src_shape:{},label_shape:{}'.format(src.shape,label.shape))
    return src,label

def gen_dataset():
    image_num=20
    img_src,img_label=creat_dataset(image_num,'./data/src','./data/label')
     #Keras图片生成器具体方法和参数可以自己设置
    data_gen_args = dict(featurewise_center=True,
                     featurewise_std_normalization=True,
                     width_shift_range=0.2,
                     height_shift_range=0.2,
                     rotation_range=45,
                     horizontal_flip=True,
                     zoom_range=0.2)
    print("begein data_gen......")
    image_datagen = ImageDataGenerator(**data_gen_args)
    mask_datagen = ImageDataGenerator(**data_gen_args)

    seed = 1 
    i=0#这里的batch_size是要每张增广的批次,所以生成图片的最终数量是batch_size*image_num
    for src_batch in image_datagen.flow(img_src, batch_size=2,save_to_dir='./data/train_src/', save_format='tif', save_prefix='all',seed=seed):
        i+=1
        if i>=image_num:        
            break;
    j=0
    for label_batch in mask_datagen.flow(img_label,batch_size=2,save_to_dir='./data/train_label/',save_format='tif',save_prefix='all', seed=seed):
        j+=1
        if j>=image_num:        
            break;
if __name__=='__main__':
    gen_dataset()

结果:

裁剪的图像裁剪的图像在这里插入图片描述对应的Mask

可以看到生成的图像和标签名称都一样,但是用方法二的时候,增广出来的图像可能没有原图像。而且个人跑代码的时候,方法二给出警告。另外我有另一篇博客用的是另一种方法进行的数据增广,附上链接:https://blog.csdn.net/lwy_520/article/details/83794238

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
好的,我可以为您提供代码实现。在这里,我将使用Keras中的ResNet50预训练模型,并使用Fashion-MNIST数据集对十种服装进行分类。首先,我们需要安装一些必要的库: ``` !pip install tensorflow !pip install keras !pip install matplotlib ``` 接下来,我们将加载数据集并进行预处理: ```python import numpy as np import keras from keras.datasets import fashion_mnist from keras.preprocessing.image import ImageDataGenerator # 数据集路径 (x_train, y_train), (x_test, y_test) = fashion_mnist.load_data() # 将图像转换为RGB格式 x_train = np.repeat(x_train[..., np.newaxis], 3, -1) x_test = np.repeat(x_test[..., np.newaxis], 3, -1) # 批量大小 batch_size = 32 # 数据增强 train_datagen = ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) # 没有数据增强的验证数据生成器 val_datagen = ImageDataGenerator(rescale=1./255) # 训练集生成器 train_generator = train_datagen.flow( x_train, keras.utils.to_categorical(y_train), batch_size=batch_size) # 验证集生成器 val_generator = val_datagen.flow( x_test, keras.utils.to_categorical(y_test), batch_size=batch_size) ``` 接下来,我们将加载ResNet50模型,并对其进行微调,以适应我们的数据集: ```python from keras.applications.resnet50 import ResNet50 from keras.layers import Dense, GlobalAveragePooling2D from keras.models import Model # 加载ResNet50模型,不包括顶层(全连接层) base_model = ResNet50(weights='imagenet', include_top=False) # 添加全局平均池化层 x = base_model.output x = GlobalAveragePooling2D()(x) # 添加全连接层,输出为十个类别 predictions = Dense(10, activation='softmax')(x) # 构建我们需要训练的完整模型 model = Model(inputs=base_model.input, outputs=predictions) # 冻结ResNet50的所有层,以便在训练过程中不更新它们的权重 for layer in base_model.layers: layer.trainable = False ``` 现在,我们可以开始训练模型了: ```python from keras.optimizers import SGD # 编译模型,指定损失函数、优化器和评价指标 model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.001), metrics=['accuracy']) # 训练模型 history = model.fit_generator( train_generator, steps_per_epoch=x_train.shape[0] // batch_size, epochs=10, validation_data=val_generator, validation_steps=x_test.shape[0] // batch_size) ``` 最后,我们可以使用matplotlib库绘制训练和验证的准确率和损失曲线: ```python import matplotlib.pyplot as plt # 绘制训练和验证的准确率曲线 plt.plot(history.history['accuracy']) plt.plot(history.history['val_accuracy']) plt.title('Model accuracy') plt.ylabel('Accuracy') plt.xlabel('Epoch') plt.legend(['Train', 'Val'], loc='upper left') plt.show() # 绘制训练和验证的损失曲线 plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('Model loss') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(['Train', 'Val'], loc='upper left') plt.show() ``` 现在您应该可以使用这些代码实现您的需求了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值