什么是图像实例分割?常见的图像实例分割有哪几种?

实例分割概念
图像实例分割是在对象检测的基础上进一步细化,分离对象的前景与背景,实现像素级别的对象分离。所以图像实例分割是基于对象检测的基础上进一步提升。图像实例分割在目标检测、人脸检测、表情识别、医学图像处理与疾病辅助诊断、视频监控与对象跟踪、零售场景的货架空缺识别等场景下均有应用。很多人会把图像语义分割跟实例分割搞混淆,其实图像的语义分割(semantic segmentation)与图像的实例分割(instance segmentation)是两个不同的概念,看下图:
图-1(来自coco数据集论文)
左侧是图像语义分割的结果,几个不同的类别人、羊、狗、背景分别用不同的颜色表示;右侧是图像实例分割的结果,对每只羊都用不同的颜色表示,而且把每个对象从背景中分离出来。这个就是语义分割跟实例分割的区别,直白点可以说就是语义分割是对每个类别、实例分割是针对每个对象(多个对象可能属于同一个类别)。
常见的实例分割网络
mask-rcnn实例分割网络
图像实例分割是在对象检测的基础上再多出个基于roi的分割分支,基于这样思想的实例分割mask-rcnn就是其经典代表,它的网络结构如下:
图-2(来自mask-rcnn的论文)
mask-rcnn可以简单地认为是faster-rcnn的基础上加上一个实例分割分支。
retinamask实例分割网络
retinamask可以看成retinanet对象检测网络跟mask-rcnn实例分割网络的两个优势组合,基于特征金字塔实现了更好的mask预测,网络结构图示如下:
图-3(来自retinamask论文)
panet实例分割网络
panet主要工作是基于mask-rcnn网络上改进所得,作者通过改进backbone部分提升了特征提取能力,通过自适应的池化操作得到更多融合特征,基于全链接融合产生mask,最终取得了比mask-rcnn更好的实例分割效果,该模型的结构如下:
图-4(来自panet论文)
其中全链接特征融合mask分支如下图:
图-5(来自panet论文)
yolact实例分割网络
该实例分割网络也是基于retinanet对象检测网络的基础上,添加一个mask分支,不过在添加mask分支的时候它的mask分支设计跟retinamask有所不同,该网络的结构图示如下:
图-6(来自yolact作者论文)
centermask实例分割网络
该实例网络是基于fcos对象检测框架的基础上,设计一个mask分支输出,该mask分支被称为空间注意力引导蒙板(spatial attention guided mask),该网络的结构如下:
图-7(来自centermask论文)
openvino 支持mask-rcnn模型
openvino 中支持两种实例分割模型分别是mask-rcnn与yolact模型,其中mask-rcnn模型支持来自英特尔官方库文件、而yolact则来自公开的第三方提供。我们这里以官方的mask-rcnn模型instance-segmentation-security-0050为例说明,该模型基于coco数据集训练,支持80个类别的实例分割,加上背景为81个类别。
openvino 支持部署faster-rcnn与mask-rcnn网络时候输入的解析都是基于两个输入层,它们分别是:
im_data : nchw=[1x3x480x480]
im_info: 1x3 三个值分别是h、w、scale=1.0
输出有四个,名称与输出格式及解释如下:
name: classes, shape: [100, ] 预测的100个类别可能性,值在[0~1]之间
name: scores: shape: [100, ] 预测的100个box可能性,值在[0~1]之间
name: boxes, shape: [100, 4] 预测的100个box坐标,左上角与右下角,基于输入的480x480
name: raw_masks, shape: [100, 81, 28, 28] box roi区域的实例分割输出,81表示类别(包含背景),28x28表示roi大小,注意:此模型输出大小为14x14
模型实例分割代码演示
因为模型的加载与推理部分的代码跟前面系列文章的非常相似,这里就不再给出。代码演示部分重点在输出的解析,为了简化,我用了两个for循环设置了输入与输出数据精度,然后直接通过hardcode的输出层名称来获取推理之后各个输出层对应的数据部分,首先获取类别,根据类别id与box的索引,直接获取实例分割mask,然后随机生成颜色,基于mask实现与原图box roi的叠加,产生了实例分割之后的效果输出。解析部分的代码首先需要获取推理以后的数据,获取数据的代码如下:
float w_rate = static_cast(im_w) / 480.0;
float h_rate = static_cast(im_h) / 480.0;
auto scores = infer_request.getblob(scores);
auto boxes = infer_request.getblob(boxes);
auto clazzes = infer_request.getblob(classes);
auto raw_masks = infer_request.getblob(raw_masks);
const float* score_data = static_cast(scores->buffer());
const float* boxes_data = static_cast(boxes->buffer());
const float* clazzes_data = static_cast(clazzes->buffer());
const auto raw_masks_data = static_cast(raw_masks->buffer());
const sizevector scores_outputdims = scores->gettensordesc().getdims();
const sizevector boxes_outputdims = boxes->gettensordesc().getdims();
const sizevector mask_outputdims = raw_masks->gettensordesc().getdims();
const int max_count = scores_outputdims[0];
const int object_size = boxes_outputdims[1];
printf(mask nchw=[%d, %d, %d, %d] , mask_outputdims[0], mask_outputdims[1], mask_outputdims[2], mask_outputdims[3]);
int mask_h = mask_outputdims[2];
int mask_w = mask_outputdims[3];
size_t box_stride = mask_h * mask_w * mask_outputdims[1];
然后根据输出数据格式开始解析box框与mask,这部分的代码如下:
for (int n = 0; n 0.5) {
cv::scalar color(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
cv::rect box;
float x1 = std::max(0.0f, xmin), static_cast(im_w));
float y1 = std::max(0.0f, ymin), static_cast(im_h));
float x2 = std::max(0.0f, xmax), static_cast(im_w));
float y2 = std::max(0.0f, ymax), static_cast(im_h));
box.x = static_cast(x1);
box.y = static_cast(y1);
box.width = static_cast(x2 - x1);
box.height = static_cast(y2 - y1);
int label = static_cast(clazzes_data[n]);
std::cout << confidence: << confidence << class name: << coco_labels[label] << std::endl;
// 解析mask
float* mask_arr = raw_masks_data + box_stride * n + mask_h * mask_w * label;
cv::mat mask_mat(mask_h, mask_w, cv_32fc1, mask_arr);
cv::mat roi_img = src(box);
cv::mat resized_mask_mat(box.height, box.width, cv_32fc1);
cv::resize(mask_mat, resized_mask_mat, cv::size(box.width, box.height));
cv::mat uchar_resized_mask(box.height, box.width, cv_8uc3, color);
roi_img.copyto(uchar_resized_mask, resized_mask_mat <= 0.5);
cv::addweighted(uchar_resized_mask, 0.7, roi_img, 0.3, 0.0f, roi_img);
cv::puttext(src, coco_labels[label].c_str(), box.tl() + (box.br() - box.tl()) / 2, cv::font_hershey_plain, 1.0, cv::scalar(0, 0, 255), 1, 8);
}
}
其中mask部分的时候有个技巧的地方,首先获取类别,然后根据类别,直接获取mask中对应的通道数据生成二值mask图像,添加上颜色,加权混合到roi区域即可得到输出结果。


华为mate10什么时候上市?华为mate10发布在即,华为Mate9再次迎来降价
辽宁省正全力推进5G网络建设
光伏向阳面板无色透明韧性耐候性好的涂层
苹果将加入新的深色模式,使用OLED屏的iPhone用户来说是个不错的消息
移相PWM系列谐振DC-DC转换器示例设计
什么是图像实例分割?常见的图像实例分割有哪几种?
内网直播局域网直播系统的搭建
双龙出海谁与争锋,华为、vivo、koobee双摄像头对比心得
NS-DR低压接地电阻柜的发展优势
基于虚拟仪器技术的航空机载电子设备自动测试系统[图]
TOPCon、HJT、XBC的发展如何
了解精密、可靠、易于设计的能源管理解决方案
干簧电阻式液位变送器的原理及特点
AI芯片不只拼算力,还得看可不可靠
IBM 最新报告 勒索软件威胁居高不下亚洲位列攻击目标榜首
黑科技太过炫酷!iPhone8将装备虹膜扫描仪
魅族Flyme6最新消息:Flyme6第三方ROM正式上线,第一批适配机型已出你的手机在吗?
高质量条幅/调频收音机电路(ULN2242),ULN2242 AM/FM RADIO
一加与老牌影像厂商哈苏进行合作
苏州移动为助力中超争冠赛制定网络覆盖方案,进行网络扩容优化