YOLO11预测返回结果plot方法解析

概述

YOLO11 predict()返回Results对象,检测任务的主要数据包括原始图像、原图像尺寸、边界框、类别及其置信度、xywh(中心坐标、宽度和高度)及其归一化数据、xyxy(左上、右下坐标)及其归一化数据。其他任务的推理返回结果包含其特定的数据。

Results对象的属性

Results 对象的属性:

名称类型描述
orig_imgnumpy.ndarray原始图像numpy array.
orig_shapetuple原始图像尺寸 (height, width) .
boxesBoxes, optionalBoxes 对象,包含所有检测到的边界框.
masksMasks, optionalMasks 对象,包含所有检测到的 masks.
probsProbs, optionalProbs 对象,包含所有分类任务的类别概率.
keypointsKeypoints, optionalKeypoints 对象,包含包含每个对象的检测关键点.
obbOBB, optionalOBB对象,包含定向边界框.
speeddict每幅图像的预处理、推理和后处理速度(ms).
namesdict类索引映射到类名称.
pathstr图像文件的路径.
save_dirstr, optional保持结果的目录.

Results对象的方法

Results对于有以下方法:

方法返回类型说明
update()None用新的检测数据(方框、遮罩、问题、Obb、关键点)更新结果对象。
cpu()Results返回将所有张量移至CPU 内存的 Results 对象副本。
numpy()Results返回将所有张量转换为 numpy 数组的 Results 对象副本。
cuda()Results返回将所有张量移至GPU 内存的 Results 对象副本。
to()Results返回将张量移动到指定设备和 dtype 的 Results 对象副本。
new()Results创建一个具有相同图像、路径、名称和速度属性的新结果对象。
plot()np.ndarray在输入的 RGB 图像上绘制检测结果,并返回带标注的图像。
show()None显示带有推理结果标注的图像。
save()str将带标注推理结果的图像保存到文件并返回文件名。
verbose()str返回每个任务的日志字符串,详细说明检测和分类结果。
save_txt()str将检测结果保存到文本文件,并返回保存文件的路径。
save_crop()None将裁剪后的检测图像保存到指定目录。
summary()List[Dict]将推理结果转换为可选归一化的摘要字典。
to_df()DataFrame将检测结果转换为 Pandas DataFrame。
to_csv()str将检测结果转换为 CSV 格式。
to_xml()str将检测结果转换为 XML 格式。
to_html()str将检测结果转换为 HTML 格式。
to_json()str将检测结果转换为 JSON 格式。
to_sql()None将检测结果转换为 SQL 兼容格式并保存到数据库。

Plot()方法

Plot()方法将检测到的对象(如边界框、遮罩、关键点和概率)叠加到原始图像上,从而实现预测的可视化。该方法以 NumPy 数组形式返回注释图像,便于显示或保存。

调用方法:

from PIL import Image

from ultralytics import YOLO

# Load a pretrained YOLO11n model
model = YOLO("yolo11n.pt")

# Run inference on 'bus.jpg'
results = model(["https://ultralytics.com/images/bus.jpg", "https://ultralytics.com/images/zidane.jpg"])  # results list

# Visualize the results
for i, r in enumerate(results):
    # Plot results image
    im_bgr = r.plot()  # BGR-order numpy array
    im_rgb = Image.fromarray(im_bgr[..., ::-1])  # BGR to RGB-order PIL image

    # Show results to screen (in supported environments)
    r.show()

    # Save results to disk
    r.save(filename=f"results{i}.jpg")

源码分析

我们来看ultralytics的源代码ultralytics\engine\results.py,

def plot(
        self,
        conf=True,
        line_width=None,
        font_size=None,
        font="Arial.ttf",
        pil=False,
        img=None,
        im_gpu=None,
        kpt_radius=5,
        kpt_line=True,
        labels=True,
        boxes=True,
        masks=True,
        probs=True,
        show=False,
        save=False,
        filename=None,
        color_mode="class",
        txt_color=(255, 255, 255),
    ):

参数:

NameTypeDescriptionDefault
confbool是否叠加置信度True
line_width`floatNone`框的线宽。如果为None,则根据图像大小自动适应。
font_size`floatNone`文本大小. 如果为None, 则根据图像大小自动适应.
fontstr字体。可以使用系统已安装的字体。'Arial.ttf'
pilbool是否以PIL Image返回.False
img`ndarrayNone`用于绘图的图像。如果为None,则使用原始图像
im_gpu`TensorNone`GPU-加速图像,用于更快地绘制蒙版。
kpt_radiusint绘制关键点的半径5
kpt_linebool是否用线条连接关键点。True
labelsbool是否绘制标签True
boxesbool是否绘制边界框.True
masksbool是否叠加蒙版True
probsbool是否绘制分类概率True
showbool是否显示带标注的图像False
savebool是否保存带标注的图像False
filename`strNone`保存图像的文件名称
color_modebool指定颜色模式: ‘instance’ 或 ‘class’. 缺省 ‘class’.'class'
txt_colortuple[int, int, int]为分类任务指定叠加的文字颜色(255, 255, 255)

继续看源码:

assert color_mode in {"instance", "class"}, f"Expected color_mode='instance' or 'class', not {color_mode}."
		#如果img为None,则使用原始图像,并且确认原始图像属于 PyTorch 的张量(Tensor)类型。把批次中的第一张图像从 PyTorch 张量格式转换为 NumPy 数组格式,并且完成通道顺序调整和数值范围缩放。
        if img is None and isinstance(self.orig_img, torch.Tensor):
            img = (self.orig_img[0].detach().permute(1, 2, 0).contiguous() * 255).to(torch.uint8).cpu().numpy()

        names = self.names
        is_obb = self.obb is not None
        pred_boxes, show_boxes = self.obb if is_obb else self.boxes, boxes
        pred_masks, show_masks = self.masks, masks
        pred_probs, show_probs = self.probs, probs
        #实例化Annotator类
        annotator = Annotator(
            deepcopy(self.orig_img if img is None else img),
            line_width,
            font_size,
            font,
            pil or (pred_probs is not None and show_probs),  # Classify tasks default to pil=True
            example=names,
        )

        # 绘制分割结果
        if pred_masks and show_masks:
            if im_gpu is None:
                img = LetterBox(pred_masks.shape[1:])(image=annotator.result())
                #将输入的图像(以 NumPy 数组形式存在)转换为 GPU 上的 PyTorch 张量,同时进行通道调整、归一化等操作
                im_gpu = (
                    torch.as_tensor(img, dtype=torch.float16, device=pred_masks.data.device)
                    .permute(2, 0, 1)
                    .flip(0)
                    .contiguous()
                    / 255
                )
            idx = (
                pred_boxes.id
                if pred_boxes.id is not None and color_mode == "instance"
                else pred_boxes.cls
                if pred_boxes and color_mode == "class"
                else reversed(range(len(pred_masks)))
            )
            annotator.masks(pred_masks.data, colors=[colors(x, True) for x in idx], im_gpu=im_gpu)

        # 绘制检测(detect)结果
        if pred_boxes is not None and show_boxes:
            for i, d in enumerate(reversed(pred_boxes)):
            	#从预测框对象中提取分类、置信度和 跟踪ID 信息,并进行类型转换与空值处理
                c, d_conf, id = int(d.cls), float(d.conf) if conf else None, None if d.id is None else int(d.id.item())
                name = ("" if id is None else f"id:{id} ") + names[c]
                label = (f"{name} {d_conf:.2f}" if conf else name) if labels else None
                #如果是OBB则使用四个顶点坐标,普通方框使用左上右下顶点坐标
                box = d.xyxyxyxy.reshape(-1, 4, 2).squeeze() if is_obb else d.xyxy.squeeze()
                annotator.box_label(
                    box,
                    label,
                    color=colors(  #依据颜色模式为检测或跟踪结果选择颜色,如果为class,则使用类别索引对应的颜色(系统预先定义),否则使用特定实例的颜色
                        c
                        if color_mode == "class"
                        else id
                        if id is not None
                        else i
                        if color_mode == "instance"
                        else None,
                        True,
                    ),
                    rotated=is_obb,
                )

        # 绘制分类结果
        if pred_probs is not None and show_probs:
            text = ",\n".join(f"{names[j] if names else j} {pred_probs.data[j]:.2f}" for j in pred_probs.top5)
            x = round(self.orig_shape[0] * 0.03)
            #在图像上叠加文字
            annotator.text([x, x], text, txt_color=txt_color)

        # 绘制姿态结果
        if self.keypoints is not None:
            for i, k in enumerate(reversed(self.keypoints.data)):
                annotator.kpts(
                    k,
                    self.orig_shape,
                    radius=kpt_radius,
                    kpt_line=kpt_line,
                    kpt_color=colors(i, True) if color_mode == "instance" else None,
                )

        # Show results
        if show:
            annotator.show(self.path)

        # Save results
        if save:
            annotator.save(filename)

        return annotator.im if pil else annotator.result()

应用实例

在停车场检测应用中,可以自行定义图像叠加的内容和样式。

 results = model.predict(source=image_path, save_txt=True, save=False, exist_ok=True, imgsz=1280, conf=conf, iou=0.45,show_conf=False,show_labels=False,)
   
    # 初始化类别计数器(支持多图批量统计)
    class_counter = defaultdict(int)
    
    # 遍历每张图像的预测结果
    for result in results:
    # 跳过无检测结果的图像
        if not result.boxes:
            continue
        
        # 获取原始类别索引(Tensor -> numpy)
        cls_indices = result.boxes.cls.cpu().numpy().astype(int)
        
        # 过滤低置信度(可选,默认使用model.predict的conf参数)
        conf_mask = result.boxes.conf.cpu().numpy() > conf
        cls_indices = cls_indices[conf_mask]
        
        # 批量转换索引为类别名
        class_names = [model.names[idx] for idx in cls_indices]
        
        # 累加计数
        for name in class_names:
            class_counter[name] += 1
    
    res_str=''
    # 打印统计结果(按数量降序排列)
    #print("类别数量统计:")
    for cls_name, count in sorted(class_counter.items(), key=lambda x: -x[1]):
        #print(f"  {cls_name}: {count}个")
        res_str+=cls_name+' '+str(count)+' '
    
    #返回第一个图像的图像数组
    im_array = results[0].plot(conf=False,
                                    labels= False,
                                    txt_color=(255, 255, 255),
                                    )
    im = Image.fromarray(im_array[..., ::-1])
    annotator = Annotator(
            im,
            line_width=2,
            #font_size=20,
            font= 'AlibabaPuHuiTi-3-65-Medium.ttf',
            example='names',
        )
    annotator.text([10, 10], f'检测结果:{res_str}', txt_color=(255,0,0), box_style=True)
       
    #保存叠加后的图片
    if  not os.path.exists('runs/detect/predict'):
        os.makedirs('runs/detect/predict')
    new_img_path = f'runs/detect/predict/{os.path.basename(image_path)}'

    im.save(new_img_path)
    

在这段代码中,不使用model.predict(),使用plot()方法把边界框绘制到图像上,并且调用Annotator.text()叠加结果到图像的左上角。
在这里插入图片描述

### 如何使用YOLOv11进行视频处理 对于想要利用YOLOv11来执行视频中的对象检测任务,通常涉及几个主要环节。首先是环境搭建,在此过程中需安装必要的依赖库以及下载预训练模型权重文件;其次是编写代码逻辑读取每一帧图像并调用YOLO算法完成预测工作;最后则是展示或保存含有标注框的结果。 #### 安装依赖项与配置开发环境 为了能够在本地环境中顺利运行YOLOv11项目,建议先确认已安装Python解释器(推荐版本3.x),接着通过pip工具获取所需软件包: ```bash pip install numpy opencv-python torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cpu ``` 上述命令会自动拉取PyTorch框架及其配套组件,这对于加载神经网络结构至关重要[^2]。 #### 下载YOLOv11模型及相关资源 访问官方GitHub仓库或其他可信源码托管平台找到对应于YOLOv11项目的页面链接,按照说明文档指引克隆整个工程至个人电脑上,并从中提取出`.weights`格式的参数文件作为后续推理的基础。如果存在转换脚本,则可进一步将其转化为更易于使用的`.pt`形式以便集成到Python程序内。 #### 编写视频流解析及物体识别部分 下面给出一段简单的Python示范代码用于捕捉来自摄像头的画面序列并对其中的目标实施分类标记操作: ```python import cv2 from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords from utils.datasets import letterbox def detect_objects(frame, model): img_size = 640 stride = int(model.stride.max()) # 图片预处理 img = letterbox(frame, new_shape=img_size)[0] img = img[:, :, ::-1].transpose(2, 0, 1).copy() img = np.ascontiguousarray(img) img = torch.from_numpy(img).to('cpu') img = img.float() / 255.0 if img.ndimension() == 3: img = img.unsqueeze(0) pred = model(img)[0] det = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45)[0] if len(det): det[:, :4] = scale_coords(img.shape[2:], det[:, :4], frame.shape).round() for *xyxy, conf, cls in reversed(det): label = f'{names[int(cls)]} {conf:.2f}' plot_one_box(xyxy, frame, label=label, color=(0, 255, 0), line_thickness=3) if __name__ == '__main__': weights_path = 'yolov11.pt' source_video = "input.mp4" device = 'cuda' if torch.cuda.is_available() else 'cpu' model = attempt_load(weights_path, map_location=device) # 加载模型 names = model.module.names if hasattr(model, 'module') else model.names # 获取类别名称列表 cap = cv2.VideoCapture(source_video) while True: ret, frame = cap.read() if not ret: break detect_objects(frame, model) cv2.imshow('Video', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() ``` 这段代码实现了从指定路径加载预先训练好的YOLOv11模型实例化过程,并定义了一个辅助函数负责接收单张图片数据进而返回带有边界矩形坐标的输出结果集。主循环体持续抓拍新画面直至遇到终止条件为止,期间每轮迭代都会调用一次该方法更新当前显示窗口内的视觉效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值