[day-29] U-net code 说明

资料来源

以下程序码皆来源自zhixuhao's unet

main.py

from model import *
from data import *

main.py import 蛮简洁的。

#os.environ["CUDA_VISIBLE_DEVICES"] = "0"
data_gen_args = dict(rotation_range=0.2,
                    width_shift_range=0.05,
                    height_shift_range=0.05,
                    shear_range=0.05,
                    zoom_range=0.05,
                    horizontal_flip=True,
                    fill_mode='nearest')

影像增量的方法。

myGene = trainGenerator(2,'data/membrane/train','image','label',data_gen_args,save_to_dir = None)

这是一个 train的Generator

model = unet() # unet model 之前有介绍过
model_checkpoint = ModelCheckpoint('unet_membrane.hdf5', monitor='loss',verbose=1, save_best_only=True) # 训练视觉化
model.fit_generator(myGene,steps_per_epoch=300,epochs=1,callbacks=[model_checkpoint]) # 训练,其中myGene是整理过的资料。
testGene = testGenerator("data/membrane/test") # 整理过後的资料 (testGene)
results = model.predict_generator(testGene,30,verbose=1)
saveResult("data/membrane/test",results) # 储存资料

data.py

from __future__ import print_function
from keras.preprocessing.image import ImageDataGenerator
import numpy as np 
import os
import glob
import skimage.io as io
import skimage.transform as trans

# 颜色视觉化
Sky = [128,128,128]
Building = [128,0,0]
Pole = [192,192,128]
Road = [128,64,128]
Pavement = [60,40,222]
Tree = [128,128,0]
SignSymbol = [192,128,128]
Fence = [64,64,128]
Car = [64,0,128]
Pedestrian = [64,64,0]
Bicyclist = [0,128,192]
Unlabelled = [0,0,0]

# 类别的array
COLOR_DICT = np.array([Sky, Building, Pole, Road, Pavement,
                          Tree, SignSymbol, Fence, Car, Pedestrian, Bicyclist, Unlabelled])

# 数据调整(将数据二值化)
def adjustData(img,mask,flag_multi_class,num_class):

# img: array
# mask: array --> label
# flag_multi_class: boolen --> 是不是多类别

    if(flag_multi_class):
        img = img / 255 # 将数值定於0-1之间
        mask = mask[:,:,:,0] if(len(mask.shape) == 4) else mask[:,:,0] 
        new_mask = np.zeros(mask.shape + (num_class,))
        for i in range(num_class):
            new_mask[mask == i,i] = 1
        new_mask = np.reshape(new_mask,(new_mask.shape[0],new_mask.shape[1]*new_mask.shape[2],new_mask.shape[3])) if flag_multi_class else np.reshape(new_mask,(new_mask.shape[0]*new_mask.shape[1],new_mask.shape[2]))
        mask = new_mask
    elif(np.max(img) > 1):
        img = img / 255
        mask = mask /255
        mask[mask > 0.5] = 1
        mask[mask <= 0.5] = 0
    return (img,mask)

# trainGenerator 是用yield,产生一个generator。
def trainGenerator(batch_size,train_path,image_folder,mask_folder,aug_dict,image_color_mode = "grayscale", mask_color_mode = "grayscale",image_save_prefix  = "image",mask_save_prefix  = "mask", flag_multi_class = False,num_class = 2,save_to_dir = None,target_size = (256,256),seed = 1):
    '''
    can generate image and mask at the same time
    use the same seed for image_datagen and mask_datagen to ensure the transformation for image and mask is the same
    if you want to visualize the results of generator, set save_to_dir = "your path"
    '''
    image_datagen = ImageDataGenerator(**aug_dict)
    mask_datagen = ImageDataGenerator(**aug_dict)
    image_generator = image_datagen.flow_from_directory(
        train_path,
        classes = [image_folder],
        class_mode = None,
        color_mode = image_color_mode,
        target_size = target_size,
        batch_size = batch_size,
        save_to_dir = save_to_dir,
        save_prefix  = image_save_prefix,
        seed = seed)
    mask_generator = mask_datagen.flow_from_directory(
        train_path,
        classes = [mask_folder],
        class_mode = None,
        color_mode = mask_color_mode,
        target_size = target_size,
        batch_size = batch_size,
        save_to_dir = save_to_dir,
        save_prefix  = mask_save_prefix,
        seed = seed)
    train_generator = zip(image_generator, mask_generator)
    for (img,mask) in train_generator:
        img,mask = adjustData(img,mask,flag_multi_class,num_class)
        yield (img,mask)


# testGenerator 是用yield,产生一个generator。
def testGenerator(test_path,num_image = 30,target_size = (256,256),flag_multi_class = False,as_gray = True):
    for i in range(num_image):
        img = io.imread(os.path.join(test_path,"%d.png"%i),as_gray = as_gray)
        img = img / 255
        img = trans.resize(img,target_size)
        img = np.reshape(img,img.shape+(1,)) if (not flag_multi_class) else img
        img = np.reshape(img,(1,)+img.shape)
        yield img

# 这边是将资料进一步的变成一个 cube 喂进 model 中。
def geneTrainNpy(image_path,mask_path,flag_multi_class = False,num_class = 2,image_prefix = "image",mask_prefix = "mask",image_as_gray = True,mask_as_gray = True):
    image_name_arr = glob.glob(os.path.join(image_path,"%s*.png"%image_prefix))
    image_arr = []
    mask_arr = []
    for index,item in enumerate(image_name_arr):
        img = io.imread(item,as_gray = image_as_gray)
        img = np.reshape(img,img.shape + (1,)) if image_as_gray else img
        mask = io.imread(item.replace(image_path,mask_path).replace(image_prefix,mask_prefix),as_gray = mask_as_gray)
        mask = np.reshape(mask,mask.shape + (1,)) if mask_as_gray else mask
        img,mask = adjustData(img,mask,flag_multi_class,num_class)
        image_arr.append(img)
        mask_arr.append(mask)
    image_arr = np.array(image_arr)
    mask_arr = np.array(mask_arr)
    return image_arr,mask_arr

# label 视觉化
def labelVisualize(num_class,color_dict,img):
    img = img[:,:,0] if len(img.shape) == 3 else img
    img_out = np.zeros(img.shape + (3,))
    for i in range(num_class):
        img_out[img == i,:] = color_dict[i]
    return img_out / 255


# 储存资料
def saveResult(save_path,npyfile,flag_multi_class = False,num_class = 2):
    for i,item in enumerate(npyfile):
        img = labelVisualize(num_class,COLOR_DICT,item) if flag_multi_class else item[:,:,0]
        io.imsave(os.path.join(save_path,"%d_predict.png"%i),img)

Concusion

其实只要读懂程序码,基本上要复制其他的 FCN也会变得很容易,但是要注意的是,U-net因为计算量算少,所以如果一些比较大型的模型可能要用到额外的技巧去实现。

Reference

[0] U-net
[1] zhixuhao's unet


<<:  [铁人12:Day 30] 「AI 的未来十年」摘要 6:逻辑推论及认知模型

>>:  除此之外,还有什麽吗?

.NET Framework4.7.2 制作 Web API 图片上传接收功能

本文将简单介绍如何制作 Web API 接收前端上传图片,并调整图片档名及尺寸,用於用户大头贴图片。...

Day16 Combine 03 - Subscriber

Subscriber 与Publisher 相对应,是观察者模式中的Observer,Publish...

Day 15 - 用 useReducer 取代 useState !?

如果有错误,欢迎留言指教~ Q_Q 上篇提到,如何取得更新後的 state useReducer ...

什麽是AutoML

什麽是AutoML 根据 Microsoft的说法节录如下: 自动化机器学习 (亦称为自动化 ML ...

什麽是帕累托图?(20/80法则)

我相信您曾经有过这样的经历。当您遇到问题并想解决时,您总是会发现有太多因素会影响该问题。太多了,您根...