过年前后两周确实懈怠了这方面的学习,进度不明显,基本都在原地踏步,所以这两周都没交周报。这一周还算做了点东西,加上之前零零散散的进度,写了寒假的第四次周报。
BRRNet全称是Building Residual Refine Network,由预测模块(predict)和残差细化模块(residual refinement)两部分组成。基于编解码器结构的预测模块引入不同膨胀率的空洞卷积,逐步提取更多的全局特征特征提取过程中增强感受域。当预测模块输出对输入图像进行初步的建筑物提取结果,残差细化模块取预测模块的输出作为输入。它进一步细化的剩余之间的结果,预测模块与真实结果相匹配,从而提高了建筑物提取的准确性。
此外,该模型在训练过程中使用Dice_loss作为损失函数,有效地缓解了数据不平衡,进一步提高了建筑物提取的准确性。实验结果预期优于其他五种最先进的方法(其中包含deeplabV3+)。
这一部分的设计论文参考了U-Net和空洞卷积的结构,它由五个部分组成:输入、编码器、桥接、解码器和输出。我们的输入实验是遥感图像瓦片。编码器使用了U-Net编码器的前三块,其中每个块是一个两层卷积和一个最大池化层,窗口大小为 2 ∗ 2 2*2 2∗2和步长为2。卷积运算后,Batch归一化,执行ReLu激活函数。在这些块中使用的卷积内核大小是 3 ∗ 3 3*3 3∗3,以及内核的数量分别是64 128 256。预测模块的编码器删除了第四个块U-Net的编码器因为第4块有大量的参数。
前面的从高分辨率图像中提取建筑物的深度学习方法通常存在问题,如不完整的建筑提取和不准确的建筑足迹提取。对于这些问题的一个重要原因,就是要避免输入图像的信息严重丢失,从而影响最终的效果与定位精度。对于只使用少量的池操作的网络。对于遥感影像,建筑物所占用的像素数会随着分辨率提高。我们称图像中像素更多的建筑为大型建筑,甚至更多在高分辨率的偏远地区,大型建筑的色调和纹理不一致或形状复杂,仅使用少量的池层会导致接受能力不足覆盖整个建筑和周围的背景。因此,不可能提取整个建筑具有全局特征,导致建筑提取不完整等问题以及不准确的建筑足迹提取。
为了进一步提高接受能力提取更多的全局信息,同时避免了丢失的信息,在尽可能多的图像中,我们采用一种扩展的卷积级数结构,逐次递增,预测模块桥梁连接部分的膨胀率。卷积的大小kernel是 3 ∗ 3 3*3 3∗3,卷积kernel的个数是512。膨胀率设置为1,2,4,8,16,依次是32个。这些超参数在实验验证集上进行调整。
每个区块包括一个反卷积层和两个卷积层。反卷积操作是将前一阶段得到的特征图上采样2次次数,然后将更新的采样特征映射和相应的编码器映射连接起来。然后,通过两个卷积层提取特征。每一个卷积层后面是批处理标准化和ReLu激活功能。在解码器之后,我们使用一个卷积大小为1的kernel 1 ∗ 1 ∗ 64 1*1*64 1∗1∗64将feature map的通道数转换为1,然后使用Sigmoid激活函数,最终得到预测的预测概率图模块。为了进一步纠正预测模块结果与实际结果之间的残差,将预测概率图输入残差细分模块。
它与上一个模块的bridge的结构相似(预测模块中的连接部分),它使用6个旋转卷积,膨胀率为1、2、4、8、16、32提取特征,然后将不同尺度的特征图融合的方式。每次卷积操作后,进行批处理归一化和ReLu激活函数使用。空洞卷积的核数是64。然后是一个具有大小的卷积核 3 ∗ 3 ∗ 64 3*3*64 3∗3∗64, step size为1,将feature map的通道数转换为1。自输入的RRM_Bu图像包含了预测模块的初步信息,我们将其融合将这一阶段得到的特征映射以加性方式输入图像,然后输入将结果融合到Sigmoid函数中,得到最终的概率图。下图为RRM_Bu(b)和RRM_Lc(a)的对比。
程序使用的环境为python3.7+tensorflow2.1.
训练集、验证集和测试集均来源于ISPRS的Vaihingen数据。首先得把遥感图像进行裁剪成 256 ∗ 256 256*256 256∗256,为了增大训练集的数量,设置了裁切步长为64像素,大大地增加了数据集的总体数量。
def crop(imgs_in, segs_in, imgs_out, segs_out, size, stride):
num = 0
filename = glob.glob(imgs_in+'/*.tif')
l = len(filename)
for i in range(len(filename)):
print("准备裁剪第%d张影像..."%(i+1))
img = io.imread(imgs_in + '/' + filename[i].split('\\')[1])
seg = io.imread(segs_in + '/' + filename[i].split('\\')[1])
#seg = np.loadtxt(segs_in + '/' + filename[i].split('\\')[1].split('.')[0] + '.txt')
seg = np.uint8(seg)
length, width = img.shape[0:2]
m = math.floor((length - size)/stride) + 1
n = math.floor((width - size)/stride) + 1
for j in range(m):
for k in range(n):
img_patch = img[stride*j:stride*j+size, stride*k:stride*k+size, :]
seg_patch = seg[stride*j:stride*j+size, stride*k:stride*k+size]
# 影像块中白色部分的比例
white_proportion = white_proportion_of_img(img_patch)
# print("white proportion of img_patch:%f"%(white_proportion))
if white_proportion<0.01:
io.imsave(imgs_out + '/' + str(num) + '.tif', img_patch)
io.imsave(segs_out + '/' + str(num) + '.tif', seg_patch)
num += 1
print("共得到裁剪瓦片数目为:%d"%(num))
为了增强tensorflow框架读取数据的速度,这里设计了tfrecords文件,同时将img进行reshape,label转化成单通道。
def img2TFRecord(img_dir,label_dir,tfrecord_file,num_examples_txt_file):
"""
将图像和对应的标签制作成TFRecord文件,之后使用tf.data.TFRecordDataset读取TFRecord文件制作成dataset
:img_dir: 图像的文件夹
:label_dir: 标签的文件夹
:tfrecord_file: tfrecord文件,如 "train.tfrecords"
:num_examples_txt_file: 存放样本数目的txt文件
"""
# 要生成的tfrecord文件
print("prepare to generate %s..."%(tfrecord_file))
t0 = time.time()
writer = tf.io.TFRecordWriter(tfrecord_file)
img_filenames = glob.glob(img_dir+'/*.tif') # list all files in the img folder
num_examples = len(img_filenames)
# 把样本数目写入在一个txt中,之后需要用
with open(num_examples_txt_file,'w') as f:
f.write(str(num_examples))
for i in range(len(img_filenames)):
img_name = img_filenames[i].split("\\")[1]
# 对应的label文件
label_filename = label_dir + '/' + img_name
#img = Image.open(img_filenames[i])
img = io.imread(img_filenames[i])
#label = Image.open(label_filename)
label = io.imread(label_filename)
# transfer label from RGB to gray value
im_size = label.shape[:2]
new_mask = np.zeros(im_size,dtype='uint8')
c1 = np.stack([label[...,0]<50,label[...,1]<50,label[...,2]>200],axis=-1)
new_mask[c1.all(-1)] = 255
#label = new_mask
# resize image and label (for test in the trial)
# in practice, we have to crop the images to avoid artifacts
img = resize(img,(256,256,3),preserve_range=True)
new_mask = resize(new_mask,(256,256),preserve_range=True)
img = img.astype('uint8')
new_mask = new_mask.astype('uint8')
# 将图像和Label转化为二进制格式
img_raw = img.tobytes()
label_raw = new_mask.tobytes()
# 对label和img进行封装
example = tf.train.Example(features=tf.train.Features(feature={
"label_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[label_raw])),
'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw]))
}))
# 序列化为字符串
writer.write(example.SerializeToString())
这里的原理在第二部分已经说过了,还有loss_Function
和predict()
.
#############自定义损失函数#####################
def dice_coeff(self,y_true, y_pred):
smooth = 1.
# Flatten
y_true_f = tf.reshape(y_true, [-1])
y_pred_f = tf.reshape(y_pred, [-1])
intersection = tf.reduce_sum(y_true_f * y_pred_f)
# something wrong
# score = (2. * intersection + smooth) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + smooth)
score = (intersection) / (tf.reduce_sum(tf.square(y_true_f)) + tf.reduce_sum(tf.square(y_pred_f)))
return score
def dice_loss(self, y_true, y_pred):
loss = 1 - self.dice_coeff(y_true, y_pred)
return loss
def predict(self,img_dir,save_dir):
# 加载训练好的模型
model = keras.models.load_model(self.savemodel_path,custom_objects={
'dice_loss':self.dice_loss})
filenames = glob.glob(img_dir+'/*.tif')
for i in range(len(filenames)):
img_name = filenames[i].split("\\")[1]
img = io.imread(filenames[i])
# 归一化
img = np.float32(img) * (1.0/255)
#print(img.shape)
img = np.expand_dims(img,0)
#print(img.shape)
prediction = model.predict(img)
prediction[prediction>0.5] = 1
prediction[prediction<=0.5] = 0
# 把4-d 改为2-d
prediction = prediction[0,:,:,0]
#print('prediction shape')
#print(prediction.shape)
io.imsave(save_dir+'/'+img_name,prediction)
print("预测结果保存路径:%s"%(save_dir))
Parameters | results |
---|---|
PA | 0.2043365478515625 |
F1_score | 0.33933462903883826 |
precision | 0.2043365478515625 |
IOU | 0.2043365478515625 |
1、参考论文-BRRNet: A Fully Convolutional Neural Network for Automatic Building Extraction From High-Resolution Remote Sensing Images
2、项目参考