图像分割技术及经典实例分割网络Mask R-CNN(含基于Keras Python源码定义)
Posted Moresweet猫甜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像分割技术及经典实例分割网络Mask R-CNN(含基于Keras Python源码定义)相关的知识,希望对你有一定的参考价值。
图像分割技术及经典实例分割网络Mask R-CNN(含Python源码定义)
文章目录
1. 图像分割技术概述
图像分割技术是可以浅显的理解为精细化的目标检测过程,由于之前的目标检测算法只能使用标定框框定规则区域,从而进行分类,标出目标的大题区域,但是,在譬如自动驾驶领域,仅仅只有一个规则的区域去框定目标还是不够的,比如碰到车道线,那么仅仅用一个矩形区域框定车道线并不能准确地指导车辆的下一步动向,所以我们需要一个能够追溯细节的新应用领域,来将检测到的目标精细化。
图像分割即为图片的每个对象创建一个像素级的掩膜,这样可以追溯到目标轮廓的更多细节。下图为细菌的图像分割例子,为每个细菌做了图像分割。
图像分类有两类:
-
语义分割:语义分割关注类别,忽略个体实例。
-
实例分割:实力分割关注个体实例。
为了使得概念更加直观,下图说明了分类、目标检测、语义分割、实例分割的不同任务直观示意图。
2. FCN与语义分割
2.1 FCN简介
FCN即Fully Convolutional Networks,全卷积网络,FCN将传统卷积网络后面的全连接层换成了卷积层,这样网络输出不再是类别而是heatmap;同时为了解决因为卷积和池化对图像尺寸的影响,提出使用上采样的方式恢复尺寸。
传统分类使用的网络结构一般通过在最后连接全连接层,它会将原来二维的图像信息“压扁”成一维的(分类),从而丢失了空间信息,最后训练输出一个标量,这就是我们的分类标签。FCN网络和一般的网络的最大不同是,FCN产生的输出和输入的维度保持一致,即改变原本的CNN网络末端的全连接层,将其调整为卷积层,这样原本的分类网络最终输出一个热度图类型的图像。
其实在笔者的上一篇博文就提过全卷积,全卷积网络最大的特点是可以适应任意尺寸的输入,因为其不受最终分类数量的限制。
2.2 反卷积
反卷积又称转置卷积,它并不是正向卷积的完全逆过程。反卷积是一种特殊的正向卷积,先按照一
定的比例通过补0来扩大输入图像的尺寸,接着旋转卷积核,再进行正向卷积。
反卷积的处理步骤概括:
- 将上一层的卷积核反转(上下左右方向进行反转)。
- 将上一层卷积的结果作为输入,做补0扩充操作,即往每一个元素后面补0。这一步是根据步长来的,对于每个元素沿着步长方向补(步长减一)个0。例如,步长为1就不用补0了
- 在扩充后的输入基础上再对整体补0。以原始输入的shape作为输出shape,按照卷积padding规则,计算pading的补0的位置及个数,得到补0的位置及个数。
- 将补0后的卷积结果作为真正的输入,反转后的卷积核为filter,进行步长为1的卷积操作。
计算padding按规则补0时,统一按照padding=‘SAME’、步长为 1 × 1 1\\times 1 1×1的方式来计算
卷积输出通道公式:
o
=
i
−
k
+
2
×
p
s
+
1
o=\\fraci-k+2\\times ps+1
o=si−k+2×p+1
反卷积输入输出通道关系计算公式:
i
=
(
o
−
1
)
×
s
+
k
−
2
×
p
i=(o-1)\\times s+k-2\\times p
i=(o−1)×s+k−2×p
注意
通过反卷积操作并不能还原出卷积之前的图片,只能还原出卷积之前图片的尺寸。卷积和反卷积,并没有什么关系,操作的过程也都是不可逆的。
反卷积的应用场景:
- 反卷积/转置卷积在语义分割领域应用很广,如果说pooling层用于特征降维,那么在多个pooling
层后,就需要用转置卷积来进行分辨率的恢复。 - 如果up-sampling采用双线性插值进行分辨率的提升,这种提升是非学习的。采用反卷积来完成上采样的工作,就可以通过学习的方式得到更高的精度
反卷积的局限性:
矩阵稀疏,有大量的0元素,因此大量的信息是无用的,反卷积所用的转置矩阵计算是非常消耗计算资源的。
2.2 FCN与语义分割的关系
FCN对图像进行像素级的分类,从而解决了语义级别的图像分割(semantic segmentation)问题。FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。最后逐个像素计算softmax分类的损失, 相当于每一个像素对应一个训练样本。
对全卷积网络的末端再进行upsampling(上采样),即可得到和原图大小一样的输出,这就是
热度图了。这里上采样采用了deconvolutional(反卷积)的方法。
反最大池化、反平均池化
池化操作中最常见的最大池化和平均池化,因此最常见的反池化操作有反最大池化和反平均池化。
反最大池化需要记录池化时最大值的位置,反平均池化不需要此过程。
语义分割的一种实现-DeconvNet
3. Mask R-CNN
3.1 实例分割的难点
实例分割(instance segmentation)的难点在于:需要同时检测出目标的位置并且对目标进行分割,所以这就需要融合目标检测(框出目标的位置)以及语义分割(对像素进行分类,分割出目标)方法。
3.2 FPN(特征金字塔)
FPN即Feature Pyramid Networks,特征金字塔,其提出的背景为目标检测任务和语义分割任务里面常常需要检测小目标。但是当小目标比较小时,可能在原图里面只有几十个像素点。对于深度卷积网络,从一个特征层卷积到另一个特征层,无论步长是1还是2还是更多,卷积核都要遍布整个图片进行卷积,大的目标所占的像素点比小目标多,所以大的目标被经过卷积核的次数远比小的目标多,所以在下一个特征层里,会更多的反应大目标的特点。特别是在步长大于等于2的情况下,大目标的特点更容易得到保留,小目标的特征点容易被跳过。因此,经过很多层的卷积之后,小目标的特点会越来越少。
例如此图中的猫,对于周边的落叶来说,明显差距很大。
特征图(feature map)用蓝色轮廓表示,较粗的轮廓表示语义上更强的特征图。
- 对于(a),使用图像金字塔构建特征金字塔。特征是根据每个不同大小比例的图像独立计算的,每计算一次特征都需要resize一下图片大小,耗时,速度很慢。
- 对于(b),检测系统都在采用的为了更快地检测而使用的单尺度特征检测。
- 对于©,由卷积计算的金字塔特征层次来进行目标位置预测,但底层feature map特征表达能力不足。
- 对于(d),特征金字塔网络(FPN)和b,c一样快,但更准确。
FPN的提出是为了实现更好的feature maps融合,一般的网络都是直接使用最后一层的feature maps,虽然最后一层的feature maps 语义强,但是位置和分辨率都比较低,容易检测不到比较小的物体。FPN的功能就是融合了底层到高层的feature maps ,从而充分的利用了提取到的各个阶段的特征(ResNet中的C2-C5)。
3.2 Mask R-CNN
Mask R-CNN可算作是Faster R-CNN的升级版。Faster R-CNN广泛用于目标检测。对于给定图像,它会给图中每个对象加上类别标签与边界框坐标。Mask R-CNN框架是以Faster R-CNN为基础而架的。因此,针对给定图像, Mask R-CNN不仅会给每个对象添加类标签与边界框坐标,还会返回其对象掩膜。
Mask R-CNN的网络结构
在Mask R-CNN的设计中网络在进行目标检测的同时进行了实例分割。
Mask R-CNN的大体框架与Faster-RCNN框架相似,可以说在基础特征网络之后又加入了全连接的分割子网,由原来的两个任务(分类+回归)变为了三个任务(分类+回归+分割)。Mask R-CNN 是一个两阶段的框架,第一个阶段扫描图像并生成候选区域(proposals,即有可能包含一个目标的区域),第二阶段分类候选区域并生成边界框和掩码。
Faster R-CNN请参考笔者的上一篇博文《CV学习笔记-Faster-RCNN》
Mask R-CNN的不同
- 使用ResNet网络作为backbone
- 将 Roi Pooling 层替换成了 RoiAlign
- 添加并列的 Mask 层
- 引入FPN 和 FCN
Mask R-CNN的处理流程:
- 输入图像,进行预处理
- 将预处理后的图像信息输入到预训练好的神经网络中(例如ResNet)获得feature map
- 对这个feature map中的每一点设定预定个的ROI,从而获得多个候选ROI
- 将这些候选的ROI送入RPN网络进行二值分类(positive或negative)和BB回归,过滤掉一部分候选的ROI(截止到目前,Mask和Faster完全相同);
- 对这些剩下的ROI进行ROIAlign操作(ROIAlign为Mask R-CNN创新点1,比ROIPooling有长足进步);
- 最后,对这些ROI进行分类(N类别分类)、BB回归和MASK生成(在每一个ROI里面进行FCN操作)(引入FCN生成Mask是创新点2,使得此网络可以进行分割型任务)。
Mask R-CNN使用Resnet101作为backbone对应为CNN提取主干特征网络部分
ResNet的相关内容请参照笔者之前的博客《CV学习笔记-ResNet》
特征金字塔FPN的构建是为了实现特征多尺度的融合,在Mask R-CNN当中,我们取出在主干特征提取网络中长宽压缩了两次C2、三次C3、四次C4、五次C5的结果来进行特征金字塔结构的构造。
具体构造过程如下:
P2-P5是将来用于预测物体的bbox,box-regression,mask的。P2-P6是用于训练RPN的,即P6只用于RPN网络中。
3.3 RoiAlign
Mask-RCNN中提出了一个新的思想就是RoIAlign,其实RoIAlign就是在RoI pooling上稍微改动过来的,但是为什么在模型中不继续使用RoI pooling呢?
Roi pooling请参考笔者博客CV学习笔记-Faster-RCNN 3.3节
在RoI pooling中出现了两次的取整,虽然在feature maps上取整看起来只是小数级别的数,但是当
把feature map还原到原图上时就会出现很大的偏差,比如第一次的取整是舍去了0.78
(665/32=20.78),还原到原图时是20*32=640,第一次取整就存在了25个像素点的偏差,在第二
次的取整后的偏差更加的大。对于分类和物体检测来说可能这不是一个很大的误差,但是对于实
例分割而言,这是一个非常大的偏差,因为mask出现没对齐的话在视觉上是很明显的。而RoIAlign
的提出就是为了解决这个不对齐问题。
简单概括就是RoiAlign取消了取整的简单取舍,使用双线性插值的做法得到固定四个点坐标的像素值,从而使得不连续的操作变得连续起来返回到原图的时候误差将会更小。
它充分的利用了原图中虚拟点(比如20.56这个浮点数。像素位置都是整数值,没有浮点值)四周
的四个真实存在的像素值来共同决定目标图中的一个像素值,即可以将20.56这个虚拟的位置点对
应的像素值估计出来。
示例:
蓝色的虚线框表示卷积后获得的feature map,黑色实线框表示ROI feature。
最后需要输出的大小是2x2,那么我们就利用双线性插值来估计这些蓝点(虚拟坐标点,又称双线性插值的网格点)处所对应的像素值,最后得到相应的输出。
然后在每一个橘红色的区域里面进行max pooling或者average pooling操作,获得最终2x2的输出结果。我们的整个过程中没有用到量化操作,没有引入误差,即原图中的像素和feature map中的像素是完全对齐的,没有偏差,这不仅会提高检测的精度,同时也会有利于实例分割。
RoiAlign的输出将作为分割掩膜的依据。
3.4 分割掩膜
获得感兴趣区域(ROI)后,给已有框架加上一个掩膜分支,每个囊括特定对象的区域都会被赋予一个掩膜。每个区域都会被赋予一个 m × m m\\times m m×m掩膜,并按比例放大以便推断。
mask语义分割信息的获取
在之前的步骤中,我们获得了预测框,我们把这个预测框作为mask模型的区域截取部分,利用这个预测框对mask模型中用到的公用特征层进行截取。截取后,利用mask模型再对像素点进行分类,获得语义分割结果。
mask分支采用FCN对每个RoI产生一个
K
×
m
×
m
K\\times m \\times m
K×m×m的输出,即K个分辨率为
m
×
m
m\\times m
m×m的二值的掩膜,K为分类物体的种类数目。
K
×
m
×
m
K\\times m \\times m
K×m×m二值mask结构解释:最终的FCN输出一个K层的mask,每一层为一类。用0.5作为阈值进
行二值化,产生背景和前景的分割Mask。
对于预测的二值掩膜输出,我们对每个像素点应用sigmoid函数(或softmax等),整体损失定义
为交叉熵。引入预测K个输出的机制,允许每个类都生成独立的掩膜,避免类间竞争。这样做解
耦了掩膜和种类预测。
Mask R-CNN的损失函数为:
L
=
L
c
l
s
+
L
b
o
x
+
L
m
a
s
k
L=L_cls+L_box+L_mask
L=Lcls+Lbox+Lmask
Lmask 使得网络能够输出每一类的 mask,且不会有不同类别 mask 间的竞争:
- 分类网络分支预测 object 类别标签,以选择输出 mask。对每一个ROI,如果检测得到的ROI属于哪一个分类,就只使用哪一个分支的交叉熵误差作为误差值进行计算。
- 举例说明:分类有3类(猫,狗,人),检测得到当前ROI属于“人”这一类,那么所使用的Lmask为“人”这一分支的mask,即每个class类别对应一个mask可以有效避免类间竞争(其他class不贡献Loss)
- 对每一个像素应用sigmoid,然后取RoI上所有像素的交叉熵的平均值作为Lmask。
网络输出如何将 14 × 14 14\\times 14 14×14或者 28 × 28 28\\times 28 28×28大小的mask映射到原图是个问题
其实一个后处理,将模型预测的mask通过resize得到与proposal中目标相同大小的mask即可。
4. 工程实践
代码工程代码稍大,所以摘取网络定义的核心源码环节展示:
from keras.layers import Input,ZeroPadding2D,Conv2D,MaxPooling2D,BatchNormalization,Activation,UpSampling2D,Add,Lambda,Concatenate
from keras.layers import Reshape,TimeDistributed,Dense,Conv2DTranspose
from keras.models import Model
import keras.backend as K
from nets.resnet import get_resnet
from nets.layers import ProposalLayer,PyramidROIAlign,DetectionLayer,DetectionTargetLayer
from nets.mrcnn_training import *
from utils.anchors import get_anchors
from utils.utils import norm_boxes_graph,parse_image_meta_graph
import tensorflow as tf
import numpy as np
'''
TimeDistributed:
对FPN网络输出的多层卷积特征进行共享参数。
TimeDistributed的意义在于使不同层的特征图共享权重。
'''
#------------------------------------#
# 五个不同大小的特征层会传入到
# RPN当中,获得建议框
#------------------------------------#
def rpn_graph(feature_map, anchors_per_location):
shared = Conv2D(512, (3, 3), padding='same', activation='relu',
name='rpn_conv_shared')(feature_map)
x = Conv2D(2 * anchors_per_location, (1, 1), padding='valid',
activation='linear', name='rpn_class_raw')(shared)
# batch_size,num_anchors,2
# 代表这个先验框对应的类
rpn_class_logits = Reshape([-1,2])(x)
rpn_probs = Activation(
"softmax", name="rpn_class_xxx")(rpn_class_logits)
x = Conv2D(anchors_per_location * 4, (1, 1), padding="valid",
activation='linear', name='rpn_bbox_pred')(shared)
# batch_size,num_anchors,4
# 这个先验框的调整参数
rpn_bbox = Reshape([-1,4])(x)
return [rpn_class_logits, rpn_probs, rpn_bbox]
#------------------------------------#
# 建立建议框网络模型
# RPN模型
#------------------------------------#
def build_rpn_model(anchors_per_location, depth):
input_feature_map = Input(shape=[None, None, depth],
name="input_rpn_feature_map")
outputs = rpn_graph(input_feature_map, anchors_per_location)
return Model([input_feature_map], outputs, name="rpn_model")
#------------------------------------#
# 建立classifier模型
# 这个模型的预测结果会调整建议框
# 获得最终的预测框
#------------------------------------#
def fpn_classifier_graph(rois, feature_maps, image_meta,
pool_size, num_classes, train_bn=True,
fc_layers_size=1024):
# ROI Pooling,利用建议框在特征层上进行截取
# Shape: [batch, num_rois, POOL_SIZE, POOL_SIZE, channels]
x = PyramidROIAlign([pool_size, pool_size],
name="roi_align_classifier")([rois, image_meta] + feature_maps)
# Shape: [batch, num_rois, 1, 1, fc_layers_size],相当于两次全连接
x = TimeDistributed(Conv2D(fc_layers_size, (pool_size, pool_size), padding="valid"),
name="mrcnn_class_conv1")(x)
x = TimeDistributed(BatchNormalization(), name='mrcnn_class_bn1')(x, training=train_bn)
x = Activation('relu')(x)
# Shape: [batch, num_rois, 1, 1, fc_layers_size]
x = TimeDistributed(Conv2D(fc_layers_size, (1, 1)),
name="mrcnn_class_conv2")(x)
x = TimeDistributed(BatchNormalization(), name='mrcnn_class_bn2')(x, training=train_bn)
x = Activation('relu')(x)
# Shape: [batch, num_rois, fc_layers_size]
shared = Lambda(lambda x: K.squeeze(K.squeeze(x, 3), 2),
name="pool_squeeze")(x)
# Classifier head
# 这个的预测结果代表这个先验框内部的物体的种类
mrcnn_class_logits = TimeDistributed(Dense(num_classes),
name='mrcnn_class_logits')(shared)
mrcnn_probs = TimeDistributed(Activation("softmax"),
name="mrcnn_class")(mrcnn_class_logits)
# BBox head
# 这个的预测结果会对先验框进行调整
# [batch, num_rois, NUM_CLASSES * (dy, dx, log(dh), log(dw))]
x = TimeDistributed(Dense(num_classes * 4, activation='linear'),
name='mrcnn_bbox_fc')(shared)
# Reshape to [batch, num_rois, NUM_CLASSES, (dy, dx, log(dh), log(dw))]
mrcnn_bbox = Reshape((-1, num_classes, 4), name="mrcnn_bbox")(x)
return mrcnn_class_logits, mrcnn_probs, mrcnn_bbox
def build_fpn_mask_graph(rois, feature_maps, image_meta,
pool_size, num_classes, train_bn=True):
# ROI Align,利用建议框在特征层上进行截取
# Shape: [batch, num_rois, MASK_POOL_SIZE, MASK_POOL_SIZE, channels]
x = PyramidROIAlign([pool_size, pool_size],
name="roi_align_mask")([rois, image_meta] + feature_maps)
# Shape: [batch, num_rois, MASK_POOL_SIZE, MASK_POOL_SIZE, channels]
x = TimeDistributed(Conv2D(256, (3, 3), padding="same"),
name="mrcnn_mask_conv1")(x)
x = TimeDistributed(BatchNormalization(),
name='mrcnn_mask_bn1')(x, training=train_bn)
x = Activation('relu')(x)
# Shape: [batch, num_rois, MASK_POOL_SIZE, MASK_POOL_SIZE, channels]
x = TimeDistributed(Conv2D(256, (3, 3), padding="same"),
name="mrcnn_mask_conv2")(x)
x = TimeDistributed(BatchNormalization(),
name='mrcnn_mask_bn2')(x, training=train_bn)
x = Activation('relu')(x)
# Shape: [batch, num_rois, MASK_POOL_SIZE, MASK_POOL_SIZE, channels]
x = TimeDistributed(Conv2D(256, (3, 3), padding="same"),
name="mrcnn_mask_conv3")(x)
x = TimeDistributed(BatchNormalization(),
name='mrcnn_mask_bn3')(x, training=train_bn)
x = Activation('relu')(x)
# Shape: [batch, num_rois, MASK_POOL_SIZE, MASK_POOL_SIZE, channels]
x = TimeDistributed(Conv2D(256, (3, 3), padding="same"),
name="mrcnn_mask_conv4")(x)
x = TimeDistributed(BatchNormalization(),
name='mrcnn_mask_bn4')(x, training=train_bn)
x = Activation('relu')(x)
# Shape: [batch, num_rois, 2xMASK_POOL_SIZE, 2xMASK_POOL_SIZE, channels]
x = TimeDistributed(Conv2DTranspose(256, (2手把手教你使用LabVIEW实现Mask R-CNN图像实例分割(含源码)
(文章目录)
前言
前面给大家介绍了使用LabVIEW工具包实现图像分类,目标检测,今天我们来看一下如何使用LabVIEW实现Mask R-CNN图像实例分割。
一、什么是图像实例分割?
图像实例分割(Instance Segmentation)是在语义检测(Semantic Segmentation)的基础上进一步细化,分离对象的前景与背景,实现像素级别的对象分离。并且图像的语义分割与图像的实例分割是两个不同的概念,语义分割仅仅会区别分割出不同类别的物体,而实例分割则会进一步的分割出同一个类中的不同实例的物体。
计算机视觉中常见的一些任务(分类,检测,语义分割,实例分割)
二、什么是Mask R-CNN
Mask R-CNN是一个实例分割(Instance segmentation)算法,可以用来做“目标检测”、“目标实例分割”、“目标关键点检测”。 Mask R-CNN算法步骤:
- 首先,输入一幅你想处理的图片,然后进行对应的预处理操作,或者预处理后的图片;
- 将其输入到一个预训练好的神经网络中(ResNeXt等)获得对应的feature map;
- 对这个feature map中的每一点设定预定的ROI,从而获得多个候选ROI;
- 将这些候选的ROI送入RPN网络进行二值分类(前景或背景)和BB回归,过滤掉一部分候选的ROI
- 接着,对这些剩下的ROI进行ROIAlign操作(即先将原图和feature map的pixel对应起来,然后
- feature map和固定的feature对应起来);
- 最后,对这些ROI进行分类(N类别分类)、BB回归和MASK生成(在每一个ROI里面进行FCN操作)
三、LabVIEW调用Mask R-CNN图像实例分割模型
1、Mask R-CNN模型获取及转换
- 安装pytorch和torchvision
- 获取torchvision中的模型(我们获取预训练好的模型):
model = models.detection.maskrcnn_resnet50_fpn(pretrained=True)
- 转onnx
def get_pytorch_onnx_model(original_model):
model=original_model
# define the directory for further converted model save
onnx_model_path = dirname
# define the name of further converted model
onnx_model_name = "maskrcnn_resnet50.onnx"
# create directory for further converted model
os.makedirs(onnx_model_path, exist_ok=True)
# get full path to the converted model
full_model_path = os.path.join(onnx_model_path, onnx_model_name)
model.eval()
x = torch.rand(1, 3, 640, 640)
# model export into ONNX format
torch.onnx.export(
original_model,
x,
full_model_path,
input_names=["input"],
output_names=["boxes", "labels", "scores", "masks"],
dynamic_axes="input": [0, 1, 2, 3],"boxes": [0, 1],"labels": [0],"scores": [0],"masks": [0, 1, 2, 3],
verbose=True,opset_version=11
)
return full_model_path
完整获取及模型转换python代码如下:
import os
import torch
import torch.onnx
from torch.autograd import Variable
from torchvision import models
dirname, filename = os.path.split(os.path.abspath(__file__))
print(dirname)
def get_pytorch_onnx_model(original_model):
model=original_model
# define the directory for further converted model save
onnx_model_path = dirname
# define the name of further converted model
onnx_model_name = "maskrcnn_resnet50.onnx"
# create directory for further converted model
os.makedirs(onnx_model_path, exist_ok=True)
# get full path to the converted model
full_model_path = os.path.join(onnx_model_path, onnx_model_name)
model.eval()
x = torch.rand(1, 3, 640, 640)
# model export into ONNX format
torch.onnx.export(
original_model,
x,
full_model_path,
input_names=["input"],
output_names=["boxes", "labels", "scores", "masks"],
dynamic_axes="input": [0, 1, 2, 3],"boxes": [0, 1],"labels": [0],"scores": [0],"masks": [0, 1, 2, 3],
verbose=True,opset_version=11
)
return full_model_path
model = models.detection.maskrcnn_resnet50_fpn(pretrained=True)
print(get_pytorch_onnx_model(model))
2、LabVIEW调用 Mask R-CNN (mask rcnn.vi)
注意:Mask R-CNN模型是没办法使用OpenCV dnn去加载的,因为有些算子不支持,所以我们主要使用LabVIEW开放神经网络交互工具包(ONNX)来加载推理模型。
-
onnxruntime调用onnx模型并选择加速方式
-
图像预处理
-
执行推理
我们使用的模型是:maskrcnn_resnet50_fpn,其输出有四层,分别为boxes,labels,scores,masks,数据类型如下:
可以看到,labels的类型为INT64,所以我们的源码中需要“Get_Rresult_int64.vi,index为1,因为labels为第二层,即下标为1;
另外三个输出我们都可以使用float32来获取了,masks虽然数据类型是uint8,但在实操过程中发现,它其实做过归一化处理了,也可以使用float32.
-
后处理并实现实例分割
因为后处理内容较多,所以直接封装为了一个子VI, mask_rcnn_post_process.vi,源码如下:
整体的程序框架如下:
实例分割结果如下,我们会发现这个模型跑起来,他花的时间比之前就更长了。因为他不但要获取每一个对象的区域,还要也要把这个区域的轮廓给框出来,我们可以看到五个人及篮球都框出来了,使用不同的颜色分割出来了。
3、LabVIEW调用 Mask R-CNN 实现实时图像分割(mask rcnn_camera.vi)
整体思想和上面检测图片的实力分割差不多,不过使用了摄像头,并加了一个循环,对每一帧对象进行实力分割,3080系列显卡可选择TensorRT加速推理,分割会更加流畅。我们发现这个模型其实很考验检测数量的,所以如果你只是对人进行分割,那可以选择一个干净一些的背景,整体检测速度就会快很多。
四、Mask-RCNN训练自己的数据集(检测行人)
1.准备工作
- 训练需要jupyterlab环境,没有安装的同学需要通过pip install jupyterlab 安装
- 如果无法解决jupyterlab环境 可以使用colab或者kaggle提供的免费gpu环境进行训练
- 训练源码:mask-rcnn.ipynb
2.开始训练
- 根据提示运行这段代码,自动或手动下载依赖文件数据集并建立数据集解析类
- 定义单轮训练的函数:网络结构直接采用torchvison里现有的,不再重新定义
- 出现如下输出表示训练进行中
- 修改这个文件名,改成自己的图片名字,运行看下训练效果
3、训练效果
4、导出ONNX
五、获取源码
大家可关注微信公众号:VIRobotics,回复关键字:Mask R-CNN图像实例分割源码 获取本次分享内容的完整项目源码及模型。
总结
以上就是今天要给大家分享的内容。
如果有问题可以在评论区里讨论,提问前请先点赞支持一下博主哦,如您想要探讨更多关于LabVIEW与人工智能技术,欢迎加入我们进行技术交流:705637299,进群请备注暗号:LabVIEW 机器学习。
以上是关于图像分割技术及经典实例分割网络Mask R-CNN(含基于Keras Python源码定义)的主要内容,如果未能解决你的问题,请参考以下文章
手把手教你使用LabVIEW实现Mask R-CNN图像实例分割(含源码)
PyTorch版Mask R-CNN图像实例分割实战:训练自己的数据集