yolov11的onnx模型C++ 调用

yolov11的onnx模型C++调用

  • 效果图
  • 一、python调用
  • 二、onnx模型导出
  • 三、python的onnx调用
    • 调用检测模型
    • 调用分割模型
  • 四、C++的onnx模型调用
  • 五 、视频流的检测
  • 后续

效果图

在这里插入图片描述

一、python调用

本文只记录生成的yolov11模型如何调用,其他可参考各种yolov11博客
模型下载:
yolo11模型及源码下载

模型调用:
下载好的python项目新建python文件

from ultralytics import YOLO# 加载模型
#model = YOLO("yolo11n.pt")
model = YOLO("yolo11n-seg.pt")
results = model("cat.jpg")
results[0].show()

不同模型效果不一样,有检测、有实例分割
在这里插入图片描述

在这里插入图片描述

二、onnx模型导出

导出onnx模型即在刚刚的代码下添加一行即可,具体参数参照各种博客,此时,文件所在的文件夹会生成一个onnx的模型,这个模型即可在python或者c++中调用

from ultralytics import YOLO# 加载模型
model = YOLO("yolo11n.pt")
# results = model("cat.jpg")
# results[0].show()path = model.export(format="onnx",dynamic=False ,opset=12)  

在这里插入图片描述

三、python的onnx调用

调用检测模型

# Ultralytics YOLO 🚀, AGPL-3.0 licenseimport argparse
import cv2
import numpy as np
import onnxruntime as ort# 类外定义类别映射关系,使用字典格式
CLASS_NAMES = {0: 'person',1: 'bicycle',2: 'car',3: 'motorcycle',4: 'airplane',5: 'bus',6: 'train',7: 'truck',8: 'boat',9: 'traffic light',10: 'fire hydrant',11: 'stop sign',12: 'parking meter',13: 'bench',14: 'bird',15: 'cat',16: 'dog',17: 'horse',18: 'sheep',19: 'cow',20: 'elephant',21: 'bear',22: 'zebra',23: 'giraffe',24: 'backpack',25: 'umbrella',26: 'handbag',27: 'tie',28: 'suitcase',29: 'frisbee',30: 'skis',31: 'snowboard',32: 'sports ball',33: 'kite',34: 'baseball bat',35: 'baseball glove',36: 'skateboard',37: 'surfboard',38: 'tennis racket',39: 'bottle',40: 'wine glass',41: 'cup',42: 'fork',43: 'knife',44: 'spoon',45: 'bowl',46: 'banana',47: 'apple',48: 'sandwich',49: 'orange',50: 'broccoli',51: 'carrot',52: 'hot dog',53: 'pizza',54: 'donut',55: 'cake',56: 'chair',57: 'couch',58: 'potted plant',59: 'bed',60: 'dining table',61: 'toilet',62: 'tv',63: 'laptop',64: 'mouse',65: 'remote',66: 'keyboard',67: 'cell phone',68: 'microwave',69: 'oven',70: 'toaster',71: 'sink',72: 'refrigerator',73: 'book',74: 'clock',75: 'vase',76: 'scissors',77: 'teddy bear',78: 'hair drier',79: 'toothbrush',# 可以添加更多类别...
}class YOLO11:"""YOLO11 目标检测模型类,用于处理推理和可视化。"""def __init__(self, onnx_model, input_image, confidence_thres, iou_thres):"""初始化 YOLO11 类的实例。参数:onnx_model: ONNX 模型的路径。input_image: 输入图像的路径。confidence_thres: 用于过滤检测结果的置信度阈值。iou_thres: 非极大值抑制(NMS)的 IoU(交并比)阈值。"""self.onnx_model = onnx_modelself.input_image = input_imageself.confidence_thres = confidence_thresself.iou_thres = iou_thres# 加载类别名称self.classes = CLASS_NAMES# 为每个类别生成一个颜色调色板self.color_palette = np.random.uniform(0, 255, size=(len(self.classes), 3))def preprocess(self):"""对输入图像进行预处理,以便进行推理。返回:image_data: 经过预处理的图像数据,准备进行推理。"""# 使用 OpenCV 读取输入图像self.img = cv2.imread(self.input_image)# 获取输入图像的高度和宽度self.img_height, self.img_width = self.img.shape[:2]# 将图像颜色空间从 BGR 转换为 RGBimg = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB)# 保持宽高比,进行 letterbox 填充, 使用模型要求的输入尺寸img, self.ratio, (self.dw, self.dh) = self.letterbox(img, new_shape=(self.input_width, self.input_height))# 通过除以 255.0 来归一化图像数据image_data = np.array(img) / 255.0# 将图像的通道维度移到第一维image_data = np.transpose(image_data, (2, 0, 1))  # 通道优先# 扩展图像数据的维度,以匹配模型输入的形状image_data = np.expand_dims(image_data, axis=0).astype(np.float32)# 返回预处理后的图像数据return image_datadef letterbox(self, img, new_shape=(640, 640), color=(114, 114, 114), auto=False, scaleFill=False, scaleup=True):"""将图像进行 letterbox 填充,保持纵横比不变,并缩放到指定尺寸。"""shape = img.shape[:2]  # 当前图像的宽高print(f"Original image shape: {shape}")if isinstance(new_shape, int):new_shape = (new_shape, new_shape)# 计算缩放比例r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])  # 选择宽高中最小的缩放比if not scaleup:  # 仅缩小,不放大r = min(r, 1.0)# 缩放后的未填充尺寸new_unpad = (int(round(shape[1] * r)), int(round(shape[0] * r)))# 计算需要的填充dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # 计算填充的尺寸dw /= 2  # padding 均分dh /= 2# 缩放图像if shape[::-1] != new_unpad:  # 如果当前图像尺寸不等于 new_unpad,则缩放img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)# 为图像添加边框以达到目标尺寸top, bottom = int(round(dh)), int(round(dh))left, right = int(round(dw)), int(round(dw))img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)print(f"Final letterboxed image shape: {img.shape}")return img, (r, r), (dw, dh)def postprocess(self, input_image, output):"""对模型输出进行后处理,以提取边界框、分数和类别 ID。参数:input_image (numpy.ndarray): 输入图像。output (numpy.ndarray): 模型的输出。返回:numpy.ndarray: 包含检测结果的输入图像。"""# 转置并压缩输出,以匹配预期形状outputs = np.transpose(np.squeeze(output[0]))rows = outputs.shape[0]boxes, scores, class_ids = [], [], []# 计算缩放比例和填充ratio = self.img_width / self.input_width, self.img_height / self.input_heightfor i in range(rows):classes_scores = outputs[i][4:]max_score = np.amax(classes_scores)if max_score >= self.confidence_thres:class_id = np.argmax(classes_scores)x, y, w, h = outputs[i][0], outputs[i][1], outputs[i][2], outputs[i][3]# 将框调整到原始图像尺寸,考虑缩放和填充x -= self.dw  # 移除填充y -= self.dhx /= self.ratio[0]  # 缩放回原图y /= self.ratio[1]w /= self.ratio[0]h /= self.ratio[1]left = int(x - w / 2)top = int(y - h / 2)width = int(w)height = int(h)boxes.append([left, top, width, height])scores.append(max_score)class_ids.append(class_id)indices = cv2.dnn.NMSBoxes(boxes, scores, self.confidence_thres, self.iou_thres)for i in indices:box = boxes[i]score = scores[i]class_id = class_ids[i]self.draw_detections(input_image, box, score, class_id)return input_imagedef draw_detections(self, img, box, score, class_id):"""在输入图像上绘制检测到的边界框和标签。参数:img: 用于绘制检测结果的输入图像。box: 检测到的边界框。score: 对应的检测分数。class_id: 检测到的目标类别 ID。返回:None"""# 提取边界框的坐标x1, y1, w, h = box# 获取类别对应的颜色color = self.color_palette[class_id]# 在图像上绘制边界框cv2.rectangle(img, (int(x1), int(y1)), (int(x1 + w), int(y1 + h)), color, 2)# 创建包含类别名和分数的标签文本label = f"{self.classes[class_id]}: {score:.2f}"# 计算标签文本的尺寸(label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)# 计算标签文本的位置label_x = x1label_y = y1 - 10 if y1 - 10 > label_height else y1 + 10# 绘制填充的矩形作为标签文本的背景cv2.rectangle(img, (label_x, label_y - label_height), (label_x + label_width, label_y + label_height), color,cv2.FILLED)# 在图像上绘制标签文本cv2.putText(img, label, (label_x, label_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)def main(self):# 使用 ONNX 模型创建推理会话,自动选择CPU或GPUsession = ort.InferenceSession(self.onnx_model,providers=["CUDAExecutionProvider", "CPUExecutionProvider"] if ort.get_device() == "GPU" else ["CPUExecutionProvider"],)# 打印模型的输入尺寸print("YOLO11 🚀 目标检测 ONNXRuntime")print("模型名称:", self.onnx_model)# 获取模型的输入形状model_inputs = session.get_inputs()input_shape = model_inputs[0].shapeself.input_width = input_shape[2]self.input_height = input_shape[3]print(f"模型输入尺寸:宽度 = {self.input_width}, 高度 = {self.input_height}")# 预处理图像数据,确保使用模型要求的尺寸 (640x640)img_data = self.preprocess()print("尺寸处理完毕")# 使用预处理后的图像数据运行推理outputs = session.run(None, {model_inputs[0].name: img_data})# 对输出进行后处理以获取输出图像return self.postprocess(self.img, outputs)  # 输出图像if __name__ == "__main__":# 创建参数解析器以处理命令行参数parser = argparse.ArgumentParser()parser.add_argument("--model", type=str, default="yolo11n-seg.onnx", help="输入你的 ONNX 模型路径。")parser.add_argument("--img", type=str, default=r"2222.jpg", help="输入图像的路径。")parser.add_argument("--conf-thres", type=float, default=0.5, help="置信度阈值")parser.add_argument("--iou-thres", type=float, default=0.45, help="NMS IoU 阈值")args = parser.parse_args()# 使用指定的参数创建 YOLO11 类的实例detection = YOLO11(args.model, args.img, args.conf_thres, args.iou_thres)# 执行目标检测并获取输出图像output_image = detection.main()# 保存输出图像到文件cv2.imwrite("det_result_picture.jpg", output_image)print("图像已保存为 det_result_picture.jpg")

在这里插入图片描述

调用分割模型

# Ultralytics YOLO 🚀, AGPL-3.0 license
"""
YOLO11 分割模型 ONNXRuntime功能1: 支持不用尺寸图像的输入功能2: 支持可视化分割结果
"""import argparse
import cv2
import numpy as np
import onnxruntime as ort# 类外定义类别映射关系,使用字典格式
CLASS_NAMES = {0: 'person',1: 'bicycle',2: 'car',3: 'motorcycle',4: 'airplane',5: 'bus',6: 'train',7: 'truck',8: 'boat',9: 'traffic light',10: 'fire hydrant',11: 'stop sign',12: 'parking meter',13: 'bench',14: 'bird',15: 'cat',16: 'dog',17: 'horse',18: 'sheep',19: 'cow',20: 'elephant',21: 'bear',22: 'zebra',23: 'giraffe',24: 'backpack',25: 'umbrella',26: 'handbag',27: 'tie',28: 'suitcase',29: 'frisbee',30: 'skis',31: 'snowboard',32: 'sports ball',33: 'kite',34: 'baseball bat',35: 'baseball glove',36: 'skateboard',37: 'surfboard',38: 'tennis racket',39: 'bottle',40: 'wine glass',41: 'cup',42: 'fork',43: 'knife',44: 'spoon',45: 'bowl',46: 'banana',47: 'apple',48: 'sandwich',49: 'orange',50: 'broccoli',51: 'carrot',52: 'hot dog',53: 'pizza',54: 'donut',55: 'cake',56: 'chair',57: 'couch',58: 'potted plant',59: 'bed',60: 'dining table',61: 'toilet',62: 'tv',63: 'laptop',64: 'mouse',65: 'remote',66: 'keyboard',67: 'cell phone',68: 'microwave',69: 'oven',70: 'toaster',71: 'sink',72: 'refrigerator',73: 'book',74: 'clock',75: 'vase',76: 'scissors',77: 'teddy bear',78: 'hair drier',79: 'toothbrush',# 可以添加更多类别...
}# 定义类别对应的颜色,格式为 (R, G, B)
CLASS_COLORS = {0: (255, 0, 0),  # 类别 0 的颜色为青黄色1: (255, 0, 255)  # 类别 1 的颜色为红色# 可以为其他类别指定颜色...
}class YOLO11Seg:def __init__(self, onnx_model):# 创建 Ort 推理会话,选择 CPU 或 GPU 提供者self.session = ort.InferenceSession(onnx_model,providers=["CUDAExecutionProvider", "CPUExecutionProvider"]if ort.get_device() == "GPU"else ["CPUExecutionProvider"],)# 根据 ONNX 模型类型选择 Numpy 数据类型(支持 FP32 和 FP16)self.ndtype = np.half if self.session.get_inputs()[0].type == "tensor(float16)" else np.single# 获取模型的输入宽度和高度(YOLO11-seg 只有一个输入)self.model_height, self.model_width = [x.shape for x in self.session.get_inputs()][0][-2:]# 打印模型的输入尺寸print("YOLO11 🚀 实例分割 ONNXRuntime")print("模型名称:", onnx_model)print(f"模型输入尺寸:宽度 = {self.model_width}, 高度 = {self.model_height}")# 加载类别名称self.classes = CLASS_NAMES# 加载类别对应的颜色self.class_colors = CLASS_COLORSdef get_color_for_class(self, class_id):return self.class_colors.get(class_id, (255, 255, 0))  # 如果没有找到类别颜色,返回白色def __call__(self, im0, conf_threshold=0.4, iou_threshold=0.45, nm=32):"""完整的推理流程:预处理 -> 推理 -> 后处理Args:im0 (Numpy.ndarray): 原始输入图像conf_threshold (float): 置信度阈值iou_threshold (float): NMS 中的 IoU 阈值nm (int): 掩膜数量Returns:boxes (List): 边界框列表segments (List): 分割区域列表masks (np.ndarray): [N, H, W] 输出掩膜"""# 图像预处理im, ratio, (pad_w, pad_h) = self.preprocess(im0)# ONNX 推理preds = self.session.run(None, {self.session.get_inputs()[0].name: im})# 后处理boxes, segments, masks = self.postprocess(preds,im0=im0,ratio=ratio,pad_w=pad_w,pad_h=pad_h,conf_threshold=conf_threshold,iou_threshold=iou_threshold,nm=nm,)return boxes, segments, masksdef preprocess(self, img):"""图像预处理Args:img (Numpy.ndarray): 输入图像Returns:img_process (Numpy.ndarray): 处理后的图像ratio (tuple): 宽高比例pad_w (float): 宽度的填充pad_h (float): 高度的填充"""# 调整输入图像大小并使用 letterbox 填充shape = img.shape[:2]  # 原始图像大小new_shape = (self.model_height, self.model_width)r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])ratio = r, rnew_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))pad_w, pad_h = (new_shape[1] - new_unpad[0]) / 2, (new_shape[0] - new_unpad[1]) / 2  # 填充宽高if shape[::-1] != new_unpad:  # 调整图像大小img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)top, bottom = int(round(pad_h - 0.1)), int(round(pad_h + 0.1))left, right = int(round(pad_w - 0.1)), int(round(pad_w + 0.1))img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(114, 114, 114))# 转换:HWC -> CHW -> BGR 转 RGB -> 除以 255 -> contiguous -> 添加维度img = np.ascontiguousarray(np.einsum("HWC->CHW", img)[::-1], dtype=self.ndtype) / 255.0img_process = img[None] if len(img.shape) == 3 else imgreturn img_process, ratio, (pad_w, pad_h)def postprocess(self, preds, im0, ratio, pad_w, pad_h, conf_threshold, iou_threshold, nm=32):"""推理后的结果后处理Args:preds (Numpy.ndarray): 来自 ONNX 的推理结果im0 (Numpy.ndarray): [h, w, c] 原始输入图像ratio (tuple): 宽高比例pad_w (float): 宽度的填充pad_h (float): 高度的填充conf_threshold (float): 置信度阈值iou_threshold (float): IoU 阈值nm (int): 掩膜数量Returns:boxes (List): 边界框列表segments (List): 分割区域列表masks (np.ndarray): 掩膜数组"""x, protos = preds[0], preds[1]  # 获取模型的两个输出:预测和原型# 转换维度x = np.einsum("bcn->bnc", x)# 置信度过滤x = x[np.amax(x[..., 4:-nm], axis=-1) > conf_threshold]# 合并边界框、置信度、类别和掩膜x = np.c_[x[..., :4], np.amax(x[..., 4:-nm], axis=-1), np.argmax(x[..., 4:-nm], axis=-1), x[..., -nm:]]# NMS 过滤x = x[cv2.dnn.NMSBoxes(x[:, :4], x[:, 4], conf_threshold, iou_threshold)]# 解析并返回结果if len(x) > 0:# 边界框格式转换:从 cxcywh -> xyxyx[..., [0, 1]] -= x[..., [2, 3]] / 2x[..., [2, 3]] += x[..., [0, 1]]# 缩放边界框,使其与原始图像尺寸匹配x[..., :4] -= [pad_w, pad_h, pad_w, pad_h]x[..., :4] /= min(ratio)# 限制边界框在图像边界内x[..., [0, 2]] = x[:, [0, 2]].clip(0, im0.shape[1])x[..., [1, 3]] = x[:, [1, 3]].clip(0, im0.shape[0])# 处理掩膜masks = self.process_mask(protos[0], x[:, 6:], x[:, :4], im0.shape)# 将掩膜转换为分割区域segments = self.masks2segments(masks)return x[..., :6], segments, masks  # 返回边界框、分割区域和掩膜else:return [], [], []@staticmethoddef masks2segments(masks):"""将掩膜转换为分割区域Args:masks (numpy.ndarray): 模型输出的掩膜,形状为 (n, h, w)Returns:segments (List): 分割区域的列表"""segments = []for x in masks.astype("uint8"):c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]  # 找到轮廓if c:c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)else:c = np.zeros((0, 2))  # 如果没有找到分割区域,返回空数组segments.append(c.astype("float32"))return segments@staticmethoddef crop_mask(masks, boxes):"""裁剪掩膜,使其与边界框对齐Args:masks (Numpy.ndarray): [n, h, w] 掩膜数组boxes (Numpy.ndarray): [n, 4] 边界框Returns:(Numpy.ndarray): 裁剪后的掩膜"""n, h, w = masks.shapex1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)r = np.arange(w, dtype=x1.dtype)[None, None, :]c = np.arange(h, dtype=x1.dtype)[None, :, None]return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))def process_mask(self, protos, masks_in, bboxes, im0_shape):"""处理模型输出的掩膜Args:protos (numpy.ndarray): [mask_dim, mask_h, mask_w] 掩膜原型masks_in (numpy.ndarray): [n, mask_dim] 掩膜数量bboxes (numpy.ndarray): 缩放到原始图像尺寸的边界框im0_shape (tuple): 原始输入图像的尺寸 (h,w,c)Returns:(numpy.ndarray): 处理后的掩膜"""c, mh, mw = protos.shapemasks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0)  # HWNmasks = np.ascontiguousarray(masks)masks = self.scale_mask(masks, im0_shape)  # 将掩膜从 P3 尺寸缩放到原始输入图像大小masks = np.einsum("HWN -> NHW", masks)  # HWN -> NHWmasks = self.crop_mask(masks, bboxes)  # 裁剪掩膜return np.greater(masks, 0.5)  # 返回二值化后的掩膜@staticmethoddef scale_mask(masks, im0_shape, ratio_pad=None):"""将掩膜缩放至原始图像大小Args:masks (np.ndarray): 缩放和填充后的掩膜im0_shape (tuple): 原始图像大小ratio_pad (tuple): 填充与原始图像的比例Returns:masks (np.ndarray): 缩放后的掩膜"""im1_shape = masks.shape[:2]if ratio_pad is None:  # 计算比例gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1])  # 比例pad = (im1_shape[1] - im0_shape[1] * gain) / 2, (im1_shape[0] - im0_shape[0] * gain) / 2  # 填充else:pad = ratio_pad[1]# 计算掩膜的边界top, left = int(round(pad[1] - 0.1)), int(round(pad[0] - 0.1))  # y, xbottom, right = int(round(im1_shape[0] - pad[1] + 0.1)), int(round(im1_shape[1] - pad[0] + 0.1))if len(masks.shape) < 2:raise ValueError(f'"len of masks shape" 应该是 2 或 3,但得到 {len(masks.shape)}')masks = masks[top:bottom, left:right]masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]), interpolation=cv2.INTER_LINEAR)  # 使用 INTER_LINEAR 插值调整大小if len(masks.shape) == 2:masks = masks[:, :, None]return masksdef draw_and_visualize(self, im, bboxes, segments, vis=False, save=True):"""绘制和可视化结果Args:im (np.ndarray): 原始图像,形状为 [h, w, c]bboxes (numpy.ndarray): [n, 4],n 是边界框数量segments (List): 分割区域的列表vis (bool): 是否使用 OpenCV 显示图像save (bool): 是否保存带注释的图像Returns:None"""# 创建图像副本im_canvas = im.copy()for (*box, conf, cls_), segment in zip(bboxes, segments):# 获取类别对应的颜色color = self.get_color_for_class(int(cls_))# 绘制轮廓和填充掩膜# cv2.polylines(im, np.int32([segment]), True, (255, 255, 255), 2)  # 绘制白色边框cv2.fillPoly(im_canvas, np.int32([segment]), color)  # 使用类别对应的颜色填充多边形# 绘制边界框cv2.rectangle(im, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), color, 1, cv2.LINE_AA)# 在图像上绘制类别名称和置信度cv2.putText(im, f"{self.classes[cls_]}: {conf:.3f}", (int(box[0]), int(box[1] - 9)),cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1, cv2.LINE_AA)# 将图像和绘制的多边形混合im = cv2.addWeighted(im_canvas, 0.3, im, 0.7, 0)# 显示图像if vis:cv2.imshow("seg_result_picture", im)cv2.waitKey(0)cv2.destroyAllWindows()# 保存图像if save:cv2.imwrite("seg_result_picture.jpg", im)if __name__ == "__main__":# 创建命令行参数解析器parser = argparse.ArgumentParser()parser.add_argument("--model", type=str, default=r"yolo11n-seg.onnx", help="ONNX 模型路径")parser.add_argument("--source", type=str,default=r"cat.jpg",help="输入图像路径")parser.add_argument("--conf", type=float, default=0.6, help="置信度阈值")parser.add_argument("--iou", type=float, default=0.45, help="NMS 的 IoU 阈值")args = parser.parse_args()# 加载模型model = YOLO11Seg(args.model)# 使用 OpenCV 读取图像img = cv2.imread(args.source)# 模型推理boxes, segments, _ = model(img, conf_threshold=args.conf, iou_threshold=args.iou)# 如果检测到目标,绘制边界框和分割区域if len(boxes) > 0:model.draw_and_visualize(img, boxes, segments, vis=False, save=True)

在这里插入图片描述

四、C++的onnx模型调用

在这里插入图片描述
在这里插入图片描述

#include <onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
#include <fstream>using namespace cv;
using namespace std;int main(int argc, char** argv)
{cv::Mat frame = cv::imread("cat.jpg", 1);std::string onnxpath = "yolo11m.onnx";//step2:load labelsstd::vector<std::string> labels;std::ifstream inputFile("coco.names");if (inputFile.is_open()){std::string classLine;while (std::getline(inputFile, classLine))labels.push_back(classLine);inputFile.close();}//step-3:load onnx modelint ih = frame.rows;int iw = frame.cols;std::wstring modelPath = std::wstring(onnxpath.begin(), onnxpath.end());Ort::SessionOptions session_options = Ort::SessionOptions();;Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "yolov11");std::cout << "onnxruntime inference try to use GPU Device" << std::endl;Ort::Session session_(env, modelPath.c_str(), session_options);std::vector<std::string> input_node_names;std::vector<std::string> output_node_names;size_t numInputNodes = session_.GetInputCount();size_t numOutputNodes = session_.GetOutputCount();Ort::AllocatorWithDefaultOptions allocator;input_node_names.reserve(numInputNodes);int input_w = 0;int input_h = 0;for (int i = 0; i < numInputNodes; i++) {//onnx newest version-1.14auto input_name = session_.GetInputNameAllocated(i, allocator);input_node_names.push_back(input_name.get());//onnx old version-1.8//input_node_names.push_back(session_.GetInputName(i, allocator));Ort::TypeInfo input_type_info = session_.GetInputTypeInfo(i);auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();auto input_dims = input_tensor_info.GetShape();input_w = input_dims[3];input_h = input_dims[2];std::cout << "input format: NxCxHxW = " << input_dims[0] << "x" << input_dims[1] << "x" << input_dims[2] << "x" << input_dims[3] << std::endl;}//step-4:get output parameterint output_h = 0;int output_w = 0;Ort::TypeInfo output_type_info = session_.GetOutputTypeInfo(0);auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();auto output_dims = output_tensor_info.GetShape();output_h = output_dims[1];output_w = output_dims[2];std::cout << "output format : HxW = " << output_dims[1] << "x" << output_dims[2] << std::endl;for (int i = 0; i < numOutputNodes; i++){//onnx newest version-1.14auto out_name = session_.GetOutputNameAllocated(i, allocator);output_node_names.push_back(out_name.get());//onnx old version-1.8//output_node_names.push_back(session_.GetOutputName(i, allocator));}std::cout << "input: " << input_node_names[0] << " output: " << output_node_names[0] << std::endl;//step-5:get infer resultint64 start = cv::getTickCount();int w = frame.cols;int h = frame.rows;int _max = std::max(h, w);cv::Mat image = cv::Mat::zeros(cv::Size(_max, _max), CV_8UC3);cv::Rect roi(0, 0, w, h);frame.copyTo(image(roi));// fix bug, boxes consistence!float x_factor = image.cols / static_cast<float>(input_w);float y_factor = image.rows / static_cast<float>(input_h);cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(input_w, input_h), cv::Scalar(0, 0, 0), true, false);size_t tpixels = input_h * input_w * 3;std::array<int64_t, 4> input_shape_info{ 1, 3, input_h, input_w };// set input data and inferenceauto allocator_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);Ort::Value input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, blob.ptr<float>(), tpixels, input_shape_info.data(), input_shape_info.size());const std::array<const char*, 1> inputNames = { input_node_names[0].c_str() };const std::array<const char*, 1> outNames = { output_node_names[0].c_str() };std::vector<Ort::Value> ort_outputs;try {ort_outputs = session_.Run(Ort::RunOptions{ nullptr }, inputNames.data(), &input_tensor_, 1, outNames.data(), outNames.size());}catch (std::exception e) {std::cout << e.what() << std::endl;}// output dataconst float* pdata = ort_outputs[0].GetTensorMutableData<float>();cv::Mat dout(output_h, output_w, CV_32F, (float*)pdata);cv::Mat det_output = dout.t(); // 8400x84// post-processstd::vector<cv::Rect> boxes;std::vector<int> classIds;std::vector<float> confidences;for (int i = 0; i < det_output.rows; i++) {cv::Mat classes_scores = det_output.row(i).colRange(4, 84);cv::Point classIdPoint;double score;minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint);//between 0~1if (score > 0.25){float cx = det_output.at<float>(i, 0);float cy = det_output.at<float>(i, 1);float ow = det_output.at<float>(i, 2);float oh = det_output.at<float>(i, 3);int x = static_cast<int>((cx - 0.5 * ow) * x_factor);int y = static_cast<int>((cy - 0.5 * oh) * y_factor);int width = static_cast<int>(ow * x_factor);int height = static_cast<int>(oh * y_factor);cv::Rect box;box.x = x;box.y = y;box.width = width;box.height = height;boxes.push_back(box);classIds.push_back(classIdPoint.x);confidences.push_back(score);}}// NMSstd::vector<int> indexes;cv::dnn::NMSBoxes(boxes, confidences, 0.25, 0.45, indexes);for (size_t i = 0; i < indexes.size(); i++) {int index = indexes[i];int idx = classIds[index];cv::rectangle(frame, boxes[index], cv::Scalar(0, 0, 255), 2, 8);cv::rectangle(frame, cv::Point(boxes[index].tl().x, boxes[index].tl().y - 20),cv::Point(boxes[index].br().x, boxes[index].tl().y), cv::Scalar(0, 255, 255), -1);std::string classString = labels[idx] + ' ' + std::to_string(confidences[idx]).substr(0, 4);putText(frame, classString, cv::Point(boxes[index].tl().x, boxes[index].tl().y), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);cv::imshow("YOLOv11 onnxrunning", frame);}//calculate FPS render itfloat t = (cv::getTickCount() - start) / static_cast<float>(cv::getTickFrequency());putText(frame, cv::format("FPS: %.2f", 1.0 / t), cv::Point(20, 40), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);cv::imshow("YOLOv11 onnxrunning", frame);cv::imwrite("result.jpg", frame);cv::waitKey(0);session_options.release();session_.release();return 0;
}

五 、视频流的检测

在这里插入图片描述

#include <onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
#include <fstream>using namespace cv;
using namespace std;int main(int argc, char** argv) 
{int c = 0;int frameRate = 10;Mat frame;namedWindow("video-demo", WINDOW_AUTOSIZE);VideoCapture capture;//连接视频capture.open("b.mp4");if (!capture.isOpened()) {printf("could not load video data...\n");return -1;}int frames = capture.get(CAP_PROP_FRAME_COUNT);//获取视频针数目(一帧就是一张图片)double fps = capture.get(CAP_PROP_FPS);//获取每针视频的频率// 获取帧的视频宽度,视频高度Size size = Size(capture.get(CAP_PROP_FRAME_WIDTH), capture.get(CAP_PROP_FRAME_HEIGHT));cout << frames << endl;cout << fps << endl;cout << size << endl;//cv::Mat frame = cv::imread("2222.jpg",1);std::string onnxpath = "yolo11n-seg.onnx";//step2:load labelsstd::vector<std::string> labels;std::ifstream inputFile("coco.names");if (inputFile.is_open()){std::string classLine;while (std::getline(inputFile, classLine))labels.push_back(classLine);inputFile.close();}//step-3:load onnx modelstd::wstring modelPath = std::wstring(onnxpath.begin(), onnxpath.end());Ort::SessionOptions session_options= Ort::SessionOptions();;Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "yolov11");std::cout << "onnxruntime inference try to use GPU Device" << std::endl;Ort::Session session_(env, modelPath.c_str(), session_options);std::vector<std::string> input_node_names;std::vector<std::string> output_node_names;size_t numInputNodes = session_.GetInputCount();size_t numOutputNodes = session_.GetOutputCount();Ort::AllocatorWithDefaultOptions allocator;input_node_names.reserve(numInputNodes);int input_w = 0;int input_h = 0;for (int i = 0; i < numInputNodes; i++) {//onnx newest version-1.14auto input_name = session_.GetInputNameAllocated(i, allocator);input_node_names.push_back(input_name.get());//onnx old version-1.8//input_node_names.push_back(session_.GetInputName(i, allocator));Ort::TypeInfo input_type_info = session_.GetInputTypeInfo(i);auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();auto input_dims = input_tensor_info.GetShape();input_w = input_dims[3];input_h = input_dims[2];std::cout << "input format: NxCxHxW = " << input_dims[0] << "x" << input_dims[1] << "x" << input_dims[2] << "x" << input_dims[3] << std::endl;}//step-4:get output parameterint output_h = 0;int output_w = 0;Ort::TypeInfo output_type_info = session_.GetOutputTypeInfo(0);auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();auto output_dims = output_tensor_info.GetShape();output_h = output_dims[1]; output_w = output_dims[2]; std::cout << "output format : HxW = " << output_dims[1] << "x" << output_dims[2] << std::endl;for (int i = 0; i < numOutputNodes; i++) {//onnx newest version-1.14auto out_name = session_.GetOutputNameAllocated(i, allocator);output_node_names.push_back(out_name.get());//onnx old version-1.8//output_node_names.push_back(session_.GetOutputName(i, allocator));}std::cout << "input: " << input_node_names[0] << " output: " << output_node_names[0] << std::endl;for (;;){//将视频转给每一张张图进行处理capture >> frame;if (c % frameRate == 0){//step-5:get infer resultint64 start = cv::getTickCount();int w = frame.cols;int h = frame.rows;if (w>0 &&h>0){int _max = std::max(h, w);cv::Mat image = cv::Mat::zeros(cv::Size(_max, _max), CV_8UC3);cv::Rect roi(0, 0, w, h);frame.copyTo(image(roi));// fix bug, boxes consistence!float x_factor = image.cols / static_cast<float>(input_w);float y_factor = image.rows / static_cast<float>(input_h);cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(input_w, input_h), cv::Scalar(0, 0, 0), true, false);size_t tpixels = input_h * input_w * 3;std::array<int64_t, 4> input_shape_info{ 1, 3, input_h, input_w };// set input data and inferenceauto allocator_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);Ort::Value input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, blob.ptr<float>(), tpixels, input_shape_info.data(), input_shape_info.size());const std::array<const char*, 1> inputNames = { input_node_names[0].c_str() };const std::array<const char*, 1> outNames = { output_node_names[0].c_str() };std::vector<Ort::Value> ort_outputs;try {ort_outputs = session_.Run(Ort::RunOptions{ nullptr }, inputNames.data(), &input_tensor_, 1, outNames.data(), outNames.size());}catch (std::exception e) {std::cout << e.what() << std::endl;}// output dataconst float* pdata = ort_outputs[0].GetTensorMutableData<float>();cv::Mat dout(output_h, output_w, CV_32F, (float*)pdata);cv::Mat det_output = dout.t(); // 8400x84// post-processstd::vector<cv::Rect> boxes;std::vector<int> classIds;std::vector<float> confidences;for (int i = 0; i < det_output.rows; i++) {cv::Mat classes_scores = det_output.row(i).colRange(4, 84);cv::Point classIdPoint;double score;minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint);//between 0~1if (score > 0.25){float cx = det_output.at<float>(i, 0);float cy = det_output.at<float>(i, 1);float ow = det_output.at<float>(i, 2);float oh = det_output.at<float>(i, 3);int x = static_cast<int>((cx - 0.5 * ow) * x_factor);int y = static_cast<int>((cy - 0.5 * oh) * y_factor);int width = static_cast<int>(ow * x_factor);int height = static_cast<int>(oh * y_factor);cv::Rect box;box.x = x;box.y = y;box.width = width;box.height = height;boxes.push_back(box);classIds.push_back(classIdPoint.x);confidences.push_back(score);}}// NMSstd::vector<int> indexes;cv::dnn::NMSBoxes(boxes, confidences, 0.25, 0.45, indexes);for (size_t i = 0; i < indexes.size(); i++) {int index = indexes[i];int idx = classIds[index];cv::rectangle(frame, boxes[index], cv::Scalar(0, 0, 255), 2, 8);cv::rectangle(frame, cv::Point(boxes[index].tl().x, boxes[index].tl().y - 20),cv::Point(boxes[index].br().x, boxes[index].tl().y), cv::Scalar(0, 255, 255), -1);std::string classString = labels[idx] + ' ' + std::to_string(confidences[idx]).substr(0, 4);putText(frame, classString, cv::Point(boxes[index].tl().x, boxes[index].tl().y), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);//cv::imshow("YOLOv11 onnxrunning", frame);}float t = (cv::getTickCount() - start) / static_cast<float>(cv::getTickFrequency());putText(frame, cv::format("FPS: %.2f", 1.0 / t), cv::Point(20, 40), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);//视频播放完退出if (frame.empty())break;imshow("video-demo", frame);//在视频播放期间按键退出if (waitKey(33) >= 0) break;}}c++;}//释放capture.release();session_options.release();session_.release();return 0;
}

后续

Qt的调用,当然也是很简单的!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/56858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

万年历制作

#include<stdio.h> int main() { int year0, month0, day0, y0, m0&#xff1b; scanf_s("%d %d", &year,&month); //判断闰年 for(y1900;y<year;y) { if ((y % 4 0 && y % 100 ! 0) || y % 400 0) …

redis内存打满了怎么办?

1、设置maxmemory的大小 我们需要给 Redis设置maxmemory的大小&#xff0c;如果不设置的话&#xff0c;它会受限于系统的物理内存和系统对内存的管理机制。 2、设置内存的淘汰策略 内存的淘汰策略分为 8 种&#xff0c;从淘汰范围来说分为从所有的key中淘汰和从设置过期时间…

C语言[求x的y次方]

C语言——求x的y次方 这段 C 代码的目的是从用户输入获取两个整数 x 和 y &#xff0c;然后计算 x 的 y 次幂&#xff08;不过这里有个小错误&#xff0c;实际计算的是 x 的 (y - 1) 次幂&#xff0c;后面会详细说&#xff09;&#xff0c;最后输出结果。 代码如下: #include…

Apache Paimon Catalog

Paimon Catalog可以持久化元数据&#xff0c;当前支持两种类型的metastore&#xff1a; 文件系统&#xff08;默认&#xff09;&#xff1a;将元数据和表文件存储在文件系统中。hive&#xff1a;在 hive metastore中存储元数据。用户可以直接从 Hive 访问表。 2.2.1 文件系统…

centeros7 编译ffmpeg

使用yum安装的路似乎已经堵住了&#xff0c;请求的镜像全是404或503 1.打开终端并使用yum安装EPEL存储库(Extra Packages for Enterprise Linux)&#xff1a;sudo yum install epel-release2.接下来&#xff0c;使用以下命令来安装FFmpeg&#xff1a;sudo yum install ffmpeg …

remote: HTTP Basic: Access denied

解决方法 输入&#xff1a; git config --system --unset credential.helper 再次进行 Git 操作&#xff0c;输入正确的用户名&#xff0c;密码即可。

static、 静态导入、成员变量的初始化、单例模式、final 常量(Content)、嵌套类、局部类、抽象类、接口、Lambda、方法引用

static static 常用来修饰类的成员&#xff1a;成员变量、方法、嵌套类 成员变量 被static修饰&#xff1a;类变量、成员变量、静态字段 在程序中只占用一段固定的内存&#xff08;存储在方法区&#xff09;&#xff0c;所有对象共享可以通过实例、类访问 (一般用类名访问和修…

OpenHarmony(1)开发环境搭建

一&#xff1a;开源项目 OpenHarmony是由开放原子开源基金会&#xff08;OpenAtom Foundation&#xff09;孵化及运营的开源项目&#xff0c;目标是面向全场景、全连接、全智能时代&#xff0c;基于开源的方式&#xff0c;搭建一个智能终端设备操作系统的框架和平台&#xff0…

使用SQL在PostGIS中创建各种空间数据

#1024程序员节&#xff5c;征文# 一、目录 1. 概述 2. 几何&#xff08;Geometry&#xff09;类型 创建点 创建线 创建面 3. 地理&#xff08;Geography&#xff09;类型 地理点&#xff08;GEOGRAPHY POINT&#xff09; 地理线串&#xff08;GEOGRAPHY LINESTRING&#xff…

Redis 单机、主从、哨兵和集群架构详解和搭建

目录 前言 单机部署 检查安装 gcc 环境 下载安装 Redis 启动 Redis 关闭 Redis 配置Redis 主从部署 整体架构图 主从复制配置 重启 Redis 验证 主从复制的作⽤ 主从复制缺点 哨兵部署&#xff08;Sentinel&#xff09; 整体架构图 哨兵模式配置 启动哨兵 验证…

MySQL-32.索引-操作语法

一.语法 二.代码实现 指定某个字段为主键&#xff0c;其实就是建立一个主键索引。而指定某个字段唯一&#xff0c;就是建立一个唯一索引。 -- 索引 -- 创建&#xff1a;为tb_emp表的name字段建立一个索引 create index idx_emp_name on tb_emp(name);-- 查询&#xff1a;查…

【智能大数据分析 | 实验四】Spark实验:Spark Streaming

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘&#xff0c;以提取有价值的信息和洞察。它结合了大数据技术、人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&a…

基于java的山区环境监督管理系统(源码+定制+开发)环境数据可视化、环境数据监测、 环境保护管理 、污染防治监测系统 大数据分析

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

《Python游戏编程入门》注-第3章3

《Python游戏编程入门》的“3.2.4 Mad Lib”中介绍了一个名为“Mad Lib”游戏的编写方法。 1 游戏玩法 “Mad Lib”游戏由玩家根据提示输入一些信息&#xff0c;例如男人姓名、女人姓名、喜欢的食物以及太空船的名字等。游戏根据玩家输入的信息编写出一个故事&#xff0c;如图…

Postgresql 配置数据库表添加主键自增id

#1024程序员节&#xff5c;征文# 在 PostgreSQL 数据库中&#xff0c;如果你想创建一个自增的 ID 字段&#xff0c;通常会使用序列&#xff08;sequence&#xff09;配合默认值或者使用带有自动递增特性的 SERIAL 类型。以下是两种常见的方法来实现自增 ID&#xff1a; 使用 …

图论BFS

 D1. The Endspeaker (Easy Version) time limit per test 2 seconds memory limit per test 256 megabytes  This is the easy version of this problem. The only difference is that you only need to output the minimum total cost of operations in t…

Docker 部署 Jaeger

Jaeger 的主要作用如下&#xff1a; 分布式追踪 Jaeger 是一个开源的分布式追踪系统&#xff0c;用于监控和排查微服务架构中的复杂问题。它可以跟踪请求在不同服务之间的传播路径&#xff0c;帮助开发者理解系统中各个组件之间的调用关系。 性能分析 通过收集和分析请求的执行…

基于Gin和GORM的在线判题系统后端

项目地址&#xff1a;基于Gin和GORM的在线判题系统后端 一、开发环境与API测试工具 开发环境 Go1.23,VSCode,Gin框架&#xff0c;GORM框架 gin-swagger swagger是一个用于描述和文档化 RESTful API 的开源工具&#xff0c;它可以帮助开发者生成交互式文档&#xff0c;并且…

【C++】—— 模板进阶

【C】—— 模板进阶 1 非类型模板参数1.1 什么是非类型模板参数1.2 非类型模板参数对比宏的优势1.3 array 简单了解 2 模板的特化2.1 引子2.2 函数模板特化2.3 函数模板特化的坑2.4 类模板的特化2.4.1 全特化2.4.2 偏特化&#xff08;半特化&#xff09;2.4.3 选择2.4.4 偏特化…

Conda 安装与使用指南

Conda 是一个开源的软件包管理和环境管理系统&#xff0c;主要解决一个系统上同时要使用python2&#xff0c;python3等等多个python环境的切换问题&#xff0c;支持多种编程语言&#xff08;如 Python、R 等&#xff09;&#xff0c;可以在 Windows、macOS 和 Linux 上运行。它…