基于Pytorch的地表建筑物图片识别语义分割
- 一、项目简介
- 二、项目技术以及要求
- 三、基本概念
- 四、Unet网络
- 五、代码实现
- 六、源码获取
一、项目简介
遥感技术已成为获取地表覆盖信息最为行之有效的手段,遥感技术已经成功应用于地表覆盖检测、植被面积检测和建筑物检测任务。使用航拍数据地表建筑物识别,将地表航拍图像素划分为有建筑物和无建筑物两类。
二、项目技术以及要求
项目技术:python、pytorch、jupyter notebook、unet神经网络、pandas等
项目要求:建议使用GPU运行,Python版本3.6.5 理论更高版本也可
三、基本概念
卷积:计算权重矩阵和扫描所得的数据矩阵的乘积,然后把结果汇总成一个输出像素。
池化:池化过程在一般卷积过程后。池化(pooling) 的本质,其实就是采样。Pooling 对于输入的 Feature Map,选择某种方式对其进行降维压缩,以加快运算速度。采用较多的一种池化过程叫最大池化(Max Pooling)。
卷积相关计算公式
填充:前面可以发现,输入图像与卷积核进行卷积后的结果中损失了部分值,输入图像的边缘被“修剪”掉了(边缘处只检测了部分像素点,丢失了图片边界处的众多信息)。这是因为边缘上的像素永远不会位于卷积核中心,而卷积核也没法扩展到边缘区域以外。通过填充的方法,当卷积核扫描输入数据时,它能延伸到边缘以外的伪像素,从而使输出和输入size相同。
步长(Stride):滑动卷积核时,我们会先从输入的左上角开始,每次往左滑动一列或者往下滑动一行逐一计算输出,我们将每次滑动的行数和列数称为Stride。
上采样和下采样:
缩小图像(或称为下采样(subsampled)或降采样(downsampled))的主要目的有两个:1、使得图像符合显示区域的大小;2、生成对应图像的缩略图。
放大图像(或称为上采样(upsampling)或图像插值(interpolating))的主要目的是放大原图像,从而可以显示在更高分辨率的显示设备上。
四、Unet网络
概述:图像处理语义分割算法,语义分割需要判断图像每个像素点的类别,进行精确分割。语义分割目前在自动驾驶、自动抠图、医疗影像等领域有着比较广泛的应用。
网络结构:前半部分就是特征提取,后半部分是上采样(编码器-解码器结构)
Encoder:左半部分,由两个3x3的卷积层(RELU)再加上一个2x2的maxpooling层组成一个下采样的模块(后面代码可以看出);
Decoder:有半部分,由一个上采样的卷积层(去卷积层)+特征拼接concat+两个3x3的卷积层(ReLU)反复构成;
五、代码实现
- 框架:pytorch
- 网络接口:UNET
- 数据集:天池地表建筑物识别
- 数据集地址以及项目简介:https://tianchi.aliyun.com/competition/entrance/531872/information
天池数据MASK是CSV格式的,需要转换后才能使用。
def create_sample():
# 训练标签数据csv转图片
train_mask = pd.read_csv("./build_data/source/train_mask.csv", sep='\t', names=['name', 'mask'])
for name,mask in train_mask.values:
if(pd.isnull(mask)):
r_dir =TRAIN_IMG_DIR+ '/' +name
if(os.path.exists(r_dir)):
os.remove(r_dir)
print("删除"+r_dir)
continue;
mask = rle_decode(mask)
cv2.imwrite(TRAIN_MASK_DIR+'/'+name.rsplit(".",maxsplit=1)[0]+"_mask.jpg", mask*255)
转换后的MSKE图片
UNet网络结构如下代码定义
#定义UNet网络
class UNet(nn.Module):
def __init__(self):
super(UNet, self).__init__()
self.max_pool_2x2 = nn.MaxPool2d(kernel_size=2, stride=2)
self.down_conv_1 = double_conv(3, 64)
self.down_conv_2 = double_conv(64, 128)
self.down_conv_3 = double_conv(128, 256)
self.down_conv_4 = double_conv(256, 512)
self.down_conv_5 = double_conv(512, 1024)
self.up_trans_1 = nn.ConvTranspose2d(
in_channels=1024,
out_channels=512,
kernel_size=2,
stride=2
)
self.up_conv_1 = double_conv(1024, 512)
self.up_trans_2 = nn.ConvTranspose2d(
in_channels=512,
out_channels=256,
kernel_size=2,
stride=2
)
self.up_conv_2 = double_conv(512, 256)
self.up_trans_3 = nn.ConvTranspose2d(
in_channels=256,
out_channels=128,
kernel_size=2,
stride=2
)
self.up_conv_3 = double_conv(256, 128)
self.up_trans_4 = nn.ConvTranspose2d(
in_channels=128,
out_channels=64,
kernel_size=2,
stride=2
)
self.up_conv_4 = double_conv(128, 64)
self.out = nn.Conv2d(
in_channels=64,
out_channels=1,
kernel_size=1
)
def forward(self, image):
# expected size
# encoder (Normal convolutions decrease the size)
x1 = self.down_conv_1(image)
# print("x1 "+str(x1.shape))
x2 = self.max_pool_2x2(x1)
# print("x2 "+str(x2.shape))
x3 = self.down_conv_2(x2)
# print("x3 "+str(x3.shape))
x4 = self.max_pool_2x2(x3)
# print("x4 "+str(x4.shape))
x5 = self.down_conv_3(x4)
# print("x5 "+str(x5.shape))
x6 = self.max_pool_2x2(x5)
# print("x6 "+str(x6.shape))
x7 = self.down_conv_4(x6)
# print("x7 "+str(x7.shape))
x8 = self.max_pool_2x2(x7)
# print("x8 "+str(x8.shape))
x9 = self.down_conv_5(x8)
# print("x9 "+str(x9.shape))
# decoder (transposed convolutions increase the size)
x = self.up_trans_1(x9)
x = addPadding(x7, x)
x = self.up_conv_1(torch.cat([x7, x], 1))
x = self.up_trans_2(x)
x = addPadding(x5, x)
x = self.up_conv_2(torch.cat([x5, x], 1))
x = self.up_trans_3(x)
x = addPadding(x3, x)
x = self.up_conv_3(torch.cat([x3, x], 1))
x = self.up_trans_4(x)
x = addPadding(x1, x)
x = self.up_conv_4(torch.cat([x1, x], 1))
x = self.out(x)
# print(x.shape)
return x.to(DEVICE)
一些其他代码就不贴了,目前模型还在训练ing,因为显卡问题,所以epoch和batch_size设置都比较小。
六、源码获取
源码、安装教程文档、项目简介文档以及其它相关文档已经上传到是云猿实战官网,可以通过下面官网进行获取项目!