keras-segmentation-master代码详解

本人学习过程中随笔记录用。代码下载源暂时忘记了,日后找到补上。

FCN8网络搭建

第一部分构建不涉及分叉出去评分的部分

def FCN8_helper(nClasses, input_height, input_width):  #分割类别 输入尺寸

    assert input_height % 32 == 0  #检查输入的长宽,不符合退出
    assert input_width % 32 == 0

    img_input = Input(shape=(input_height, input_width, 3)) 
    #把输入的形状规范,考虑到不是所有格式都是长宽通道的格式

    model = vgg16.VGG16(
        include_top=False,
        weights='imagenet', input_tensor=img_input,
        pooling=None,
        classes=1000)
       #include_top=False不保留顶层的3个全连接网络
       #weights='imagenet'代表加载预训练权重
       #input_tensor=img_input设置输入
       #pooling=None 不进行池化操作
       
    assert isinstance(model, Model)#判断model和keras库中Model是否同类别

    o = Conv2D(
        filters=4096,
        kernel_size=(
            7,
            7),
        padding="same",
        activation="relu",
        name="fc6")(
            model.output)
    #2维卷积层,输出维度4096,卷积核尺寸(7,7)激活函数用relu
    #padding:same表示不够卷积核大小的块就补0,所以输出和输入形状相同
    o = Dropout(rate=0.5)(o)#Dropout按比例随机置零,缓解过拟合。
    o = Conv2D(
        filters=4096,
        kernel_size=(
            1,
            1),
        padding="same",
        activation="relu",
        name="fc7")(o)
    o = Dropout(rate=0.5)(o)

    o = Conv2D(filters=nClasses, kernel_size=(1, 1), padding="same", activation="relu", kernel_initializer="he_normal",
               name="score_fr")(o)
	#kernel_initializer="he_normal"以He正态分布初始化,参数由0均值,标准差为sqrt(2 / fan_in) 的正态分布产生
    o = Conv2DTranspose(filters=nClasses, kernel_size=(2, 2), strides=(2, 2), padding="valid", activation=None,
                        name="score2")(o)

    fcn8 = Model(inputs=img_input, outputs=o)#构建模型
    fcn8.summary()
    return fcn8#返回模型

第二部分从评分VGG16的池化部分分出评分

def FCN8(nClasses, input_height, input_width):

    fcn8 = FCN8_helper(nClasses, input_height, input_width)#上面的函数的输出
    # Conv to be applied on Pool4
    skip_con1 = Conv2D(nClasses, kernel_size=(1, 1), padding="same", activation=None, kernel_initializer="he_normal",
                       name="score_pool4")(fcn8.get_layer("block4_pool").output)
    # 承接fcn8的输出
    Summed = add(inputs=[skip_con1, fcn8.output])#求和
    x = Conv2DTranspose(nClasses, kernel_size=(2, 2), strides=(2, 2), padding="valid", activation=None,
                        name="score4")(Summed)
    #反卷积进行上采样
    #padding=“valid”:表示不够卷积核大小的块,则丢弃;
    ###
    skip_con2 = Conv2D(nClasses, kernel_size=(1, 1), padding="same", activation=None, kernel_initializer="he_normal",
                       name="score_pool3")(fcn8.get_layer("block3_pool").output)
    Summed2 = add(inputs=[skip_con2, x])

    #####
    Up = Conv2DTranspose(nClasses, kernel_size=(8, 8), strides=(8, 8),
                         padding="valid", activation=None, name="upsample")(Summed2)

    Up = Reshape((-1, nClasses))(Up)
    Up = Activation("softmax")(Up)#softmax进行概率打分

    mymodel = Model(inputs=fcn8.input, outputs=Up)

    return mymodel

第三部分用于打印网络

if __name__ == '__main__':
    m = FCN8(15, 320, 320)#输入的尺寸
    from keras.utils.vis_utils import plot_model
    plot_model(m, show_shapes=True, to_file=r'C:\Users\dai\Desktop\model_fcn8.png')
    #把结果输出成png格式
    print(len(m.layers))
    #打印层数

加载部分

对输入图片进行处理

def getImageArr(im):

    img = im.astype(np.float32)
	#把图片的种类转变为float32
    img[:, :, 0] -= 103.939
    img[:, :, 1] -= 116.779
    img[:, :, 2] -= 123.68
	#ImageNet平均 BGR [103.939, 116.779, 123.68]。去均值,有利于三通道的训练效果
    return img
	

获得对分割图片进行编码,需输入分割图,类数,尺寸。

def getSegmentationArr(seg, nClasses, input_height, input_width):

    seg_labels = np.zeros((input_height, input_width, nClasses))
	#全置零
    for c in range(nClasses):
        seg_labels[:, :, c] = (seg == c).astype(int)
	#合适的位置置1
    seg_labels = np.reshape(seg_labels, (-1, nClasses))
    #把形状变为(input_height*input_width,nClasses)
    return seg_labels

加载图像文件

def imageSegmentationGenerator(images_path, segs_path, batch_size,
                               n_classes, input_height, input_width):

    assert images_path[-1] == '/'
    assert segs_path[-1] == '/'
	#检测路径名最后是不是以'/'
    images = sorted(glob.glob(images_path + "*.jpg") +
                    glob.glob(images_path + "*.png") + glob.glob(images_path + "*.jpeg"))
	#加载指定目录里面所有的图片并排序
    segmentations = sorted(glob.glob(segs_path + "*.jpg") +
                           glob.glob(segs_path + "*.png") + glob.glob(segs_path + "*.jpeg"))

    zipped = itertools.cycle(zip(images, segmentations))
    #zip把图片和分割结果的一一对应放在一起,zipped包含了所有的对
    #print(list(itertools.islice(zipped, 0, 10, 1)))打印结果
	
    while True:
        X = []
        Y = []
        for _ in range(batch_size):
            im, seg = zipped.__next__()
            im = cv2.imread(im, 1)#读取彩色图片
            seg = cv2.imread(seg, 0)#读取灰度图片

            assert im.shape[:2] == seg.shape[:2]
            #检测是否同长宽

            assert im.shape[0] >= input_height and im.shape[1] >= input_width
			#输入图片尺寸必须大于等于预设尺寸
			
            xx = random.randint(0, im.shape[0] - input_height)
            yy = random.randint(0, im.shape[1] - input_width)

            im = im[xx:xx + input_height, yy:yy + input_width]
            seg = seg[xx:xx + input_height, yy:yy + input_width]
			#把原图分割成更小的块
            X.append(getImageArr(im))
            Y.append(
                getSegmentationArr(
                    seg,
                    n_classes,
                    input_height,
                    input_width))

        yield np.array(X), np.array(Y) #生成X和Y

执行函数读取

if __name__ == '__main__':
    G = imageSegmentationGenerator("data/dataset1/images_prepped_train/",
                                   "data/dataset1/annotations_prepped_train/", batch_size=16, n_classes=15, input_height=160, input_width=160)
    x, y = G.__next__()
    #由于imageSegmentationGenerator是生成器需要用__next__读取
    #类似进行了一个循环把逐一访问所有元素,只能单向前进
    print(x.shape, y.shape)

visualizeDataset

def imageSegmentationGenerator(images_path, segs_path, n_classes):
    assert images_path[-1] == '/'
    assert segs_path[-1] == '/'
	#检查输入是否为路径
    images = sorted(glob.glob(images_path +"*.jpg") +
        			glob.glob(images_path +"*.png") +
        			glob.glob(images_path +"*.jpeg"))
    segmentations = sorted(glob.glob(segs_path + "*.jpg") + 
    				glob.glob(segs_path + "*.png") + 
    				glob.glob(segs_path + "*.jpeg"))
	#按路径根据格式按顺序加载图片
    colors = [(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) for _ in range(n_classes)]#给每一个类按照255随机选择一种颜色

    assert len(images) == len(segmentations)#保证尺寸一致,是对应的图片
    for im_fn, seg_fn in zip(images, segmentations):

        img = cv2.imread(im_fn)
        seg = cv2.imread(seg_fn) #读图
        print(np.unique(seg)) #输出seg里用到的颜色通道

        seg_img = np.zeros_like(seg)#构件全零阵,与seg同形状

        for c in range(n_classes):
            seg_img[:, :, 0] += ((seg[:, :, 0] == c) *
                                 (colors[c][0])).astype('uint8')
            seg_img[:, :, 1] += ((seg[:, :, 0] == c) *
                                 (colors[c][1])).astype('uint8')
            seg_img[:, :, 2] += ((seg[:, :, 0] == c) *
                                 (colors[c][2])).astype('uint8')
		#按照新颜色安排
        eqaimg = color.rgb2hsv(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        eqaimg[:, :, 2] = exposure.equalize_hist(eqaimg[:, :, 2])
        eqaimg = color.hsv2rgb(eqaimg)

        cv2.imshow("img", img)
        cv2.imshow("seg_img", seg_img)
        cv2.imshow(
            "equalize_hist_img",
            cv2.cvtColor((eqaimg *255.).astype(np.uint8),cv2.COLOR_RGB2BGR))
        cv2.waitKey()

你可能感兴趣的:(Keras)