[
  {
    "path": ".gitignore",
    "content": "/data\n/__pycache__\n/.idea\n/test\n/output\n/Models/__pycache__\n"
  },
  {
    "path": "LoadBatches.py",
    "content": "import numpy as np\nimport cv2\nimport glob\nimport itertools\nimport matplotlib.pyplot as plt\nimport random\n\n\ndef getImageArr(im):\n\n    img = im.astype(np.float32)\n\n    img[:, :, 0] -= 103.939\n    img[:, :, 1] -= 116.779\n    img[:, :, 2] -= 123.68\n\n    return img\n\n\ndef getSegmentationArr(seg, nClasses, input_height, input_width):\n\n    seg_labels = np.zeros((input_height, input_width, nClasses))\n\n    for c in range(nClasses):\n        seg_labels[:, :, c] = (seg == c).astype(int)\n\n    seg_labels = np.reshape(seg_labels, (-1, nClasses))\n    return seg_labels\n\n\ndef imageSegmentationGenerator(images_path, segs_path, batch_size,\n                               n_classes, input_height, input_width):\n\n    assert images_path[-1] == '/'\n    assert segs_path[-1] == '/'\n\n    images = sorted(glob.glob(images_path + \"*.jpg\") +\n                    glob.glob(images_path + \"*.png\") + glob.glob(images_path + \"*.jpeg\"))\n\n    segmentations = sorted(glob.glob(segs_path + \"*.jpg\") +\n                           glob.glob(segs_path + \"*.png\") + glob.glob(segs_path + \"*.jpeg\"))\n\n    zipped = itertools.cycle(zip(images, segmentations))\n\n    while True:\n        X = []\n        Y = []\n        for _ in range(batch_size):\n            im, seg = zipped.__next__()\n            im = cv2.imread(im, 1)\n            seg = cv2.imread(seg, 0)\n\n            assert im.shape[:2] == seg.shape[:2]\n\n            assert im.shape[0] >= input_height and im.shape[1] >= input_width\n\n            xx = random.randint(0, im.shape[0] - input_height)\n            yy = random.randint(0, im.shape[1] - input_width)\n\n            im = im[xx:xx + input_height, yy:yy + input_width]\n            seg = seg[xx:xx + input_height, yy:yy + input_width]\n\n            X.append(getImageArr(im))\n            Y.append(\n                getSegmentationArr(\n                    seg,\n                    n_classes,\n                    input_height,\n                    input_width))\n\n        yield np.array(X), np.array(Y)\n\n\nif __name__ == '__main__':\n    G = imageSegmentationGenerator(\"data/dataset1/images_prepped_train/\",\n                                   \"data/dataset1/annotations_prepped_train/\", batch_size=16, n_classes=15, input_height=320, input_width=320)\n    x, y = G.__next__()\n    print(x.shape, y.shape)\n"
  },
  {
    "path": "Models/FCN32.py",
    "content": "from keras.applications import vgg16\nfrom keras.models import Model, Sequential\nfrom keras.layers import Conv2D, Conv2DTranspose, Input, Cropping2D, add, Dropout, Reshape, Activation\nfrom keras.utils import plot_model\n\n\ndef FCN32(nClasses, input_height, input_width):\n\n    assert input_height % 32 == 0\n    assert input_width % 32 == 0\n\n    img_input = Input(shape=(input_height, input_width, 3))\n\n    model = vgg16.VGG16(\n        include_top=False,\n        weights='imagenet', input_tensor=img_input)\n    assert isinstance(model, Model)\n\n    o = Conv2D(\n        filters=4096,\n        kernel_size=(\n            7,\n            7),\n        padding=\"same\",\n        activation=\"relu\",\n        name=\"fc6\")(\n            model.output)\n    o = Dropout(rate=0.5)(o)\n    o = Conv2D(\n        filters=4096,\n        kernel_size=(\n            1,\n            1),\n        padding=\"same\",\n        activation=\"relu\",\n        name=\"fc7\")(o)\n    o = Dropout(rate=0.5)(o)\n\n    o = Conv2D(filters=nClasses, kernel_size=(1, 1), padding=\"same\", activation=\"relu\", kernel_initializer=\"he_normal\",\n               name=\"score_fr\")(o)\n\n    o = Conv2DTranspose(filters=nClasses, kernel_size=(32, 32), strides=(32, 32), padding=\"valid\", activation=None,\n                        name=\"score2\")(o)\n\n    o = Reshape((-1, nClasses))(o)\n    o = Activation(\"softmax\")(o)\n\n    fcn8 = Model(inputs=img_input, outputs=o)\n    # mymodel.summary()\n    return fcn8\n\n\nif __name__ == '__main__':\n    m = FCN32(15, 320, 320)\n    m.summary()\n    plot_model(m, show_shapes=True, to_file='model_fcn32.png')\n    print(len(m.layers))\n"
  },
  {
    "path": "Models/FCN8.py",
    "content": "from keras.applications import vgg16\nfrom keras.models import Model, Sequential\nfrom keras.layers import Conv2D, Conv2DTranspose, Input, Cropping2D, add, Dropout, Reshape, Activation\n\n\ndef FCN8_helper(nClasses, input_height, input_width):\n\n    assert input_height % 32 == 0\n    assert input_width % 32 == 0\n\n    img_input = Input(shape=(input_height, input_width, 3))\n\n    model = vgg16.VGG16(\n        include_top=False,\n        weights='imagenet', input_tensor=img_input,\n        pooling=None,\n        classes=1000)\n    assert isinstance(model, Model)\n\n    o = Conv2D(\n        filters=4096,\n        kernel_size=(\n            7,\n            7),\n        padding=\"same\",\n        activation=\"relu\",\n        name=\"fc6\")(\n            model.output)\n    o = Dropout(rate=0.5)(o)\n    o = Conv2D(\n        filters=4096,\n        kernel_size=(\n            1,\n            1),\n        padding=\"same\",\n        activation=\"relu\",\n        name=\"fc7\")(o)\n    o = Dropout(rate=0.5)(o)\n\n    o = Conv2D(filters=nClasses, kernel_size=(1, 1), padding=\"same\", activation=\"relu\", kernel_initializer=\"he_normal\",\n               name=\"score_fr\")(o)\n\n    o = Conv2DTranspose(filters=nClasses, kernel_size=(2, 2), strides=(2, 2), padding=\"valid\", activation=None,\n                        name=\"score2\")(o)\n\n    fcn8 = Model(inputs=img_input, outputs=o)\n    # mymodel.summary()\n    return fcn8\n\n\ndef FCN8(nClasses, input_height, input_width):\n\n    fcn8 = FCN8_helper(nClasses, input_height, input_width)\n\n    # Conv to be applied on Pool4\n    skip_con1 = Conv2D(nClasses, kernel_size=(1, 1), padding=\"same\", activation=None, kernel_initializer=\"he_normal\",\n                       name=\"score_pool4\")(fcn8.get_layer(\"block4_pool\").output)\n    Summed = add(inputs=[skip_con1, fcn8.output])\n\n    x = Conv2DTranspose(nClasses, kernel_size=(2, 2), strides=(2, 2), padding=\"valid\", activation=None,\n                        name=\"score4\")(Summed)\n\n    ###\n    skip_con2 = Conv2D(nClasses, kernel_size=(1, 1), padding=\"same\", activation=None, kernel_initializer=\"he_normal\",\n                       name=\"score_pool3\")(fcn8.get_layer(\"block3_pool\").output)\n    Summed2 = add(inputs=[skip_con2, x])\n\n    #####\n    Up = Conv2DTranspose(nClasses, kernel_size=(8, 8), strides=(8, 8),\n                         padding=\"valid\", activation=None, name=\"upsample\")(Summed2)\n\n    Up = Reshape((-1, nClasses))(Up)\n    Up = Activation(\"softmax\")(Up)\n\n    mymodel = Model(inputs=fcn8.input, outputs=Up)\n\n    return mymodel\n\n\nif __name__ == '__main__':\n    m = FCN8(15, 320, 320)\n    from keras.utils import plot_model\n    plot_model(m, show_shapes=True, to_file='model_fcn8.png')\n    print(len(m.layers))\n"
  },
  {
    "path": "Models/SegNet.py",
    "content": "\"\"\"\n@author: LiShiHang\n@software: PyCharm\n@file: SegNet.py\n@time: 2018/12/18 14:58\n\"\"\"\nfrom keras import Model,layers\nfrom keras.layers import Input,Conv2D,BatchNormalization,Activation,Reshape\n\nfrom Models.utils import MaxUnpooling2D,MaxPoolingWithArgmax2D\n\ndef SegNet(nClasses, input_height, input_width):\n\n    assert input_height % 32 == 0\n    assert input_width % 32 == 0\n\n    img_input = Input(shape=( input_height, input_width,3))\n\n    # Block 1\n    x = layers.Conv2D(64, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block1_conv1')(img_input)\n    x = layers.Conv2D(64, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block1_conv2')(x)\n    x, mask_1 = MaxPoolingWithArgmax2D(name='block1_pool')(x)\n\n    # Block 2\n    x = layers.Conv2D(128, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block2_conv1')(x)\n    x = layers.Conv2D(128, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block2_conv2')(x)\n    x , mask_2 = MaxPoolingWithArgmax2D(name='block2_pool')(x)\n\n    # Block 3\n    x = layers.Conv2D(256, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block3_conv1')(x)\n    x = layers.Conv2D(256, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block3_conv2')(x)\n    x = layers.Conv2D(256, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block3_conv3')(x)\n    x, mask_3 = MaxPoolingWithArgmax2D(name='block3_pool')(x)\n\n    # Block 4\n    x = layers.Conv2D(512, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block4_conv1')(x)\n    x = layers.Conv2D(512, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block4_conv2')(x)\n    x = layers.Conv2D(512, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block4_conv3')(x)\n\n    x, mask_4 = MaxPoolingWithArgmax2D(name='block4_pool')(x)\n\n    # Block 5\n    x = layers.Conv2D(512, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block5_conv1')(x)\n    x = layers.Conv2D(512, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block5_conv2')(x)\n    x = layers.Conv2D(512, (3, 3),\n                      activation='relu',\n                      padding='same',\n                      name='block5_conv3')(x)\n    x, mask_5 = MaxPoolingWithArgmax2D(name='block5_pool')(x)\n\n    Vgg_streamlined=Model(inputs=img_input,outputs=x)\n\n    # 加载vgg16的预训练权重\n    Vgg_streamlined.load_weights(r\"E:\\Code\\PycharmProjects\\keras-segmentation\\data\\vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5\")\n\n    # 解码层\n    unpool_1 = MaxUnpooling2D()([x, mask_5])\n    y = Conv2D(512, (3,3), padding=\"same\")(unpool_1)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n    y = Conv2D(512, (3, 3), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n    y = Conv2D(512, (3, 3), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n\n    unpool_2 = MaxUnpooling2D()([y, mask_4])\n    y = Conv2D(512, (3, 3), padding=\"same\")(unpool_2)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n    y = Conv2D(512, (3, 3), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n    y = Conv2D(256, (3, 3), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n\n    unpool_3 = MaxUnpooling2D()([y, mask_3])\n    y = Conv2D(256, (3, 3), padding=\"same\")(unpool_3)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n    y = Conv2D(256, (3, 3), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n    y = Conv2D(128, (3, 3), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n\n    unpool_4 = MaxUnpooling2D()([y, mask_2])\n    y = Conv2D(128, (3, 3), padding=\"same\")(unpool_4)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n    y = Conv2D(64, (3, 3), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n\n    unpool_5 = MaxUnpooling2D()([y, mask_1])\n    y = Conv2D(64, (3, 3), padding=\"same\")(unpool_5)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n\n    y = Conv2D(nClasses, (1, 1), padding=\"same\")(y)\n    y = BatchNormalization()(y)\n    y = Activation(\"relu\")(y)\n\n    y = Reshape((-1, nClasses))(y)\n    y = Activation(\"softmax\")(y)\n\n    model=Model(inputs=img_input,outputs=y)\n    return model\n\n\n\nif __name__ == '__main__':\n    m = SegNet(15,320, 320)\n    # print(m.get_weights()[2]) # 看看权重改变没，加载vgg权重测试用\n    from keras.utils import plot_model\n    plot_model(m, show_shapes=True, to_file='model_segnet.png')\n    print(len(m.layers))\n    m.summary()\n"
  },
  {
    "path": "Models/UNet.py",
    "content": "\"\"\"\n@author: LiShiHang\n@software: PyCharm\n@file: UNet.py\n@time: 2018/12/27 16:54\n@desc:\n\"\"\"\nfrom keras import Model, layers\nfrom keras.applications import vgg16\nfrom keras.layers import Input, Conv2D, BatchNormalization, Activation, Reshape, MaxPool2D, concatenate, UpSampling2D\n\n\ndef UNet(nClasses, input_height, input_width):\n    assert input_height % 32 == 0\n    assert input_width % 32 == 0\n\n    img_input = Input(shape=(input_height, input_width, 3))\n\n    vgg_streamlined = vgg16.VGG16(\n        include_top=False,\n        weights='imagenet', input_tensor=img_input)\n    assert isinstance(vgg_streamlined, Model)\n\n    # 解码层\n    o = UpSampling2D((2, 2))(vgg_streamlined.output)\n    o = concatenate([vgg_streamlined.get_layer(\n        name=\"block4_pool\").output, o], axis=-1)\n    o = Conv2D(512, (3, 3), padding=\"same\")(o)\n    o = BatchNormalization()(o)\n\n    o = UpSampling2D((2, 2))(o)\n    o = concatenate([vgg_streamlined.get_layer(\n        name=\"block3_pool\").output, o], axis=-1)\n    o = Conv2D(256, (3, 3), padding=\"same\")(o)\n    o = BatchNormalization()(o)\n\n    o = UpSampling2D((2, 2))(o)\n    o = concatenate([vgg_streamlined.get_layer(\n        name=\"block2_pool\").output, o], axis=-1)\n    o = Conv2D(128, (3, 3), padding=\"same\")(o)\n    o = BatchNormalization()(o)\n\n    o = UpSampling2D((2, 2))(o)\n    o = concatenate([vgg_streamlined.get_layer(\n        name=\"block1_pool\").output, o], axis=-1)\n    o = Conv2D(64, (3, 3), padding=\"same\")(o)\n    o = BatchNormalization()(o)\n\n    # UNet网络处理输入时进行了镜面放大2倍，所以最终的输入输出缩小了2倍\n    # 此处直接上采样置原始大小\n    o = UpSampling2D((2, 2))(o)\n    o = Conv2D(64, (3, 3), padding=\"same\")(o)\n    o = BatchNormalization()(o)\n\n    o = Conv2D(nClasses, (1, 1), padding=\"same\")(o)\n    o = BatchNormalization()(o)\n    o = Activation(\"relu\")(o)\n\n    o = Reshape((-1, nClasses))(o)\n    o = Activation(\"softmax\")(o)\n\n    model = Model(inputs=img_input, outputs=o)\n    return model\n\n\nif __name__ == '__main__':\n    m = UNet(15, 320, 320)\n    # print(m.get_weights()[2]) # 看看权重改变没，加载vgg权重测试用\n    from keras.utils import plot_model\n    plot_model(m, show_shapes=True, to_file='model_unet.png')\n    print(len(m.layers))\n    m.summary()\n"
  },
  {
    "path": "Models/utils.py",
    "content": "\"\"\"\n@author: LiShiHang\n@software: PyCharm\n@file: utils.py\n@time: 2018/12/18 14:58\n\"\"\"\nfrom keras.engine import Layer\nimport keras.backend as K\n\n\nclass MaxPoolingWithArgmax2D(Layer):\n\n    def __init__(\n            self,\n            pool_size=(2, 2),\n            strides=(2, 2),\n            padding='same',\n            **kwargs):\n        super(MaxPoolingWithArgmax2D, self).__init__(**kwargs)\n        self.padding = padding\n        self.pool_size = pool_size\n        self.strides = strides\n\n    def call(self, inputs, **kwargs):\n        padding = self.padding\n        pool_size = self.pool_size\n        strides = self.strides\n        if K.backend() == 'tensorflow':\n            ksize = [1, pool_size[0], pool_size[1], 1]\n            padding = padding.upper()\n            strides = [1, strides[0], strides[1], 1]\n            output, argmax = K.tf.nn.max_pool_with_argmax(\n                inputs,\n                ksize=ksize,\n                strides=strides,\n                padding=padding)\n        else:\n            errmsg = '{} backend is not supported for layer {}'.format(\n                K.backend(), type(self).__name__)\n            raise NotImplementedError(errmsg)\n        argmax = K.cast(argmax, K.floatx())\n        return [output, argmax]\n\n    def compute_output_shape(self, input_shape):\n        ratio = (1, 2, 2, 1)\n        output_shape = [\n            dim // ratio[idx]\n            if dim is not None else None\n            for idx, dim in enumerate(input_shape)]\n        output_shape = tuple(output_shape)\n        return [output_shape, output_shape]\n\n    def compute_mask(self, inputs, mask=None):\n        return 2 * [None]\n\n\nclass MaxUnpooling2D(Layer):\n    def __init__(self, up_size=(2, 2), **kwargs):\n        super(MaxUnpooling2D, self).__init__(**kwargs)\n        self.up_size = up_size\n\n    def call(self, inputs, output_shape=None):\n\n        updates, mask = inputs[0], inputs[1]\n        with K.tf.variable_scope(self.name):\n            mask = K.cast(mask, 'int32')\n            input_shape = K.tf.shape(updates, out_type='int32')\n            #  calculation new shape\n            if output_shape is None:\n                output_shape = (\n                    input_shape[0],\n                    input_shape[1] * self.up_size[0],\n                    input_shape[2] * self.up_size[1],\n                    input_shape[3])\n\n            # calculation indices for batch, height, width and feature maps\n            one_like_mask = K.ones_like(mask, dtype='int32')\n            batch_shape = K.concatenate(\n                [[input_shape[0]], [1], [1], [1]],\n                axis=0)\n            batch_range = K.reshape(\n                K.tf.range(output_shape[0], dtype='int32'),\n                shape=batch_shape)\n            b = one_like_mask * batch_range\n            y = mask // (output_shape[2] * output_shape[3])\n            x = (mask // output_shape[3]) % output_shape[2]\n            feature_range = K.tf.range(output_shape[3], dtype='int32')\n            f = one_like_mask * feature_range\n\n            # transpose indices & reshape update values to one dimension\n            updates_size = K.tf.size(updates)\n            indices = K.transpose(K.reshape(\n                K.stack([b, y, x, f]),\n                [4, updates_size]))\n            values = K.reshape(updates, [updates_size])\n            ret = K.tf.scatter_nd(indices, values, output_shape)\n            return ret\n\n    def compute_output_shape(self, input_shape):\n        mask_shape = input_shape[1]\n        return (\n            mask_shape[0],\n            mask_shape[1] * self.up_size[0],\n            mask_shape[2] * self.up_size[1],\n            mask_shape[3]\n        )\n\n\nif __name__ == '__main__':\n\n    import keras\n    import numpy as np\n\n    # input = keras.layers.Input((4, 4, 3))\n    # o = MaxPoolingWithArgmax2D()(input)\n    # model = keras.Model(inputs=input, outputs=o)  # outputs=o\n    # model.compile(optimizer=\"adam\", loss='categorical_crossentropy')\n    # x = np.random.randint(0, 100, (3, 4, 4, 3)) # 调试此处\n    # m = model.predict(x) # 调试此处\n    # print(m)\n\n    input = keras.layers.Input((4, 4, 3))\n    o = MaxPoolingWithArgmax2D()(input)\n    o2 = MaxUnpooling2D()(o)\n    model = keras.Model(inputs=input, outputs=o2)  # outputs=o\n    model.compile(optimizer=\"adam\", loss='categorical_crossentropy')\n    x = np.random.randint(0, 100, (3, 4, 4, 3))  # 调试此处\n    m = model.predict(x)  # 调试此处\n    print(m)\n"
  },
  {
    "path": "Models/utils_cpu.py",
    "content": "\"\"\"\n@author: LiShiHang\n@software: PyCharm\n@file: utils.py\n@time: 2018/12/18 14:58\n\"\"\"\nfrom keras.engine import Layer\nimport keras.backend as K\nfrom keras.utils import plot_model\n\nclass MaxPoolingWithArgmax2D(Layer):\n\n    def __init__(\n            self,\n            pool_size=(2, 2),\n            strides=(2, 2),\n            padding='same',\n            **kwargs):\n        super(MaxPoolingWithArgmax2D, self).__init__(**kwargs)\n        self.padding = padding\n        self.pool_size = pool_size\n        self.strides = strides\n\n    def call(self, inputs, **kwargs):\n        padding = self.padding\n        pool_size = self.pool_size\n        strides = self.strides\n        if K.backend() == 'tensorflow':\n            ksize = [1, pool_size[0], pool_size[1], 1]\n            padding = padding.upper()\n            strides = [1, strides[0], strides[1], 1]\n            output, argmax = K.tf.nn.max_pool_with_argmax(\n                inputs,\n                ksize=ksize,\n                strides=strides,\n                padding=padding)\n        else:\n            errmsg = '{} backend is not supported for layer {}'.format(\n                K.backend(), type(self).__name__)\n            raise NotImplementedError(errmsg)\n        argmax = K.cast(argmax, K.floatx())\n        return [output, argmax]\n\n    def compute_output_shape(self, input_shape):\n        ratio = (1, 2, 2, 1)\n        output_shape = [\n            dim // ratio[idx]\n            if dim is not None else None\n            for idx, dim in enumerate(input_shape)]\n        output_shape = tuple(output_shape)\n        return [output_shape, output_shape]\n\n    def compute_mask(self, inputs, mask=None):\n        return 2 * [None]\n\n\nclass MaxUnpooling2D(Layer):\n    def __init__(self, up_size=(2, 2), **kwargs):\n        super(MaxUnpooling2D, self).__init__(**kwargs)\n        self.up_size = up_size\n\n    def call(self, inputs, output_shape=None):\n        updates, mask = inputs[0], inputs[1]\n        with K.tf.variable_scope(self.name):\n            mask = K.cast(mask, 'int32')\n            input_shape = K.tf.shape(updates, out_type='int32')\n            #  calculation new shape\n            if output_shape is None:\n                output_shape = (\n                    input_shape[0],\n                    input_shape[1] * self.up_size[0],\n                    input_shape[2] * self.up_size[1],\n                    input_shape[3])\n\n            # calculation indices for batch, height, width and feature maps\n            one_like_mask = K.ones_like(mask, dtype='int32')\n            batch_shape = K.concatenate(\n                [[input_shape[0]], [1], [1], [1]],\n                axis=0)\n            batch_range = K.reshape(\n                K.tf.range(output_shape[0], dtype='int32'),\n                shape=batch_shape)\n            b = one_like_mask * batch_range\n            # y = mask // (output_shape[2] * output_shape[3])\n            feature_range = K.tf.range(output_shape[3], dtype='int32')\n            f = one_like_mask * feature_range\n            y = (mask - f) // (output_shape[2] * output_shape[3]) - b * output_shape[1]\n            x = (mask // output_shape[3]) % output_shape[2]\n\n            # transpose indices & reshape update values to one dimension\n            updates_size = K.tf.size(updates)\n            indices = K.transpose(K.reshape(\n                K.stack([b, y, x, f]),\n                [4, updates_size]))\n            # indices_return = K.reshape(indices, (input_shape[0], 12, 4))\n            # indices_return = K.cast(indices_return, 'float32')\n            values = K.reshape(updates, [updates_size])\n            ret = K.tf.scatter_nd(indices, values, output_shape)\n            # ret = K.cast(ret, 'float32')\n            return ret\n\n    def compute_output_shape(self, input_shape):\n        mask_shape = input_shape[1]\n        return (\n            mask_shape[0],\n            mask_shape[1] * self.up_size[0],\n            mask_shape[2] * self.up_size[1],\n            mask_shape[3]\n        )\n\n\nif __name__ == '__main__':\n\n    import keras\n    import numpy as np\n\n    # input = keras.layers.Input((4, 4, 3))\n    # o = MaxPoolingWithArgmax2D()(input)\n    # model = keras.Model(inputs=input, outputs=o)  # outputs=o\n    # model.compile(optimizer=\"adam\", loss='categorical_crossentropy')\n    # x = np.random.randint(0, 100, (3, 4, 4, 3)) # 调试此处\n    # m = model.predict(x) # 调试此处\n    # print(m)\n\n    input = keras.layers.Input((4, 4, 3))\n    o = MaxPoolingWithArgmax2D()(input)\n    o2 = MaxUnpooling2D()(o)\n    model = keras.Model(inputs=input, outputs=o2)  # outputs=o\n    model.compile(optimizer=\"adam\", loss='categorical_crossentropy')\n    x = np.random.randint(0, 100, (3, 4, 4, 3))# 调试此处\n    m = model.predict(x)  # 调试此处\n    print(m)"
  },
  {
    "path": "predict.py",
    "content": "import LoadBatches\nfrom keras.models import load_model\nfrom Models import FCN32, FCN8, SegNet, UNet\nimport glob\nimport cv2\nimport numpy as np\nimport random\n\nn_classes = 11\n\nkey = \"unet\"\n\nmethod = {\n    \"fcn32\": FCN32.FCN32,\n    \"fcn8\": FCN8.FCN8,\n    \"segnet\": SegNet.SegNet,\n    'unet': UNet.UNet}\n\nimages_path = \"data/dataset1/images_prepped_test/\"\nsegs_path = \"data/dataset1/annotations_prepped_test/\"\n\ninput_height = 320\ninput_width = 320\n\ncolors = [\n    (random.randint(\n        0, 255), random.randint(\n            0, 255), random.randint(\n                0, 255)) for _ in range(n_classes)]\n\n##########################################################################\n\n\ndef label2color(colors, n_classes, seg):\n    seg_color = np.zeros((seg.shape[0], seg.shape[1], 3))\n    for c in range(n_classes):\n        seg_color[:, :, 0] += ((seg == c) *\n                               (colors[c][0])).astype('uint8')\n        seg_color[:, :, 1] += ((seg == c) *\n                               (colors[c][1])).astype('uint8')\n        seg_color[:, :, 2] += ((seg == c) *\n                               (colors[c][2])).astype('uint8')\n    seg_color = seg_color.astype(np.uint8)\n    return seg_color\n\n\ndef getcenteroffset(shape, input_height, input_width):\n    short_edge = min(shape[:2])\n    xx = int((shape[0] - short_edge) / 2)\n    yy = int((shape[1] - short_edge) / 2)\n    return xx, yy\n\n\nimages = sorted(\n    glob.glob(\n        images_path +\n        \"*.jpg\") +\n    glob.glob(\n        images_path +\n        \"*.png\") +\n    glob.glob(\n        images_path +\n        \"*.jpeg\"))\nsegmentations = sorted(glob.glob(segs_path + \"*.jpg\") +\n                       glob.glob(segs_path + \"*.png\") + glob.glob(segs_path + \"*.jpeg\"))\n\n\n# m = load_model(\"output/%s_model.h5\" % key)\nm = method[key](11, 320, 320)  # 有自定义层时，不能直接加载模型\nm.load_weights(\"output/%s_model.h5\" % key)\n\nfor i, (imgName, segName) in enumerate(zip(images, segmentations)):\n\n    print(\"%d/%d %s\" % (i + 1, len(images), imgName))\n\n    im = cv2.imread(imgName, 1)\n    # im=cv2.resize(im,(input_height,input_width))\n    xx, yy = getcenteroffset(im.shape, input_height, input_width)\n    im = im[xx:xx + input_height, yy:yy + input_width, :]\n\n    seg = cv2.imread(segName, 0)\n    # seg= cv2.resize(seg,interpolation=cv2.INTER_NEAREST)\n    seg = seg[xx:xx + input_height, yy:yy + input_width]\n\n    pr = m.predict(np.expand_dims(LoadBatches.getImageArr(im), 0))[0]\n    pr = pr.reshape((input_height, input_width, n_classes)).argmax(axis=2)\n\n    cv2.imshow(\"img\", im)\n    cv2.imshow(\"seg_predict_res\", label2color(colors, n_classes, pr))\n    cv2.imshow(\"seg\", label2color(colors, n_classes, seg))\n\n    cv2.waitKey()\n"
  },
  {
    "path": "readme.md",
    "content": "<h1 align=\"center\"><a href=\"https://github.com/lsh1994/keras-segmentation\" target=\"_blank\">keras-segmentation</a></h1>\n\n<p align=\"center\">\nImplementation is not original papers. The purpose of this project is to get started with semantic segmentation and master the basic process.\n</p>\n\n<font color=red>FCN32/8、SegNet、U-Net [Model published](https://github.com/lsh1994/keras-segmentation/releases). Thank you for your support.</font> \n\n[中文说明](readme_zh.md)\n\n## Environment\n  \nItem     | Value | Item     | Value\n:---: | :---: | :---: | :---: \nkeras | 2.2.4  | OS | win10\ntensorflow-gpu | 1.10/1.12 | Python| 3.6.7\n\n## Reference\n  \nhttps://github.com/divamgupta/image-segmentation-keras  \nhttps://github.com/ykamikawa/SegNet  \n  \nData：  \nhttps://drive.google.com/file/d/0B0d9ZiqAgFkiOHR1NTJhWVJMNEU/view?usp=sharing  \nData or：  \nhttps://github.com/alexgkendall/SegNet-Tutorial/tree/master/CamVid\n\n## Project Strcutre  \n![在这里插入图片描述](https://img-blog.csdnimg.cn/20181218212010847.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n`python  visualizeDataset.py`: Visual samples  \n![在这里插入图片描述](https://img-blog.csdnimg.cn/20181113165336706.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n`python train.py`: Execution train    \n`python predict.py`: Execution predict  \n\nYou can modify the parameter in project switching model or cloning the historical version.\n\n## About\n\n### FCN32\n\nVisualization results:    \n![在这里插入图片描述](https://img-blog.csdnimg.cn/2018111410255134.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n### FCN8\n\nVisualization results:   \n![在这里插入图片描述](https://img-blog.csdnimg.cn/20181114103306961.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n\n### SegNet\n\n### U-Net\n\n\n  "
  },
  {
    "path": "readme_zh.md",
    "content": "<h1 align=\"center\"><a href=\"https://github.com/lsh1994/keras-segmentation\" target=\"_blank\">keras-segmentation</a></h1>\n\n<p align=\"center\">\n非论文的原始实现。本工程目的是用于语义分割入门，掌握基本流程。\n</p>\n\n<font color=red>已经发布模型FCN32/8、SegNet、U-Net [对应提交](https://github.com/lsh1994/keras-segmentation/releases)。</font>\n\n## 实验环境\n\n  \nItem     | Value | Item     | Value\n:---: | :---: | :---: | :---: \nkeras | 2.2.4  | OS | win10\ntensorflow-gpu | 1.10/1.12 | Python| 3.6.7\n\n## 参考 \n\nhttps://github.com/divamgupta/image-segmentation-keras  \nhttps://github.com/ykamikawa/SegNet  \n  \n实验数据：  \nhttps://drive.google.com/file/d/0B0d9ZiqAgFkiOHR1NTJhWVJMNEU/view?usp=sharing  \n实验数据或者：  \nhttps://github.com/alexgkendall/SegNet-Tutorial/tree/master/CamVid\n\n## 文件结构  \n![在这里插入图片描述](https://img-blog.csdnimg.cn/20181218212010847.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n`python  visualizeDataset.py` 可视化样本：\n![在这里插入图片描述](https://img-blog.csdnimg.cn/20181113165336706.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n`python train.py`:训练  \n`python predict.py`:预测  \n请自行修改代码中相关参数切换模型，或者克隆历史版本。\n\n## 详细描述\n\n### FCN32\n\n[文章参考](https://blog.csdn.net/nima1994/article/details/84031759)  \n可视化结果：  \n![在这里插入图片描述](https://img-blog.csdnimg.cn/2018111410255134.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n### FCN8\n\n[文章参考](https://blog.csdn.net/nima1994/article/details/84062253)  \n可视化结果：  \n![在这里插入图片描述](https://img-blog.csdnimg.cn/20181114103306961.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pbWExOTk0,size_16,color_FFFFFF,t_70)\n\n\n### SegNet\n[文章参考](https://blog.csdn.net/nima1994/article/details/85079510)  \n\n### U-Net\n[文章参考](https://blog.csdn.net/nima1994/article/details/86300172)\n\n\n  "
  },
  {
    "path": "train.py",
    "content": "from keras.callbacks import ModelCheckpoint, TensorBoard\n\nimport LoadBatches\nfrom Models import FCN8, FCN32, SegNet, UNet\nfrom keras import optimizers\nimport math\n\n#############################################################################\ntrain_images_path = \"data/dataset1/images_prepped_train/\"\ntrain_segs_path = \"data/dataset1/annotations_prepped_train/\"\ntrain_batch_size = 8\nn_classes = 11\n\nepochs = 500\n\ninput_height = 320\ninput_width = 320\n\n\nval_images_path = \"data/dataset1/images_prepped_test/\"\nval_segs_path = \"data/dataset1/annotations_prepped_test/\"\nval_batch_size = 8\n\nkey = \"unet\"\n\n\n##################################\n\nmethod = {\n    \"fcn32\": FCN32.FCN32,\n    \"fcn8\": FCN8.FCN8,\n    'segnet': SegNet.SegNet,\n    'unet': UNet.UNet}\n\nm = method[key](n_classes, input_height=input_height, input_width=input_width)\nm.compile(\n    loss='categorical_crossentropy',\n    optimizer=\"adadelta\",\n    metrics=['acc'])\n\nG = LoadBatches.imageSegmentationGenerator(train_images_path,\n                                           train_segs_path, train_batch_size, n_classes=n_classes, input_height=input_height, input_width=input_width)\n\nG_test = LoadBatches.imageSegmentationGenerator(val_images_path,\n                                                val_segs_path, val_batch_size, n_classes=n_classes, input_height=input_height, input_width=input_width)\n\ncheckpoint = ModelCheckpoint(\n    filepath=\"output/%s_model.h5\" %\n    key,\n    monitor='acc',\n    mode='auto',\n    save_best_only='True')\ntensorboard = TensorBoard(log_dir='output/log_%s_model' % key)\n\nm.fit_generator(generator=G,\n                steps_per_epoch=math.ceil(367. / train_batch_size),\n                epochs=epochs, callbacks=[checkpoint, tensorboard],\n                verbose=2,\n                validation_data=G_test,\n                validation_steps=8,\n                shuffle=True)\n"
  },
  {
    "path": "visualizeDataset.py",
    "content": "import glob\nimport numpy as np\nimport cv2\nimport random\nfrom skimage import color, exposure\n\n\ndef imageSegmentationGenerator(images_path, segs_path, n_classes):\n\n    assert images_path[-1] == '/'\n    assert segs_path[-1] == '/'\n\n    images = sorted(\n        glob.glob(\n            images_path +\n            \"*.jpg\") +\n        glob.glob(\n            images_path +\n            \"*.png\") +\n        glob.glob(\n            images_path +\n            \"*.jpeg\"))\n    segmentations = sorted(glob.glob(\n        segs_path + \"*.jpg\") + glob.glob(segs_path + \"*.png\") + glob.glob(segs_path + \"*.jpeg\"))\n\n    colors = [\n        (random.randint(\n            0, 255), random.randint(\n            0, 255), random.randint(\n                0, 255)) for _ in range(n_classes)]\n\n    assert len(images) == len(segmentations)\n\n    for im_fn, seg_fn in zip(images, segmentations):\n\n        img = cv2.imread(im_fn)\n        seg = cv2.imread(seg_fn)\n        print(np.unique(seg))\n\n        seg_img = np.zeros_like(seg)\n\n        for c in range(n_classes):\n            seg_img[:, :, 0] += ((seg[:, :, 0] == c) *\n                                 (colors[c][0])).astype('uint8')\n            seg_img[:, :, 1] += ((seg[:, :, 0] == c) *\n                                 (colors[c][1])).astype('uint8')\n            seg_img[:, :, 2] += ((seg[:, :, 0] == c) *\n                                 (colors[c][2])).astype('uint8')\n\n        eqaimg = color.rgb2hsv(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n        eqaimg[:, :, 2] = exposure.equalize_hist(eqaimg[:, :, 2])\n        eqaimg = color.hsv2rgb(eqaimg)\n\n        cv2.imshow(\"img\", img)\n        cv2.imshow(\"seg_img\", seg_img)\n        cv2.imshow(\n            \"equalize_hist_img\",\n            cv2.cvtColor(\n                (eqaimg *\n                 255.).astype(\n                    np.uint8),\n                cv2.COLOR_RGB2BGR))\n        cv2.waitKey()\n\n\nimages = \"data/dataset1/images_prepped_train/\"\nannotations = \"data/dataset1/annotations_prepped_train/\"\nn_classes = 11\n\nimageSegmentationGenerator(images, annotations, n_classes)\n"
  }
]