开发者实战 | 用OpenVINO™ C++ API编写YOLOv8-Seg实例分割模型推理程序

01. 简介

本文章将介绍使用 OpenVINO 2023.0 C++ API 开发YOLOv8-Seg 实例分割(Instance Segmentation)模型的 AI 推理程序。本文 C++ 范例程序的开发环境是 Windows + Visual Studio Community 2022。

请读者先配置基于 Visual Studio 的 OpenVINO C++ 开发环境

请克隆本文的代码仓:

git clone 

https://gitee.com/ppov-nuc/yolov8_openvino_cpp.git

02. 导出 YOLOv8-Seg OpenVINO IR 模型

YOLOv8 是 Ultralytics 公司基于 YOLO 框架,发布的一款面向物体检测与跟踪、实例分割、图像分类和姿态估计任务的 SOTA 模型工具套件。

首先用命令 :

pip install -r requirements.txt

安装  ultralytics 和 openvino-dev 。

然后使用命令:

yolo export model=yolov8n-seg.pt format=openvino half=True

向右滑动查看完整代码

导出 FP16 精度的 OpenVINO IR 模型,如下图所示。

8dce753893cbb59b0f7b11de3b618442.png

接着使用命令:

benchmark_app -m yolov8n-seg.xml -d GPU.1

向右滑动查看完整代码

获得 yolov8n-seg.xml 模型在 A770m 独立显卡上的异步推理计算性能,如下图所示。

56a1f419e0cc28865f88d3878205325d.png

03. 使用 OpenVINO C++ API 

编写 YOLOv8-Seg 实例分割模型推理程序

使用 OpenVINO C++ API 编写 YOLOv8-Seg 实例分割模型推理程序主要有5个典型步骤:

1

 采集图像&图像解码

2

 图像数据预处理

3

 AI 推理计算(基于 OpenVINO C++ API )

4

 对推理结果进行后处理

5

 将处理后的结果可视化

06f684b82a43dbea674ec3b3b3a537a6.png

YOLOv8-Seg 实例分割模型推理程序的图像数据预处理和AI推理计算的实现方式跟 YOLOv8 目标检测模型推理程序的实现方式几乎一模一样,可以直接复用。

3.1 图像数据预处理

使用 Netron 打开 yolov8n-seg.onnx ,如下图所示,可以看到:

输入节点的名字:“ images ”;数据:float32[1,3,640,640]

输出节点1的名字:“ output0 ”;数据:float32[1,116,8400]。其中116的前84个字段跟  YOLOv8 目标检测模型输出定义完全一致,即cx,cy,w,h 和80类的分数;后32个字段为掩膜置信度,用于计算掩膜数据。

输出节点2的名字:“ output1 ”;数据:float32[1,32,160,160]。output0 后32个字段与 output1 的数据做矩阵乘法后得到的结果,即为对应目标的掩膜数据

9ac4ebbe490cfac3c0ad7495a97bc3f9.png

图像数据预处理的目标就是将任意尺寸的图像数据转变为形状为[1,3,640,640],精度为 FP32 的张量。YOLOv8-Seg 模型的输入尺寸为正方形,为了解决将任意尺寸数据放缩为正方形带来的图像失真问题,在图像放缩前,采用 letterbox 算法先保持图像的长宽比,如下图所示,然后再使用 cv::dnn::blobFromImage 函数对图像进行放缩。

25352ee8afee11bc3e466f8a62f7a21a.png

图像数据预处理的范例程序如下所示:

Mat letterbox(const Mat& source)
{
    int col = source.cols;
    int row = source.rows;
    int _max = MAX(col, row);
    Mat result = Mat::zeros(_max, _max, CV_8UC3);
    source.copyTo(result(Rect(0, 0, col, row)));
    return result;
}
Mat img = cv::imread("bus.jpg"); 
Mat letterbox_img = letterbox(img);
Mat blob = blobFromImage(letterbox_img, 1.0/255.0, Size(640,640), Scalar(), true);

向右滑动查看完整代码

3.2 AI 同步推理计算

用 OpenVINO C++ API 实现同步推理计算,主要有七步:

1

实例化 Core 对象:ov::Core core;

2

编译并载入模型:core.compile_model();

3

创建推理请求:infer_request = compiled_model.create_infer_request();

4

读取图像数据并完成预处理;

5

将输入数据传入模型:infer_request.set_input_tensor(input_tensor);

6

启动推理计算:infer_request.infer();

7

获得推理结果:output0 = infer_request.get_output_tensor(0) ; 

output1 = infer_request.get_output_tensor(1) ;

范例代码如下所示:

// -------- Step 1. Initialize OpenVINO Runtime Core --------
    ov::Core core;
    // -------- Step 2. Compile the Model --------
    auto compiled_model = core.compile_model("yolov8n-seg.xml", "CPU");
    // -------- Step 3. Create an Inference Request --------
    ov::InferRequest infer_request = compiled_model.create_infer_request();
    // -------- Step 4.Read a picture file and do the preprocess --------
    Mat img = cv::imread("bus.jpg");
    // Preprocess the image
    Mat letterbox_img = letterbox(img);
    float scale = letterbox_img.size[0] / 640.0;
    Mat blob = blobFromImage(letterbox_img, 1.0 / 255.0, Size(640, 640), Scalar(), true);
    // -------- Step 5. Feed the blob into the input node of the Model -------
    // Get input port for model with one input
    auto input_port = compiled_model.input();
    // Create tensor from external memory
    ov::Tensor input_tensor(input_port.get_element_type(), input_port.get_shape(), blob.ptr(0));
    // Set input tensor for model with one input
    infer_request.set_input_tensor(input_tensor);
    // -------- Step 6. Start inference --------
    infer_request.infer();
    // -------- Step 7. Get the inference result --------
    auto output0 = infer_request.get_output_tensor(0); //output0
    auto output1 = infer_request.get_output_tensor(1); //otuput1

向右滑动查看完整代码

3.3 推理结果后处理

实例分割推理程序的后处理是从结果中拆解出预测别类(class_id),类别分数(class_score),类别边界框(box)和类别掩膜(mask),范例代码如下所示:

// -------- Step 8. Postprocess the result --------
    Mat output_buffer(output0_shape[1], output0_shape[2], CV_32F, output0.data<float>());
    Mat proto(32, 25600, CV_32F, output1.data<float>()); //[32,25600]
    transpose(output_buffer, output_buffer); //[8400,116]
    float score_threshold = 0.25;
    float nms_threshold = 0.5;
    std::vector<int> class_ids;
    std::vector<float> class_scores;
    std::vector<Rect> boxes;
    std::vector<Mat> mask_confs;
    // Figure out the bbox, class_id and class_score
    for (int i = 0; i < output_buffer.rows; i++) {
        Mat classes_scores = output_buffer.row(i).colRange(4, 84);
        Point class_id;
        double maxClassScore;
        minMaxLoc(classes_scores, 0, &maxClassScore, 0, &class_id);


        if (maxClassScore > score_threshold) {
            class_scores.push_back(maxClassScore);
            class_ids.push_back(class_id.x);
            float cx = output_buffer.at<float>(i, 0);
            float cy = output_buffer.at<float>(i, 1);
            float w = output_buffer.at<float>(i, 2);
            float h = output_buffer.at<float>(i, 3);
            int left = int((cx - 0.5 * w) * scale);
            int top = int((cy - 0.5 * h) * scale);
            int width = int(w * scale);
            int height = int(h * scale);
            cv::Mat mask_conf = output_buffer.row(i).colRange(84, 116);
            mask_confs.push_back(mask_conf);
            boxes.push_back(Rect(left, top, width, height));
        }
    }
    //NMS
    std::vector<int> indices;
    NMSBoxes(boxes, class_scores, score_threshold, nms_threshold, indices);

向右滑动查看完整代码

完整范例参考参见:yolov8_seg_ov_infer.cpp ,运行结果如下图所示:

b0b38252e8ad1bd47b318a2b5e64b2ae.png

04 结论

OpenVINO C++ API 简单清晰,易学易用。本文用不到100行(不含可视化检测结果)  C++  代码就实现了基于 OpenVINOYOLOv8-Seg 实例分割模型推理程序,在英特尔® 独立显卡 A770m 上获得了较好的推理计算性能。

--END--

你也许想了解(点击蓝字查看)⬇️➡️ OpenVINO™ DevCon 2023重磅回归!英特尔以创新产品激发开发者无限潜能➡️ 5周年更新 | OpenVINO™  2023.0,让AI部署和加速更容易➡️ OpenVINO™5周年重头戏!2023.0版本持续升级AI部署和加速性能➡️ OpenVINO™2023.0实战 | 在 LabVIEW 中部署 YOLOv8 目标检测模型➡️ 开发者实战系列资源包来啦!➡️ 以AI作画,祝她节日快乐;简单三步,OpenVINO™ 助你轻松体验AIGC
➡️ 还不知道如何用OpenVINO™作画?点击了解教程。➡️ 几行代码轻松实现对于PaddleOCR的实时推理,快来get!➡️ 使用OpenVINO 在“端—边—云”快速实现高性能人工智能推理➡️ 图片提取文字很神奇?试试三步实现OCR!➡️【Notebook系列第六期】基于Pytorch预训练模型,实现语义分割任务➡️使用OpenVINO™ 预处理API进一步提升YOLOv5推理性能
扫描下方二维码立即体验 
OpenVINO™ 工具套件 2023.0

点击 阅读原文 立即体验OpenVINO 2023.0

f0e7f18894c92f4c22278492130ef466.png

文章这么精彩,你有没有“在看

Yolov8-seg是一种基于目标检测和语义分割的实例分割方法。在Yolov8-seg中,首先使用YoloV5目标检测器检测图像中的物体,然后将检测到的物体传递给语义分割模型,以生成每个物体的分割掩膜。 如果您想提取分割掩膜,您可以按照以下步骤进行操作: 1. 使用Yolov8-seg模型检测图像中的物体。 2. 将检测到的物体传递给语义分割模型,以生成每个物体的分割掩膜。 3. 对于每个检测到的物体,提取其对应的分割掩膜。 4. 将分割掩膜应用于原始图像,以提取物体的图像部分。 您可以使用Python和深度学习框架(如PyTorch或TensorFlow)来实现这些步骤。以下是一个示例代码片段,用于提取Yolov8-seg模型生成的分割掩膜并将其应用于原始图像: ```python import cv2 import torch # Load Yolov8-seg and semantic segmentation models yolo_model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) seg_model = torch.hub.load('pytorch/vision', 'deeplabv3_resnet101', pretrained=True) # Load image img = cv2.imread('image.jpg') # Detect objects using Yolov8-seg model results = yolo_model(img) # Extract segmentation masks for each detected object masks = [] for result in results.xyxy: box = result[:4].tolist() mask = seg_model(img, box=box)['out'] mask = torch.argmax(mask.squeeze(), dim=0).cpu().numpy() masks.append(mask) # Apply segmentation masks to original image to extract object parts object_parts = [] for mask in masks: object_part = cv2.bitwise_and(img, img, mask=mask) object_parts.append(object_part) # Display extracted object parts for object_part in object_parts: cv2.imshow('Object part', object_part) cv2.waitKey(0) ``` 请注意,此代码片段仅用于示例目的,您需要根据自己的需求进行修改和优化。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值