尧图精选

best.pt推理实战:YOLO统一封装图片/视频/摄像头目标检测代码

🕒 发布时间:2026/9/5 22:26:58 📁 来源:尧图网络
如果只给你一个训练好的best.pt要求在图片、本地视频和摄像头上都能跑目标检测你的代码会怎么写很多人训练完只看过训练日志真正落地时反而在“推理脚本”这里卡住调用 API 不熟悉、视频抽帧太慢、摄像头流又不知道怎么接。这次整理一套统一的 YOLO 检测工程把 YOLO26 / YOLO11 / YOLOv8 系列权重用同一个思路封装成图片检测、视频检测、摄像头检测核心模型文件就是best.pt。为什么值得看一眼这套东西它直接解决三个问题一是你不需要为每个数据来源维护一套独立代码二是模型加载一次后面可以反复推理三是部署范围很宽有显卡就上 GPU没有显卡也能先用 CPU 把流程跑通。下面是能直接复用的检测器封装和不同场景的调用方式。先说明一个背景无论你的best.pt是 YOLOv8、YOLO11 还是 YOLO26 系列训练出来的在 Ultralytics 生态里推理侧的用法基本一致。加载方式是YOLO(weights/best.pt)预测方式是model(frame)或model.predict(source...)。真正的坑往往不在这层代码而在于ultralytics包版本和训练权重版本是否匹配。整个工程不大但麻雀虽小五脏俱全有检测器类封装、有图片批量推理、有逐帧视频处理、有摄像头实时显示帧率。后面还补充了接口化改造思路和常用字段方便你接自己的业务流程。1. 核心能力速览能力项说明项目类型YOLO 目标检测推理工程核心功能调用训练好的best.pt完成图片、批量图片、本地视频、摄像头实时目标检测兼容模型版本YOLOv8、YOLO11、YOLO26 等 Ultralytics 系列权重需保证训练与推理包版本匹配模型文件常用weights/best.pt输入数据单张图片、图片文件夹、视频文件、USB 摄像头、RTSP 流输出数据带检测框的结果图片、结果视频、终端日志运行方式Python 脚本运行是否支持 CPU支持CPU 推理相对慢适合验证是否支持 GPU支持 NVIDIA 显卡 CUDA也支持无 NVIDIA 环境下的 CPU 兜底是否支持批量支持图片文件夹批量、视频列表逐一处理是否支持 API可基于检测器类二次封装提供 HTTP 接口显存占用取决于模型参数量、输入尺寸和批大小没有统一值需按实际模型测试适合读者训练完 YOLO 想快速搭建演示项目的人、需要在本地集成检测能力的工程师这里不给一个“某某显卡占用 6G”式结论因为不同版本模型、不同输入尺寸、不同 batch 差别很大。更稳妥的做法是拿到工程后自己跑一次小图再用任务管理器或nvidia-smi观察。2. 适用场景与使用边界2.1 这套检测工程适合哪些场景训练完目标检测模型想在少量测试图片上快速看效果。需要批量处理数据集里的图片把所有包含目标的框画出来。有本地视频文件希望输出一份“检测后仍可播放”的结果视频。在手边有 USB 摄像头或 RTSP 网络摄像头想做实时画面预览。作为 API 服务后端把模型推理能力开放给业务侧调用。2.2 不适合哪些场景高并发线上服务直接用一个 Python 进程同时处理几十路视频流很可能出现排队、掉帧、内存上涨。这个工程定位是单机推理演示和中小规模验证。需要复杂后处理的任务比如一个画面里要先跟踪再统计进出人数那还需要接入 BYTETrack / DeepSORT 之类的跟踪模块。对延迟要求极高的边缘设备需要在 TensorRT、OpenVINO、RKNN 等推理引擎上做模型转换和算子优化单靠ultralytics默认推理不一定满足要求。2.3 安全与授权边界这篇文章会涉及图片检测、视频检测、摄像头检测属于通用目标检测能力。使用时有几类风险要提前规避图片和视频素材必须有合法来源不能随意拿未经授权的监控录像或他人人脸数据进行测试。摄像头画面如果包含可识别人员部署前要完成隐私告知和授权确认。不要把这套能力用于未授权的身份识别、轨迹追踪、账号隐私收集等违规用途。后续如果要商用需要再次核验训练的best.pt数据来源是否合规权重文件是否允许对外发布。3. 环境准备与前置条件3.1 版本对应关系best.pt的训练方式会影响推理环境选择。最佳实践是训练使用的模型建议推理环境YOLOv8ultralytics8.x 早期版本YOLO11ultralytics8.3.x 之后版本YOLO26 系列优先使用与该权重配套发布的新版ultralytics如果推理时出现模型结构定义错误、KeyError、Unable to load这类报错大概率是包版本和训练模型不匹配优先回退到训练时的环境。3.2 Python 与 CUDA工程以 Python 3.10 为基准即可。不强制要求集显或 N 卡。先确认几件事是否安装 Python 3.8 以上。是否需要 GPU 加速NVIDIA 显卡优先确认驱动是否正常。是否已经有可用环境建议用 conda 或 venv 单独创建避免和项目环境污染。检查 NVIDIA 显卡状态nvidia-smi看到显卡型号和 Driver 版本就说明驱动层面没问题。如果想进一步确认 PyTorch 是否用上 CUDA可以在 Python 里执行import torch print(torch.__version__) print(torch.cuda.is_available())如果输出False说明当前 PyTorch 不是 CUDA 版本或者 CUDA 调用失败这时候会退回 CPU 推理。3.3 关于 AMD 显卡和 YOLO经常有人问AMD RX 580 能跑 YOLO 吗需不需要装 CUDA先说结论如果你只想让推理流程跑起来完全可以用 CPU 模式跑 YOLO不装 CUDA 也可以。AMD RX 580 这类老显卡本身不支持 NVIDIA CUDA强行走 ROCm 加速也可能遇到支持和性能问题。更实际的做法是先把环境配好用 CPU 跑通前面的图片和视频检测再单独考虑 GPU 加速方案。计算量很大的批量任务建议放到支持 CUDA 的 NVIDIA 设备或云 GPU 实例上。4. 统一的 best.pt 检测器封装4.1 推荐目录结构先建一个干净的工程目录yolo-detect/ ├── detector.py ├── run_image.py ├── run_video.py ├── run_camera.py ├── requirements.txt ├── weights/ │ └── best.pt ├── data/ │ ├── test.jpg │ └── test.mp4 └── outputs/weights/best.pt放训练好的权重data放测试素材outputs放结果文件。目录纯英文路径避免某些环境下因为中文字符导致模型加载或视频编码报错。4.2 检测器封装代码这部分是核心。把图片、单帧、视频、摄像头统一封装到一个类里后面所有调用都走同一个模型实例避免每次推理都重复加载权重# detector.py import cv2 from ultralytics import YOLO class YoloDetector: def __init__(self, weightsweights/best.pt, conf0.25, imgsz640, deviceNone): self.model YOLO(weights) self.conf conf self.imgsz imgsz self.device device def detect_frame(self, frame): results self.model.predict( sourceframe, confself.conf, imgszself.imgsz, deviceself.device, verboseFalse ) annotated results[0].plot() return annotated def detect_image(self, image_path, save_pathNone): frame cv2.imread(image_path) if frame is None: raise FileNotFoundError(f图片读取失败: {image_path}) annotated self.detect_frame(frame) if save_path: cv2.imwrite(save_path, annotated) return annotated def detect_video(self, video_path, output_path): cap cv2.VideoCapture(video_path) if not cap.isOpened(): raise IOError(f视频读取失败: {video_path}) fps cap.get(cv2.CAP_PROP_FPS) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fourcc cv2.VideoWriter_fourcc(*mp4v) writer cv2.VideoWriter(output_path, fourcc, fps, (width, height)) while True: ret, frame cap.read() if not ret: break annotated self.detect_frame(frame) writer.write(annotated) cap.release() writer.release() print(f视频检测完成结果保存到: {output_path}) def detect_camera(self, camera_id0): cap cv2.VideoCapture(camera_id) if not cap.isOpened(): raise IOError(f摄像头无法打开: {camera_id}) while cap.isOpened(): ret, frame cap.read() if not ret: break annotated self.detect_frame(frame) cv2.imshow(YOLO Detector, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()使用要点detect_frame内部只接收一帧图像所有上层调用都基于这一帧所以模型推理逻辑统一。imgsz640是常见推理尺寸。如果显存不足或 CPU 较慢可以降到416。这里的deviceNone表示交给 Ultralytics 自动选择设备。有 CUDA 就优先 CUDA没有就 CPU。results[0].plot()返回的是带检测框的 BGR 图像可以直接cv2.imshow或cv2.imwrite。5. 图片检测测试调用 best.pt 验证单张图片5.1 运行脚本新建run_image.py# run_image.py import cv2 from detector import YoloDetector if __name__ __main__: detector YoloDetector(weightsweights/best.pt, conf0.25) image_path data/test.jpg annotated detector.detect_image(image_path) cv2.imwrite(outputs/test_result.jpg, annotated) print(图片检测结果已保存到 outputs/test_result.jpg)执行python run_image.py如果best.pt本身是在自定义数据集上训练的检测结果会显示训练时设定的类别名。比如person、car或你自己的业务类别。如果显示的标签是数字而不是文字通常是模型文件里没有附带类别名需要继续查训练时data.yaml的类名配置。5.2 批量图片检测检测一张图往往不是最终需求生产场景经常要跑整个文件夹。批量处理时仍然复用同一个YoloDetector# run_image_batch.py import glob import os import cv2 from detector import YoloDetector if __name__ __main__: detector YoloDetector(weightsweights/best.pt, conf0.25) input_dir data/images output_dir outputs/images os.makedirs(output_dir, exist_okTrue) image_paths glob.glob(os.path.join(input_dir, *.jpg)) image_paths glob.glob(os.path.join(input_dir, *.png)) for idx, image_path in enumerate(image_paths): save_path os.path.join(output_dir, fresult_{idx}.jpg) detector.detect_image(image_path, save_pathsave_path) print(f处理完成: {image_path} - {save_path})判断成功的标准很简单每张图都有对应输出文件画面中目标被画框终端没有抛异常。如果发现某张图没有框需要先排查置信度阈值是否设置过高。5.3 测试维度建议低置信度目标测试把conf调低到0.1看漏检是否减少同时观察误检是否增加。不同分辨率测试分别用 416、640、1280 尺寸跑一次对比结果框的位置稳定性。批量稳定性测试一次处理 100 张以上图片检查程序有没有内存持续增长或中途崩溃。6. 视频检测测试用 best.pt 处理本地视频6.1 为什么要手动逐帧处理Ultralytics 本身支持直接传视频路径model.predict(sourcedata/test.mp4, saveTrue)但很多工程场景需要手动逐帧处理的理由是要在检测前对帧做自定义预处理。要控制实际送入模型的帧率比如每秒只检测几帧。要把检测结果和业务数据叠加比如在画面里写时间戳、统计数量。要在检测后接跟踪算法不手动拿到帧就没法做跟踪状态维护。所以上面detector.py里的detect_video是一份比较典型的逐帧处理实现。下面给一个更直观的使用入口# run_video.py import os from detector import YoloDetector if __name__ __main__: detector YoloDetector(weightsweights/best.pt, conf0.25, imgsz640) video_path data/test.mp4 output_path outputs/test_result.mp4 os.makedirs(outputs, exist_okTrue) detector.detect_video(video_path, output_path)执行python run_video.py启动后可以看到终端开始逐帧读取视频并处理。视频越长耗时越长。整个处理过程不会实时播放画面属于“离线条带式处理”。6.2 检测结果验证判断视频检测是否成功的标准输出文件存在且能被常见播放器正常打开。视频尺寸和输入视频一致。帧率不要求完全等于原始视频编码后帧率变化只要在可接受范围即可。检测框在运动目标上能稳定出现不出现大面积目标漏检。如果视频中间存在花屏、绿屏、编码失败优先检查cv2.VideoWriter_fourcc的编码器和输出文件后缀是否匹配。mp4v对应.mp4如果改成.avi建议把编码改成XVID。6.3 视频处理性能观察逐帧处理时性能瓶颈通常在两个位置原始视频解码。模型推理本身。如果 CPU 推理太慢可以使用抽帧策略不是每一帧都送模型而是每隔 3 帧检测一次。处理方式是在detect_video的循环里加一个帧计数器frame_idx 0 while True: ret, frame cap.read() if not ret: break if frame_idx % 3 0: annotated self.detect_frame(frame) last_annotated annotated else: annotated last_annotated writer.write(annotated) frame_idx 1这样会牺牲一点目标连续性但能明显提升处理速度。7. 摄像头检测测试调用 best.pt 做实时推理7.1 USB 摄像头检测摄像头是目标检测最常见的实时场景。新建run_camera.py# run_camera.py from detector import YoloDetector if __name__ __main__: detector YoloDetector(weightsweights/best.pt, conf0.25, imgsz640) detector.detect_camera(camera_id0)执行python run_camera.py在弹出来的窗口中按q退出。如果摄像头编号不是0需要改成1、2或其他编号。有的笔记本自带摄像头占用编号 0外接 USB 摄像头反而在 1可以先写个小脚本列出可用编号import cv2 for index in range(3): cap cv2.VideoCapture(index) if cap.isOpened(): print(fcamera {index} 可用) cap.release()打开后常见现象画面卡顿严重说明 CPU 推理帧率不足。检测框位置抖动正常现象因为没有使用跟踪器平滑。画面上人物动作有延迟说明每帧处理时间较长可降低imgsz或调成隔帧检测。7.2 RTSP 摄像头检测很多工程场景不是 USB 摄像头而是网络摄像头 RTSP 流。这时候把cv2.VideoCapture的入参改成 RTSP 地址即可# run_rtsp.py from detector import YoloDetector if __name__ __main__: detector YoloDetector(weightsweights/best.pt, conf0.25, imgsz640) rtsp_url rtsp://user:password192.168.1.64:554/stream1 detector.detect_camera(camera_idrtsp_url)这里不写死某一个厂商地址实际使用时替换成自己的摄像头 RTSP 地址。网络摄像头解码可能不稳定画面卡住时先确认网络带宽和摄像头码流设置一般优先切换到子码流测试。7.3 帧率与实时性摄像头实时检测的核心指标是 FPS。可以在检测循环里加入简单计时import time start time.time() frame_count 0 # 在 detect_camera 的循环里 frame_start time.time() annotated self.detect_frame(frame) frame_cost time.time() - frame_start frame_count 1 if frame_count % 10 0: avg_fps frame_count / (time.time() - start) print(f当前帧处理耗时: {frame_cost * 1000:.1f} ms, 平均 FPS: {avg_fps:.2f})这样你能立刻看出算力瓶颈。如果 FPS 只有 3 到 5说明每帧需要 200 到 300 毫秒推理实时互动体验会很差。常见优化方案有imgsz从 640 降到 416。使用更小的模型例如yolov8n、yolo11n。只在目标出现区域做局部推理但这会增加控制复杂度。更新到支持 CUDA 的环境。8. 接口 API 与批量任务8.1 用 FastAPI 包一层 HTTP 接口单机脚本已经满足演示需求但工程集成经常需要一个 HTTP 接口。思路是先加载YoloDetector单例再对外提供图片检测接口。安装依赖pip install fastapi uvicorn写服务端# api_server.py import cv2 import numpy as np from fastapi import FastAPI, UploadFile, File, Response from detector import YoloDetector app FastAPI() detector YoloDetector(weightsweights/best.pt, conf0.25) app.post(/detect/image) async def detect_image(file: UploadFile File(...)): data await file.read() image cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR) if image is None: return {code: 1, message: 图片解码失败} annotated detector.detect_frame(image) ok, jpg cv2.imencode(.jpg, annotated) if not ok: return {code: 2, message: 结果编码失败} return Response(contentjpg.tobytes(), media_typeimage/jpeg)启动uvicorn api_server:app --host 127.0.0.1 --port 8000调用端可以直接用 Python 请求import requests url http://127.0.0.1:8000/detect/image files {file: (test.jpg, open(data/test.jpg, rb), image/jpeg)} response requests.post(url, filesfiles, timeout30) if response.status_code 200: with open(outputs/api_result.jpg, wb) as f: f.write(response.content) print(接口调用成功) else: print(response.text)一定要把服务绑定在127.0.0.1不要为了方便直接绑到0.0.0.0对公网开放。如果需要被内网其他机器调用再通过防火墙规则限制可访问来源。8.2 批量任务目录化处理批量任务不一定都要上消息队列。小规模场景用一个输入目录加输出目录就够了。每次跑批量任务时生成独立时间戳子目录方便结果回溯# run_batch.py import glob import os import time from detector import YoloDetector if __name__ __main__: detector YoloDetector(weightsweights/best.pt, conf0.25) batch_name time.strftime(%Y%m%d_%H%M%S) input_dir data/batch_input output_dir foutputs/{batch_name} os.makedirs(output_dir, exist_okTrue) fail_log [] for image_path in glob.glob(os.path.join(input_dir, *.*)): ext os.path.splitext(image_path)[1].lower() if ext not in [.jpg, .jpeg, .png]: continue try: save_name os.path.basename(image_path) detector.detect_image(image_path, save_pathos.path.join(output_dir, save_name)) except Exception as exc: fail_log.append((image_path, str(exc))) print(f完成失败数量: {len(fail_log)}) for path, message in fail_log: print(f失败: {path} - {message})这种小批量工具的好处是自带失败记录。当数据量很大时可以再加一个断点续跑逻辑判断输出文件是否已存在存在就跳过。9. 资源占用与性能观察9.1 资源占用观察方法这部分不写死显存占用值。显存占用的上下限和模型类别、输入尺寸、batch size、推理方式都有关系最可靠的方法是直接观察Windows 用任务管理器 - GPU 查看专用 GPU 内存。Linux 执行nvidia-smi -l 1每 1 秒刷新一次。用 Python 在推理前后统计推理耗时。如果是 8G 显存以下的老显卡建议优先从yolov8n、yolo11n这类轻量级模型开始测。目标是将推理耗时控制在满足场景需求的范围内而不是把模型参数全部塞满显存。9.2 CPU 推理 vs GPU 推理CPU 推理可以使用但 YOLO 本身就是计算密集型模型。CPU 上跑一张 640x640 的图片可能需要几百毫秒到数秒不等视频和摄像头实时场景会明显卡顿。GPU 推理通常可以把单帧推理时间压缩到几十毫秒但实际帧率还受视频解码、图像缩放、后处理影响。因此建议顺序是CPU 跑通功能确认输入输出逻辑正确。GPU 环境验证加速效果观察显存和推理耗时。如果 GPU 也不能满足实时性降低输入尺寸或换轻量模型。9.3 降低资源占用的常见手段降低imgsz。调低视频帧率检测前cap.grab()跳过部分帧。控制batch摄像头场景一定是batch1。关闭日志verboseFalse能减少终端 I/O 开销。模型加载只做一次不要在循环里YOLO()重复加载。10. 常见问题与排查方法问题现象可能原因排查方式解决方案加载best.pt报错或 KeyError训练和推理的ultralytics包版本不匹配查看训练环境依赖版本对比当前pip show ultralytics调整当前包版本到训练时版本终端提示找不到best.pt路径写错或文件不在指定目录检查weights/目录下文件改成绝对路径或确认工程目录检测结果没有标签名best.pt中缺少类别名信息打开权重文件检查names字段用训练时的模型类和data.yaml重新导出摄像头打不开摄像头编号错误或已被占用遍历 0 到 3 的摄像头编号修改camera_id或释放占用摄像头的程序视频输出文件无法播放编码器与文件后缀不匹配确认VideoWriter_fourcc和输出后缀.mp4用mp4v.avi用XVID推理很慢 FPS 低CPU 推理、输入尺寸过大、模型过大打印单帧耗时确认设备换 GPU、缩小imgsz或换轻量模型显存不足输入尺寸太大、batch 太大、多进程加载观察nvidia-smi降低分辨率使用单 batch或用更小模型画面检测框乱跳没有跟踪算法或置信度阈值过低观察错误框区域提高conf或接入跟踪器OpenCV 报编码错误缺少对应视频编码依赖查看报错栈换编码方式或安装对应依赖API 调用超时服务未启动、端口占用、推理耗时过长先本地跑图片脚本重启服务检查防火墙和显存并不是所有问题都来自模型本身。项目结构、路径、环境版本、视频编码导致的报错占了相当大比例。遇到报错先读最后三行异常堆栈往往比乱改参数更高效。11. 最佳实践与使用建议第一第一次运行不要直接上大视频。先用一张测试图片验证best.pt加载正常再用 10 到 30 秒的短视频验证视频处理流程最后再上摄像头或 RTSP。这样能把问题隔离开。第二保留一套最小可运行配置。很多团队训练完模型就只留下best.pt结果几个月后想推理时发现不知道当时用什么版本训练、类别名是什么。建议把下面的信息一起归档训练时使用的ultralytics版本。训练时使用的data.yaml。最佳权重best.pt。一份简单的 README写明类别列表。第三目录管理要清晰。weights、data、outputs分开存放输出结果按时间戳建子目录。否则批量跑几次后所有结果图都堆在同一个目录覆盖或误删的概率很高。第四批量任务必须加日志。最简单的是在任务结束后打印失败数量和失败文件列表。更正式一点的做法是在每条处理记录里写日志文件包含时间、输入路径、输出路径、是否成功、耗时、异常信息。第五服务化时限制访问范围。模型推理服务不能默认暴露到外网。内网调用也要考虑鉴权比如加一个简单的 token 字段防止被其他人刷接口。第六涉及人脸、车牌、个人隐私数据时先确认是否有合法处理依据。模型能力本身是中性的但数据来源、部署场景必须合规。第七如果要做边缘部署比如 K230、Jetson 这类设备可以把本工程的 Python 脚本当成“功能验证参考”之后再把权重转换成目标平台需要的格式。不同平台对算子支持不同转换后尽量用真实业务数据重新测一遍精度。第八关于数据集相关工作常见流程是先把原始标注转换成 YOLO 格式再训练再得到best.pt。比如 VisDrone 这类公开数据集的转换本质是把标注框归一化并生成每张图片对应的 txt 文件。这个环节推荐在训练前规范化处理避免训练集和验证集格式不一致。12. 总结与下一步这套工程把 YOLO 三件事讲清楚了加载best.pt、三种输入数据统一处理、不同场景下如何调试。它不是复杂到让你看不懂的框架而是一套能直接跑的代码。YOLOv8、YOLO11、YOLO26 系列在推理 API 上的一致性让这套代码可以长期复用。起步时建议先做两件事。第一用一张自己训练集之外的图片跑通图片检测确认类别、置信度、检测框位置都正常。这一步能排除模型文件损坏、包版本不匹配等潜在问题。第二打开本地摄像头做一次实时检测。摄像头场景能最直观地暴露性能问题。如果 FPS 上不去马上调整imgsz或换轻量模型比到部署阶段再优化成本低得多。最容易踩的坑不是代码而是环境版本和模型来源不一致产生的“玄学报错”。所以拿到best.pt后一定先确认它是哪一版 YOLO 训练出来的推理环境尽量保持一致。后续扩展方向也很明确视频场景接入目标跟踪实现跨帧稳定图片场景接入批量任务队列做并发处理摄像头场景可以加区域入侵、计数、告警逻辑。需要把这套检测封装成服务时优先做输入输出规范化再逐步加鉴权、日志、监控。建议收藏备用等真正开始写推理代码时能少走不少弯路。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →