OpenVINO部署Mask-RCNN实例分割网络

2022 年 1 月 27 日 极市平台
↑ 点击 蓝字  关注极市平台

作者丨gloomyfish
来源丨OpenCV学堂
编辑丨极市平台

极市导读

 

OpenVINO是英特尔推出的一款全面的工具套件,用于快速部署应用和解决方案,支持计算机视觉的CNN网络结构超过150余种。本文展示了用OpenVINO部署Mask-RCNN实例分割网络的详细过程及代码演示。 >>加入极市CV技术交流群,走在计算机视觉的最前沿

模型介绍

OpenVINO支持Mask-RCNN与yolact两种实例分割模型的部署,其中Mask-RCNN系列的实例分割网络是OpenVINO官方自带的,直接下载即可,yolact是来自第三方的公开模型库。

这里以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大小。

上面都是官方文档给我的关于模型的相关信息,但是我发现该模型的实际推理输raw_masks输出格式大小为:100x81x14x14这个算文档没更新吗?

代码演示

这边的代码输出层跟输入层都不止一个,所以为了简化,我用了两个for循环设置了输入与输出数据精度,然后直接通过hardcode来获取推理之后各个输出层对应的数据部分,首先获取类别,根据类别ID与Box的索引,直接获取实例分割mask,然后随机生成颜色,基于mask实现与原图BOX ROI的叠加,产生了实例分割之后的效果输出。完整的演示代码分为下面几步:IE引擎初始化与模型加载


InferenceEngine::Core ie;std::vector<std::string> coco_labels;read_coco_labels(coco_labels);cv::RNG rng(12345);
cv::Mat src = cv::imread("D:/images/sport-girls.png");cv::namedWindow("input", cv::WINDOW_AUTOSIZE);int im_h = src.rows;int im_w = src.cols;
InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);InferenceEngine::InputsDataMap inputs = network.getInputsInfo();InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();
设置输入与输出数据格式
std::string image_input_name = "";std::string image_info_name = "";int in_index = 0;for (auto item : inputs) {    if (in_index == 0) {        image_input_name = item.first;        auto input_data = item.second;        input_data->setPrecision(Precision::U8);        input_data->setLayout(Layout::NCHW);    }    else {        image_info_name = item.first;        auto input_data = item.second;        input_data->setPrecision(Precision::FP32);    }    in_index++;}
for (auto item : outputs) { std::string output_name = item.first; auto output_data = item.second; output_data->setPrecision(Precision::FP32); std::cout << "output name: " << output_name << std::endl;}

设置blob输入数据与推理

   
   
     
auto executable_network = ie.LoadNetwork(network, "CPU");auto infer_request = executable_network.CreateInferRequest();
auto input = infer_request.GetBlob(image_input_name);matU8ToBlob<uchar>(src, input);
auto input2 = infer_request.GetBlob(image_info_name);auto imInfoDim = inputs.find(image_info_name)->second->getTensorDesc().getDims()[1];InferenceEngine::MemoryBlob::Ptr minput2 = InferenceEngine::as<InferenceEngine::MemoryBlob>(input2);auto minput2Holder = minput2->wmap();float *p = minput2Holder.as<InferenceEngine::PrecisionTrait<InferenceEngine::Precision::FP32>::value_type *>();p[0] = static_cast<float>(inputs[image_input_name]->getTensorDesc().getDims()[2]);p[1] = static_cast<float>(inputs[image_input_name]->getTensorDesc().getDims()[3]);p[2] = 1.0f;
infer_request.Infer();

解析输出结果

   
   
     
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<PrecisionTrait<Precision::FP32>::value_type*>(scores->buffer());const float* boxes_data = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(boxes->buffer());const float* clazzes_data = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(clazzes->buffer());const auto raw_masks_data = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(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]\n", 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];for (int n = 0; n < max_count; n++) {    float confidence = score_data[n];    float xmin = boxes_data[n*object_size] * w_rate;    float ymin = boxes_data[n*object_size + 1] * h_rate;    float xmax = boxes_data[n*object_size + 2] * w_rate;    float ymax = boxes_data[n*object_size + 3] * h_rate;    if (confidence > 0.5) {        cv::Scalar color(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));        cv::Rect box;        float x1 = std::min(std::max(0.0f, xmin), static_cast<float>(im_w));        float y1 = std::min(std::max(0.0f,ymin), static_cast<float>(im_h));        float x2 = std::min(std::max(0.0f, xmax), static_cast<float>(im_w));        float y2 = std::min(std::max(0.0f, ymax), static_cast<float>(im_h));        box.x = static_cast<int>(x1);        box.y = static_cast<int>(y1);        box.width = static_cast<int>(x2 - x1);        box.height = static_cast<int>(y2 - y1);        int label = static_cast<int>(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);    }}

最终程序测试结果:


如果觉得有用,就请分享到朋友圈吧!

△点击卡片关注极市平台,获取 最新CV干货

公众号后台回复“transformer”获取最新Transformer综述论文下载~


极市干货
课程/比赛: 珠港澳人工智能算法大赛 保姆级零基础人工智能教程
算法trick 目标检测比赛中的tricks集锦 从39个kaggle竞赛中总结出来的图像分割的Tips和Tricks
技术综述: 一文弄懂各种loss function 工业图像异常检测最新研究总结(2019-2020)


CV技术社群邀请函 #

△长按添加极市小助手
添加极市小助手微信(ID : cvmart4)

备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳)


即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群


每月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~


觉得有用麻烦给个在看啦~   




登录查看更多
0

相关内容

CVPR2022 | 一种适用于密集场景的渐进式端到端目标检测器
专知会员服务
20+阅读 · 2021年7月28日
【CVPR2021】用Transformers无监督预训练进行目标检测
专知会员服务
55+阅读 · 2021年3月3日
CVPR2020 | 商汤-港中文等提出PV-RCNN:3D目标检测新网络
专知会员服务
43+阅读 · 2020年4月17日
【ICLR-2020】网络反卷积,NETWORK DECONVOLUTION
专知会员服务
37+阅读 · 2020年2月21日
ONNXRUNTIME C++ 版本推理部署踩坑记录
极市平台
1+阅读 · 2022年3月29日
Mask-RCNN模型的实现自定义对象(无人机)检测
计算机视觉life
17+阅读 · 2019年8月12日
PyTorch语义分割开源库semseg
极市平台
25+阅读 · 2019年6月6日
用PyTorch做物体检测和追踪
AI研习社
12+阅读 · 2019年1月6日
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
2+阅读 · 2009年12月31日
Arxiv
12+阅读 · 2021年11月1日
Deep Face Recognition: A Survey
Arxiv
17+阅读 · 2019年2月12日
VIP会员
相关资讯
ONNXRUNTIME C++ 版本推理部署踩坑记录
极市平台
1+阅读 · 2022年3月29日
Mask-RCNN模型的实现自定义对象(无人机)检测
计算机视觉life
17+阅读 · 2019年8月12日
PyTorch语义分割开源库semseg
极市平台
25+阅读 · 2019年6月6日
用PyTorch做物体检测和追踪
AI研习社
12+阅读 · 2019年1月6日
相关基金
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
2+阅读 · 2009年12月31日
Top
微信扫码咨询专知VIP会员