基于OpenCV+Qt+YOLO的实时目标检测系统构建与实现
2026/8/31 16:20:31 网站建设 项目流程

简介:本资源是一个基于OpenCV、Qt与YOLO的轻量级实时人体检测系统实现,面向计算机视觉初学者与嵌入式/桌面端应用开发者,解决视频流或静态图像中快速定位并框选人体的目标检测需求,适用于安防监控、人流统计等入门级项目实践。压缩包共26个文件,含5个核心CPP源码、4个H头文件支撑模块化逻辑,1个UI界面设计文件与1个QRC资源文件构成Qt图形界面基础,另有6张PNG、3张JPG测试图及2份PDF说明文档(含README与案例介绍),整体大小为4.96MB。已有84人学习下载。读者可直接编译运行,获得完整可执行流程:从Qt界面启动、OpenCV调用摄像头采集、YOLOv5s模型推理、边界框绘制到结果实时渲染,代码结构清晰,CMakeLists.txt与JSON配置文件完备,便于理解多框架协同开发范式,并支持模型替换与功能扩展。 最近整理手上几个小项目的时候,翻到了这套基于 OpenCV + Qt + YOLO 的简单检测系统。功能说不上多高大上,就是从摄像头或视频文件里取帧,YOLO 检测画面中的人,再通过 OpenCV 画框标出来,整个过程放在一个 Qt 窗口里实时显示。当时有朋友找我拿这份代码做课设参考,我把项目思路、关键实现和踩过的坑一并整理出来,给正准备做类似检测系统的人一点参考。

这套东西适合谁?两类人。一是刚接触目标检测、想快速搭一个带 GUI 的检测 demo 的学生,二是工作中需要在画面里做实时人形框选的开发者。不管你是用 YOLOv5 还是 YOLOv8,界面上怎么组织、OpenCV 和 Qt 之间怎么配合,这套思路都是通用的。下面我把整个项目的设计逻辑、环境配置、核心代码、常见问题挨个拆开讲。

1. 项目整体设计与技术选型

1.1 这个检测系统到底做了什么

从功能角度看,这个项目要解决的其实是三件事:图像从哪来、人怎么被识别出来、识别结果怎么呈现给用户。整个数据流是一条直线:摄像头或视频文件作为输入,OpenCV 负责读取和预处理每一帧图像,YOLO 模型负责对图像做推理并输出目标位置,最后 OpenCV 把边界框绘制到原图上,Qt 窗口负责把处理后的图像实时显示出来。

我这里把功能清单列一下,方便你对照自己项目的需求范围:

  • 实时读取摄像头画面,作为检测输入源
  • 读取已录制的视频文件(mp4、avi 等常见格式)
  • 对每一帧执行 YOLO 推理,检测画面中的人
  • 在原图上绘制边界框和置信度标签
  • 通过 Qt 窗口实时显示检测结果
  • 用滑块调节置信度阈值,过滤低置信度结果
  • 支持暂停检测、恢复检测、退出

最初我把这套系统做成纯命令行调用 YOLO 的方式,每跑一帧在终端里打印坐标,结果调试起来非常痛苦。你根本不知道检测框画在画面里是什么效果,只能把结果写回图片再打开看。后来加上 Qt 界面之后,所有问题一目了然,调参也顺手多了。这是我认为这个组合最大的价值——不是哪个环节特别强,而是链路完整,从采集到显示全程可视。

1.2 为什么偏偏是 OpenCV + Qt + YOLO

三个库的分工很明确。OpenCV 负责图像处理环节:读取摄像头、颜色空间转换、图像缩放、画框、在窗口里虽然也能显示但我不建议用,因为 Qt 的界面交互能力远远更强。Qt 负责界面和线程:窗口布局、按钮交互、信号槽机制、多线程管理与 UI 更新的线程安全。YOLO 负责核心的推理环节:输入一张图,输出所有检测目标的类别、坐标、置信度。

选型背后是有取舍的。当初我也考虑过直接在 OpenCV 里用 DNN 模块跑模型,OpenCV 自带的cv::dnn::readNet可以加载 ONNX 格式的模型,不用额外引 YOLO 相关库。但实际用下来发现,如果你想换模型版本、做数据增强预处理、甚至自己重新训练一个模型,YOLO 官方生态提供的工具链要成熟得多。另外从学习角度讲,把 YOLO 推理独立成一个模块,能让你更清楚地看到模型输入输出的细节。

有人可能会问,为什么不直接用 Python 写?用 Python 的话 OpenCV 和 YOLO 的调用确实更简单,代码量少很多。但 Qt 做桌面端界面,C++ 版本在性能和打包发布上还是有优势的,尤其你要做的是实时的视频流处理,C++ 在内存控制和帧处理延迟上更可控。当然,如果你只是快速验证算法,Python 也行,本文的架构思路在两种语言下是通用的。

1.3 这个项目的边界在哪里

再说清楚一点:这个系统的定位是“简单检测系统”,不是完整的安防监控平台。它没有做目标跟踪、跨摄像头接力、报警联动、录像回放这些功能,只有最基础的“检测人并框选”。这样的定位有好处,就是代码结构清晰,适合作为二次开发的基础骨架。

你在参考的时候,可以按自己的需求往里加东西。比如加上 DeepSORT 做目标跟踪,让每个检测到的人有稳定的 ID;或者加入计数逻辑,统计画面里某一区域的人数;甚至把检测结果写入数据库做报表。因为整个架构把采集、推理、显示三个环节解耦了,改任何一个环节都不会影响另外两个。

2. 环境搭建与依赖准备

2.1 OpenCV 安装和最容易踩的坑

OpenCV 版本我建议直接用 4.x 系列,4.5 以上都行,最新的 4.8、4.9 也完全没问题。版本太老(比如 3.x)在 YOLO 模型支持上会有不少麻烦,尤其是 DNN 模块对新格式模型的支持。安装方式我用的是官方预编译包,Windows 上下载 exe 后解压到指定目录,然后把opencv\\build\\include加入包含目录,把opencv\\build\\x64\\vc15\\lib加入库目录。

这里有个新手必踩的坑:编译 Debug 版本的程序,链接库也要选带d后缀的opencv_world490d.lib,Release 版本则链接opencv_world490.lib,搞混了会出现一堆莫名其妙的链接错误。运行时还要把opencv_world490.dll复制到 exe 所在目录,或者把opencv\\build\\x64\\vc15\\bin加入 PATH 环境变量,否则程序一启动就报“找不到 opencv_world490.dll”。

Linux 上面如果有apt可以直接装libopencv-dev,不过版本可能不是最新的。我自己更推荐从源码编译,能按需裁剪模块,但编译时间比较长,新手可以先装现成的。源码编译的话,记得开WITH_QT=ON选项,这样 OpenCV 自带的imshow能和 Qt 集成,后续如果有需要可以少踩一个坑。

2.2 Qt 环境:版本选择与工程配置

Qt 版本我推荐 5.12 或 5.15 LTS,对 OpenCV 的兼容性好,资料也多。Qt6 这几年也越来越成熟,但有些老代码在 Qt6 上要改。如果你的电脑上已经装了 Qt5,就先用 Qt5,不用纠结。编译器方面,Windows 上建议用 MSVC,因为 OpenCV 官方预编译包就是 MSVC 编译的,用 MinGW 会有 ABI 兼容问题,到时候链接会出乱子。如果一定要用 MinGW,OpenCV 也得自己源码编译成 MinGW 版本,工程量直接翻倍。

工程文件我用的是.pro格式。如果你用 CMake 也完全可以,不过.pro文件在 Qt Creator 里更顺手。这是我当时工程文件里和 OpenCV、YOLO 路径相关的配置:

QT += core gui widgets TARGET = YoloDetector TEMPLATE = app CONFIG += c++17 # OpenCV INCLUDEPATH += D:/opencv/build/include LIBS += D:/opencv/build/x64/vc15/lib/opencv_world490.lib LIBS += D:/opencv/build/x64/vc15/lib/opencv_world490d.lib SOURCES += main.cpp MainWindow.cpp Detector.cpp HEADERS += MainWindow.h Detector.h FORMS += MainWindow.ui

D:/opencv是我的安装路径,你换成自己的路径就行。还有一个细节,Debug 和 Release 两个模式链接的库不一样,所以我上面把两个都写了,但实际你最好用CONFIG(debug, debug|release)CONFIG(release, debug|release)分隔开,避免同时链接两个库文件冲突。

2.3 YOLO 模型:选 v5 还是 v8

做“检测人”这种单类别任务,YOLOv5s 和 YOLOv8n 都很合适。YOLOv5s 的体积小、速度快,在 CPU 上跑也能有不错的帧率;YOLOv8n 是 Ultralytics 官方推出的轻量模型,精度比 v5s 略高一点,生态也更主动。因为我这个项目最终要部署到别人的电脑上,对方不一定有 GPU,所以我优先选体积小、推理快的模型,最后用了 YOLOv8n。

模型格式上,你会发现 YOLOv5 常用.pt(PyTorch)格式,YOLOv8 也支持.pt。如果你要在 C++ 里集成,强烈建议把模型导出为 ONNX 格式,然后用 ONNX Runtime 或者 OpenCV DNN 加载。ONNX 的好处是跨框架、跨语言,部署的时候不用装 PyTorch,整个程序体积小很多。

导出命令很简单,在 Python 环境里装好 ultralytics 后,执行:

yolo export model=yolov8n.pt format=onnx opset=12

导出完成后会得到一个yolov8n.onnx文件,把这个文件复制到项目目录下,接下来就可以用它做推理了。你如果坚持用 PyTorch 的.pt文件做 C++ 推理,那得用 libtorch,配置更复杂,还不容易打包,我是不推荐走这条路。

3. 核心实现:从摄像头到屏幕的完整链路

3.1 架构设计:为什么必须分线程

检测系统如果直接在 UI 线程里做视频读取和模型推理,界面会卡成 PPT。YOLO 推理在 CPU 上一帧要几十毫秒到上百毫秒,在这期间 UI 线程被占住,点击按钮没反应、窗口拖不动,体验非常差。所以我一开始就把整个程序分成三个线程:

  • 主线程(UI 线程):负责界面响应、按钮事件、图像显示
  • 采集线程:用 OpenCV 的VideoCapture持续读取帧,放入缓冲队列
  • 推理线程:从缓冲队列取帧,执行 YOLO 推理,画框,把结果显示出来

三个线程之间通过 Qt 的信号槽通信。C++ 里跨线程传cv::Mat是不安全的,所以我在采集线程读完帧之后,先把cv::Mat转成QImage,通过信号槽丢给 UI 线程去显示。QImage是隐式共享的,传起来成本低,而且在 UI 线程里直接setPixmap也不需要额外加锁。

你可能会问:既然都要转成QImage,那推理之前是不是也得转回来?我的做法是不转回来。推理线程拿到的是原始cv::Mat的拷贝,在推理线程内部做预处理、推理和绘制,绘制完的结果再转成QImage发给界面。也就是说,线程间的传输类型统一是QImage,这样最省心。

还要注意缓冲队列的长度。我一开始用QQueue<cv::Mat>做队列,不加限制,结果发现摄像头输入 30 帧,推理只能跑 10 帧,队列越积越长,延迟越来越大。后来加了一个限制,队列里最多保留 3 帧,满了就丢弃新帧。这个策略叫丢帧,保证你看到的永远是最近的一帧,而不是积压的旧画面。

3.2 Qt 界面:最简布局也要讲逻辑

界面布局我没做得花哨,一个 QLabel 用来显示图像,一个 QComboBox 切换输入源(摄像头/视频文件),几个按钮控制开始、暂停、停止,一个滑块调置信度阈值。看起来简单,但布局顺序要讲究。QLabel 是整个界面的核心,应该放在中心区域并自动伸缩;控制按钮放在底部或侧边,用QHBoxLayout排成一行。

关键点在于 QLabel 显示图像时的缩放策略。摄像头分辨率可能是 1280x720,但窗口可能只有 800x600,直接用setPixmap会超出窗口范围。我在setPixmap之前调用pixmap.scaled(label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation),这样图片会按比例缩放,不变形。同时把 QLabel 的setAlignment(Qt::AlignCenter)设置好,保证缩放后的图像居中显示。

对于阈值滑块,我用 QSlider 配合 QLCDNumber 或者 QLabel 显示当前值,范围设 25 到 95,单位是百分比。滑块值变化时发出valueChanged信号,在槽函数里更新推理线程的置信度参数。这里要注意线程安全问题,滑块在 UI 线程,推理线程读这个值。我一开始直接用普通变量,结果出现界面改了值,推理线程偶尔还是旧值的情况。后来改成std::atomic<int>,问题就没了。

3.3 YOLO 推理封装:输入输出要做哪些处理

我把 YOLO 推理封装成了一个独立的Detector类,对外只暴露两个方法:loadModeldetect。这样在 UI 层完全不用关心模型内部怎么实现,想换模型版本只需要改这个类。

loadModel负责加载 ONNX 模型并创建 ONNX Runtime 的会话。这个会话可以复用,不用每帧重新创建,否则性能会非常差。

detect方法要做的事比较细:

  1. 把 OpenCV 的cv::Mat(BGR 格式)转成 RGB,因为 YOLO 训练时用的是 RGB
  2. 缩放到模型要求的输入尺寸(比如 640x640)
  3. 归一化:像素值从 0-255 缩放到 0-1
  4. 把 HWC 格式转成 CHW 格式,因为模型输入是 NCHW
  5. 执行session.Run
  6. 解析输出,用 NMS(非极大值抑制)过滤重叠框
  7. 把坐标从输入尺寸映射回原始图像尺寸

第 4 步是新手最容易出错的地方。OpenCV 的cv::Mat默认是 HWC,模型要的是 CHW,你如果直接把 Mat 的数据指针传给模型,一定会得到一堆乱坐标。我这里贴一段核心的预处理代码:

cv::Mat blob = cv::dnn::blobFromImage(letterbox_img, 1.0 / 255.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);

blobFromImage一步就完成了缩放、归一化和 HWC→CHW 的转换,非常方便。不过我用 ONNX Runtime 的时候是自己手动做的转换,因为要更精细地控制转换逻辑。顺序是这样的:先cv::cvtColor转 RGB,再cv::resize到 640x640,然后img.convertTo(img, CV_32FC3, 1.0 / 255.0),最后把三个通道的数据分别拷贝到输入张量对应的内存位置。

输出解析这块,YOLOv8 的输出格式是一个二维数组,形状是[1, 84, 8400]。其中 84 是 4 个坐标信息加 80 个类别置信度,8400 是所有预测框的数量。你要做的就是从 8400 个框中过滤出类别为 person(COCO 数据集中 person 的类别 id 是 0)且置信度大于阈值的框,再做 NMS。NMS 的逻辑不复杂:把所有框按置信度排序,选分数最高的框,然后删除和它重叠度(IoU)大于 0.45 的其他框,不断重复。

3.4 绘制框选:画框的位置和样式有讲究

检测结果拿到坐标后,用 OpenCV 的cv::rectanglecv::putText在原图上画框和标签。这个环节看起来简单,但有两个细节要注意。

第一是坐标映射。模型输入的图是 640x640,如果你的原始视频是 1280x720,直接拿模型输出的坐标在原图上画,框的位置会完全偏掉。我写了两个转换函数,一个是检测框坐标从模型输入空间映射回原始图像空间。如果用的是简单的 resize 而不是 letterbox,那映射就是等比缩放;如果用了 letterbox(保持宽高比加灰边),那要先减去灰边的偏移再缩放。我当时为了省事用了直接 resize,牺牲了一点比例,但画出来的框是准确的。

第二是绘制性能。cv::rectangle每个框调用一次没问题,但如果检测到很多人,几十个框叠加遍历绘制,对性能的影响其实可以忽略,因为 OpenCV 的绘制是高度优化的。真正影响性能的是字体。cv::putText每次调用要重新计算字形,如果对每个框都用默认字体,一帧里几十个框就会出现轻微卡顿。我后来改用cv::HersheyFonts里较简单的字体,并且对同一个标签文本做了缓存,问题就消失了。

还有一个反直觉的点:画框的线条不能太粗。在 1280x720 的画面里,线条粗细设为 2 就够醒目了,设成 4 反而会遮住人脸细节。如果你在窗口中做二次缩放显示,线宽还会被放大,所以建议线宽设为 1 或 2。

3.5 cv::Mat 与 QImage 的转换细节

这个转换是所有 Qt + OpenCV 项目里绕不开的一步,坑也多。我直接给出我用的函数:

QImage MatToQImage(const cv::Mat &mat) { switch (mat.type()) { case CV_8UC3: { cv::Mat rgb; cv::cvtColor(mat, rgb, cv::COLOR_BGR2RGB); return QImage(rgb.data, rgb.cols, rgb.rows, static_cast<int>(rgb.step), QImage::Format_RGB888).copy(); } case CV_8UC1: { return QImage(mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_Grayscale8).copy(); } default: return QImage(); } }

注意我调用了.copy(),这一点特别重要。如果不调用 copy,QImage 只是包了一层外部的数据指针,一旦原始cv::Mat被释放,QImage 就变成悬空指针,界面显示的图像会出现花屏甚至程序崩溃。因为 Qt 的信号槽是异步的,图像数据可能在槽函数执行之前就被释放了。copy 会复制一份像素数据,虽然多一次内存拷贝,但保证了线程安全。

格式方面,OpenCV 读入的图是 BGR 顺序,QImage 里最常见的是 RGB888,所以必须先cvtColor转成 RGB,否则显示出来红色和蓝色是反的。这个错我曾经犯过,看到画面里人的脸是蓝的才反应过来。

4. 性能优化与功能扩展

4.1 推理速度不够怎么办

如果你在 CPU 上跑 YOLOv8n,640x640 输入,实测大概每帧 60-100 毫秒,也就是 10-15 FPS。这个速度看静态场景还凑合,但画面一有快速运动就会明显卡顿。我的建议是,先别急着上 GPU,按顺序做下面几个优化:

  • 把输入尺寸降到 480x480 或 416x416,推理时间可以缩短近一半,代价是远距离小目标的检测率下降
  • 在视频流场景下做跳帧推理,比如只对每 2-3 帧执行一次模型推理,中间帧直接沿用上一帧的检测结果,画面看起来依然是流畅的
  • 把推理线程的 CPU 亲和性设置为大核,减少线程调度带来的抖动
  • cv::UMat做图像预处理,在支持的硬件上可以利用 GPU 加速转换

跳帧是性价比最高的方案。我实际测试,检测的 FPS 只有 12,但开了间隔 2 帧检测之后,显示端的画面流畅度接近 24 FPS,视觉体验提升非常明显。代价是如果画面里快速出现一个新的人,最多延迟 2 帧才被框出来,对多数场景来说完全可以接受。

4.2 不只检测人:如何扩展到其他目标

这个项目虽然只检测人,但换检测类别其实很简单。COCO 数据集有 80 个类别,YOLOv8 模型输出层的类别置信度已经包含了所有 80 类。你要做的只是在解析输出时,把过滤条件从“类别 id 等于 0(person)”改成其他类别 id。例如检测猫就是 id 15,检测车就是 id 2。

如果你想检测自己训练的特殊目标,比如车牌、特定产品缺陷等,那就要重新训练模型了。数据集可以用 LabelImg 或 Roboflow 标注,训练过程用 ultralytics 一条命令就能跑起来。训练完导出 ONNX,替换掉项目里的模型文件,再按需修改类别列表和 NMS 阈值,其他代码完全不用动。这算是封装成独立 Detector 类最大的好处。

4.3 结果保存:截图与视频录制

在实际使用中,经常需要把检测结果保存下来。截图的实现最简单,在 UI 线程拿到 QImage 后直接image.save("capture.png")。不过我建议在保存前把界面上叠加的信息也绘制进去,这样图片能反映当时的检测状态。我是在推理线程里绘制完框之后、转成 QImage 之前,额外在图像左上角写一行时间戳和 FPS,这样保存下来的截图自带信息,后面翻看很方便。

录制检测结果视频稍微复杂一点。一种方式是用 OpenCV 的VideoWriter,在推理线程里把绘制好的cv::Mat写入编码器。但要注意编码器的选择,mp4v编码在很多设备上兼容性最好,x264编码则文件更小。如果你用的是 Qt 界面,还可以用 Qt Multimedia 模块做录制,但配置复杂一些。我的经验是,录检测后的画面用 OpenCV 就够了,因为数据本来就在cv::Mat里流转,没必要多绕一层。

5. 常见问题与排查经验

5.1 现场最常遇到的 5 个问题

我在做这个项目的过程中,几乎把新手的坑都踩了一遍。下面按问题频率整理成表格,方便你对照排查。

问题现象产生原因解决办法
程序启动后立即报“找不到 DLL 文件”OpenCV 或 Qt 的 DLL 不在 exe 同目录opencv_world490.dll和 Qt 的Qt5Core.dll等复制到 exe 目录
摄像头图标亮了但画面黑屏摄像头被其他程序占用,或者视频格式不支持关闭其他摄像头程序;尝试cv::VideoCapture(0)换索引号
检测不到任何目标置信度阈值设置过高,或模型类别不是 person把阈值调到 25% 试一下;检查类别解析逻辑
画面中框的位置偏移严重模型输入尺寸与原始图像尺寸映射错误检查坐标逆变换公式,注意 letterbox 的灰边偏移
界面上图像颜色怪异(红蓝对调)cv::Mat 的 BGR 与 QImage 的 RGB 混用在 MatToQImage 里加cvtColor

5.2 摄像头打不开的深层原因

摄像头打开失败是最常见的入门问题。OpenCV 里VideoCapture(0)的索引 0 表示系统第一个摄像头,但笔记本上如果有多个摄像头(比如一个是红外、一个是普通 RGB),索引就要挨个试。我曾经遇到过一台设备上要写VideoCapture(2)才能打开内置摄像头的情况,原因是有两个虚拟摄像头排在前面。

另一个坑是权限问题。在 Windows 上,系统的隐私设置里有一个“允许桌面应用访问相机”的开关,如果这个关掉了,Qt 程序调摄像头时会直接失败,但不会有明显报错,只是画面一直是黑的。Linux 上则是设备权限问题,用户需要在video用户组里,否则/dev/video0设备无法访问。

如果在程序崩溃后重新打开摄像头,可能遇到“设备被占用”的提示,这时候先把进程彻底退掉,再重新VideoCapture。我在异常退出后经常用任务管理器杀掉残留进程,否则重启程序会一直报错。

5.3 推理结果偶尔闪退,真相往往是内存问题

闪退是 C++ 项目里最让人头疼的问题。我在这个项目里遇到过几次闪退,定位下来基本都是内存访问越界引起的,不是 YOLO 本身的问题。

最常见的三种情况是:解析输出时访问了超出模型输出长度的索引;NMS 实现里对空集合调用front();跨线程传递cv::Mat时没有拷贝。前面两件事要在代码里仔细检查边界条件,后面一件事我前面提过,用mat.clone()或转成 QImage 再传就能解决。如果你在调试时看到异常发生在cv::Mat的析构函数里,大概率就是跨线程共享了 Mat 数据。

定位这种问题,我强烈建议用AddressSanitizer编译一下程序,编译选项加-fsanitize=address,它能精确告诉你哪一行代码越界了,比用断点一点点排查快十倍。在 Qt 的.pro文件里加上QMAKE_CXXFLAGS += -fsanitize=addressLIBS += -fsanitize=address就能开启。

5.4 部署到别的电脑上运行不起来

开发环境跑得好好的,把 exe 拷到别的电脑打不开,这是 Qt 项目打包的经典问题。解决办法是用 Qt 自带的windeployqt工具,把 Qt 相关的 DLL 自动复制到 exe 目录,然后再手动把 OpenCV 的 DLL 放进去。windeployqt的使用是在命令行运行:

windeployqt YoloDetector.exe

它会分析 exe 的依赖,把需要的 Qt 模块 DLL、插件目录都复制过来。OpenCV 的 DLL 需要手动复制。如果你用了 ONNX Runtime,对应的onnxruntime.dll也要放进目录。复制完之后把整个文件夹压缩发给别人,就能直接运行了。

我还有一个习惯,就是在main.cpp里设置qputenv("QT_QPA_PLATFORM_PLUGIN_PATH", "./platforms"),确保插件路径正确。如果你发现目标电脑上程序报could not find or load the Qt platform plugin "windows",多半就是 platforms 插件目录没复制进去。

6. 个人实操总结

这套检测系统不复杂,但它把一个完整的链路打通了:从摄像头取流、模型推理、结果绘制、界面显示,全都可以在本地实时跑起来。我做完之后最大的感受是,很多看似理所当然的步骤,真在代码里走一遍才会碰到各种细节问题,比如 BGR 和 RGB 的转换、线程间的 Mat 共享、模型坐标映射。这些问题折磨人的时候确实烦,但解决完之后,对 OpenCV 和 Qt 的理解会深一个层次。

如果你要在这个项目上继续往前做,我建议优先补两件事:一是加一个简单的目标跟踪模块,让检测框在画面上稳定不跳;二是把模型换成自己训练的版本,检测你真正关心的目标。这两件事做完,这个系统基本就能从课设作品变成能实际用的小工具了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询