C++ QT 结合 OpenCV 12周项目制学习计划(普通版)
目录
第1周:环境搭建与基础图像处理
第2周:图像处理核心 - 滤波与几何变换
第3周:颜色空间与形态学操作
第4周:直方图与特征检测
第5周:视频处理与背景减除
第6周:目标追踪算法
第7周:机器学习入门 - Haar/LBP 人脸检测
第8周:DNN 模块 - 运行深度学习模型
第9周:相机标定
第10周:立体视觉与深度图
第11周:OCR 文字识别
第12周:企业级项目 - 综合应用
C++ QT 结合 OpenCV 学习建议
1. 专注与深入
2. QT 与 OpenCV 的协同(重点)
3. 项目扩展
4. 保持耐心
本计划专为已有 C++ QT 基础、希望深入学习 OpenCV 并最终能独立完成企业级项目的开发者设计。每周将围绕一个核心项目,在“做中学”,快速掌握 OpenCV 的关键技能。
第1周:环境搭建与基础图像处理
-
核心焦点: 配置 OpenCV 开发环境,将其与 QT 项目(QMake 或 CMake)链接,掌握最核心的
cv::Mat数据结构,以及图像的读取、显示和保存。 -
本周项目: “简易图像查看器”
-
描述: 创建一个 QT 窗口应用,可以打开本地图像文件,将其显示在
QLabel或QGraphicsView中。 -
功能点:
-
QT 菜单栏实现“打开文件”功能。
-
使用
cv::imread读取图像到cv::Mat。 -
核心转换: 编写一个辅助函数,将
cv::Mat(BGR 格式) 转换为QImage(RGB 格式) 以便在 QT 中显示。 -
实现“另存为”功能,使用
cv::imwrite保存图像。 -
额外挑战:添加“灰度化”按钮,使用
cv::cvtColor将彩色图像转为灰度图并显示。
-
-
-
关键学习:
-
cv::Mat: 了解其构造、通道 (channels)、深度 (depth) 和数据指针 (.data)。 -
cv::imread,cv::imwrite: 读写图像。 -
cv::cvtColor: 颜色空间转换 (BGR <-> RGB, BGR -> GRAY)。 -
OpenCV 与 QT 的集成配置(头文件和库的链接)。
-
第2周:图像处理核心 - 滤波与几何变换
-
核心焦点: 图像去噪(模糊)、边缘检测和几何变换。
-
本周项目: “文档扫描矫正器”
-
描述: 加载一张倾斜拍摄的文档照片,自动检测文档边缘,并将其通过透视变换“拉正”为A4纸那样的俯视视角。
-
功能点:
-
cv::GaussianBlur: 高斯模糊以减少噪点。 -
cv::Canny: Canny 边缘检测,找到文档轮廓。 -
cv::findContours: 查找图像中的所有轮廓。 -
轮廓筛选:遍历轮廓,通过
cv::approxPolyDP找到最大的四边形轮廓(即文档)。 -
cv::getPerspectiveTransform: 根据找到的四边形四个顶点和目标矩形的四个顶点,计算变换矩阵。 -
cv::warpPerspective: 应用透视变换,得到矫正后的图像。
-
-
-
关键学习:
-
图像滤波:
cv::GaussianBlur,cv::medianBlur。 -
边缘检测:
cv::Canny。 -
轮廓处理:
cv::findContours,cv::drawContours,cv::approxPolyDP。 -
几何变换:
cv::getPerspectiveTransform,cv::warpPerspective。
-
第3周:颜色空间与形态学操作
-
核心焦点: 探索 HSV 颜色空间(对光照变化更鲁棒),并使用形态学操作(腐蚀、膨胀)来优化二值图像。
-
本周项目: “特定颜色物体追踪”
-
描述: 从摄像头(或视频文件)读取实时视频流,识别并用方框圈出指定颜色(例如:一个绿色的瓶盖)的物体。
-
功能点:
-
cv::VideoCapture: 打开摄像头或视频文件。 -
在 QT 中使用
QTimer定时读取视频帧。 -
cv::cvtColor: 将 BGR 帧转换为 HSV 颜色空间。 -
cv::inRange: 根据设定的 HSV 阈值(例如绿色的 H 范围),生成一个二值化的掩码 (mask)。 -
cv::morphologyEx: 使用“开运算”(先腐蚀后膨胀)去除小的噪点,使用“闭运算”(先膨胀后腐蚀)填充物体内部的小孔洞。 -
cv::findContours: 在掩码上找到物体轮廓。 -
cv::boundingRect: 获取轮廓的最小外接矩形,并将其绘制在原始视频帧上。
-
-
-
关键学习:
-
HSV 颜色空间及其在物体识别中的优势。
-
cv::inRange: 创建颜色掩码。 -
形态学:
cv::erode(腐蚀),cv::dilate(膨胀),cv::morphologyEx(开/闭运算)。 -
cv::VideoCapture: 处理视频流。 -
cv::boundingRect: 查找包围盒。
-
第4周:直方图与特征检测
-
核心焦点: 图像直方图的计算与应用。了解特征点(Keypoints)和描述子(Descriptors)的概念。
-
本周项目: “图像相似度比对器”
-
描述: 加载一张“模板”图像和一张“测试”图像,使用 ORB 特征点来判断两张图像的相似程度。
-
功能点:
-
cv::calcHist: (可选)计算两张图的直方图,并使用cv::compareHist比较,作为一种粗略的相似度判断。 -
cv::ORB::create(): 创建 ORB 特征检测器。 -
detectAndCompute(): 在两张图像上分别检测特征点并计算描述子。 -
cv::BFMatcher: 创建一个暴力匹配器。 -
match(): 匹配两组描述子。 -
筛选匹配:根据匹配“距离”(Distance)筛选出好的匹配点。
-
cv::drawMatches: 可视化匹配结果。 -
根据“好的匹配点”的数量来给出一个相似度评分。
-
-
-
关键学习:
-
特征点检测:
cv::ORB,cv::KeyPoint。 -
特征描述子:
cv::DescriptorExtractor。 -
特征匹配:
cv::BFMatcher(暴力匹配),cv::DMatch(匹配结果)。 -
(可选)
cv::calcHist,cv::compareHist。
-
第5周:视频处理与背景减除
-
核心焦点: 实时视频流中的运动物体检测。
-
本周项目: “简易安防监控(移动侦测)”
-
描述: 监控摄像头画面,当有物体进入(即发生移动)时,高亮显示移动物体。
-
功能点:
-
继续使用
cv::VideoCapture和QTimer。 -
cv::createBackgroundSubtractorMOG2: 创建一个基于高斯混合模型的背景减除器。 -
apply(): 将每一帧喂给减除器,它会返回一个只包含“前景”(即移动物体)的掩码。 -
对前景掩码进行形态学操作(开/闭运算)以去噪。
-
cv::findContours: 找到所有移动物体的轮廓。 -
在原图上绘制这些轮廓的包围盒。
-
-
-
关键学习:
-
背景减除:
cv::BackgroundSubtractor,cv::createBackgroundSubtractorMOG2。 -
apply()方法的使用。 -
将前景掩码与原始帧结合显示。
-
第6周:目标追踪算法
-
核心焦点: 了解 OpenCV
tracking模块中提供的多种追踪算法(如 KCF, CSRT)。 -
本周项目: “ROI 选定与追踪”
-
描述: 在视频流的第一帧,允许用户通过鼠标(在 QT 界面上)拖拽出一个矩形框(ROI, Region of Interest),然后启动追踪器,在后续视频帧中持续追踪这个被选中的物体。
-
功能点:
-
在 QT 中重写
mousePressEvent和mouseMoveEvent来实现矩形框选。 -
cv::TrackerCSRT::create(): 创建一个高性能的 CSRT 追踪器。 -
init(): 使用用户选择的矩形框和第一帧图像来初始化追踪器。 -
update(): 在后续的每一帧上调用,追踪器会返回物体的新位置。 -
在界面上实时绘制追踪到的矩形框。
-
-
-
关键学习:
-
OpenCV
tracking模块的编译和使用。 -
cv::Tracker,cv::TrackerCSRT,cv::TrackerKCF。 -
init()和update()流程。 -
QT 鼠标事件与 OpenCV ROI 的结合。
-
第7周:机器学习入门 - Haar/LBP 人脸检测
-
核心焦点: 使用 OpenCV 提供的传统机器学习方法(Haar/LBP 特征)进行目标检测。
-
本周项目: “实时人脸打卡模拟器”
-
描述: 打开摄像头,实时检测画面中的人脸,并在 QT 界面上显示检测到的人数。
-
功能点:
-
cv::CascadeClassifier: 创建级联分类器。 -
load(): 加载 OpenCV 预训练好的haarcascade_frontalface_default.xml(或lbpcascade_frontalface.xml)模型文件。 -
detectMultiScale(): 在每一帧图像(建议先转为灰度图)上执行多尺度检测,返回检测到的人脸矩形框列表。 -
遍历矩形框列表,在原图上绘制。
-
在 QT UI 上更新一个
QLCDNumber或QLabel来显示rects.size()(即人数)。
-
-
-
关键学习:
-
cv::CascadeClassifier: 级联分类器的使用。 -
detectMultiScale: 多尺度检测。 -
了解预训练模型 (XML 文件) 的概念。
-
Haar 特征与 LBP 特征的(概念性)区别。
-
第8周:DNN 模块 - 运行深度学习模型
-
核心焦点: 使用 OpenCV 的 DNN 模块加载并运行主流的深度学习模型(如 Caffe, TensorFlow, ONNX 格式)。
-
本周项目: “实时物体识别 (MobileNet-SSD)”
-
描述: 加载一个预训练的轻量级物体检测模型(如 MobileNet-SSD),对摄像头视频流进行实时检测,能识别多种物体(如:人、车、猫、狗、瓶子等)并显示类别和置信度。
-
功能点:
-
下载预训练的
.caffemodel和.prototxt文件。 -
cv::dnn::readNetFromCaffe(): 加载 Caffe 模型(如果是其他格式,用readNet)。 -
cv::dnn::blobFromImage(): 将cv::Mat图像转换为网络所需的blob输入格式(包括缩放、归一化等)。 -
net.setInput(): 设置网络输入。 -
net.forward(): 执行前向传播,得到检测结果。 -
解析输出:
forward返回的cv::Mat是一个N行7列的矩阵。遍历每一行,解析出 [batchId, classId, confidence, left, top, right, bottom] 信息。 -
根据置信度(如 > 0.5)筛选结果,并在原图上绘制矩形框和类别标签。
-
-
-
关键学习:
-
cv::dnn::Net: 深度学习网络类。 -
cv::dnn::readNet...: 加载不同格式的模型。 -
cv::dnn::blobFromImage: 图像预处理。 -
net.forward(): 运行模型。 -
理解并解析 DNN 模型的输出格式(这是本周的难点和重点)。
-
第9周:相机标定
-
核心焦点: 理解相机内参、外参和畸变系数。学会如何标定自己的相机。
-
本周项目: “相机畸变校正器”
-
描述: 1. 准备一张棋盘格(打印出来)。 2. 编写一个程序,用相机从不同角度拍摄棋盘格(约15-20张)。 3. 程序自动检测每张照片的角点。 4. 使用这些角点计算相机的内参矩阵和畸变系数。 5. 保存标定结果。 6. 开启实时校正模式,用
cv::undistort对摄像头画面进行实时去畸变。 -
功能点:
-
cv::findChessboardCorners: 查找棋盘格角点。 -
cv::cornerSubPix: 亚像素级角点精调。 -
cv::calibrateCamera: 执行相机标定,得到cameraMatrix和distCoeffs。 -
cv::undistort: 使用标定结果对新图像或视频帧进行畸变校正。
-
-
-
关键学习:
-
相机模型(针孔模型)。
-
内参、外参、畸变系数的物理意义。
-
cv::calibrateCamera,cv::undistort。 -
标定数据的保存与加载 (使用
cv::FileStorage)。
-
第10周:立体视觉与深度图
-
核心焦点: (需要双目摄像头或数据)理解立体匹配原理,计算视差图和深度图。
-
本周项目: “双目测距(生成深度图)”
-
描述: (如果硬件受限,可使用 OpenCV 官方提供的 Stereo 数据集) 1. 对双目相机进行立体标定。 2. 对左右图像进行立体校正。 3. 使用
StereoSGBM算法计算视差图。 4. 可视化视差图(即深度图)。 -
功能点:
-
cv::stereoCalibrate: 双目标定。 -
cv::stereoRectify: 立体校正。 -
cv::initUndistortRectifyMap: 计算校正查找图。 -
cv::remap: 应用校正。 -
cv::StereoSGBM::create(): 创建 SGBM(半全局块匹配)算法实例。 -
compute(): 计算视差图。 -
cv::reprojectImageTo3D: (可选)将视差图转换为 3D 点云。
-
-
-
关键学习:
-
对极几何(Epipolar Geometry)基本概念。
-
cv::stereoCalibrate,cv::stereoRectify。 -
cv::StereoBM,cv::StereoSGBM两种匹配算法的使用和调参。
-
第11周:OCR 文字识别
-
核心焦点: 使用 OpenCV 的
text模块(可能需要额外编译)或结合 Tesseract OCR 引擎。 -
本周项目: “图像文字提取器”
-
描述: 加载一张包含清晰文字的图片(如发票、书页),识别图中的文字并将其显示在 QT 的
QTextEdit中。 -
功能点:
-
(方案一)配置和使用 Tesseract OCR 库(推荐)。
-
(方案二)编译 OpenCV
text模块,使用cv::text::OCRTesseract。 -
对输入图像进行预处理:灰度化、二值化(
cv::adaptiveThreshold非常有用)、去噪。 -
调用 OCR 引擎的
recognize或GetUTF8Text方法。 -
将识别到的字符串设置到
QTextEdit。
-
-
-
关键学习:
-
OCR 基本原理。
-
Tesseract OCR 库的 C++ API 使用。
-
图像预处理对 OCR 结果的极端重要性。
-
cv::adaptiveThreshold。
-
第12周:企业级项目 - 综合应用
-
核心焦点: 将前11周所学知识融会贯通,构建一个更完整、更健壮的“企业级”原型应用。
-
本周项目: “简易工业质检(QC)流水线模拟”
-
描述: 模拟一条流水线,物品(如螺丝钉)匀速通过摄像头下方。系统需要:
-
检测物体: 当物体进入视野时(使用第5周的背景减除或第3周的颜色识别)。
-
定位物体: 抓取该物体的 ROI(第3周或第5周)。
-
执行质检: 对 ROI 图像执行“质检”算法。
-
质检算法A (尺寸检测): 找到物体轮廓(第2周),计算其外接矩形或最小外接圆,判断长宽比或面积是否在合格范围。
-
质检算法B (模板匹配): 使用
cv::matchTemplate(新函数)与标准“合格品”模板进行匹配,看匹配度是否达标。 -
质检算法C (缺陷检测): 使用特征匹配(第4周)或 DNN(第8周)判断是否为合格品。
-
-
UI反馈: 在 QT 界面上实时显示通过的物品总数、合格数、不合格数,并高亮显示当前被检测的物品(绿色=合格,红色=不合格)。
-
-
-
关键学习:
-
多线程: (企业级核心) 必须将 OpenCV 的耗时处理(如 DNN, SGBM, 视频帧处理)放在一个单独的工作线程中,通过 QT 信号将处理完的
QImage和结果发送回主线程(UI线程)更新,防止界面卡死。 -
系统集成: 将多个 OpenCV 模块(检测、跟踪、分类)组合成一个完整的逻辑流。
-
健壮性: 考虑各种异常情况(如物体遮挡、光照变化)。
-
参数调优: 学会通过 QT 界面(如
QSlider,QSpinBox)动态调整算法参数(如 Canny 阈值、HSV 范围等),以达到最佳效果。
-
C++ QT 结合 OpenCV 学习建议
恭喜你选择了一条极具价值的技术路径!为了让你在这12周的学习中收获最大,请参考以下建议:
1. 专注与深入
-
官方文档是第一老师: 遇到不熟悉的函数,第一反应应该是去查阅 OpenCV 官方文档。文档通常会提供 C++, Python, Java 的示例,并且详细解释每个参数的含义。
-
理解参数而非复制粘贴: 很多教程会直接给出一堆“魔法数字”(如
cv::Canny(img, edges, 100, 200))。你必须去理解100和200(高低阈值)的含义,尝试修改它们,看看会对结果产生什么影响。这是从“会用”到“精通”的关键。 -
阅读源码(如果可能): 当你对某个算法(如 Canny)非常好奇时,不妨点进去看看它的实现(或者至少是头文件中的注释)。这会极大加深你的理解。
2. QT 与 OpenCV 的协同(重点)
-
UI 线程 vs 工作线程: 这是企业级开发中最重要的原则。 任何耗时超过 10ms 的 OpenCV 操作(几乎所有的视频处理、DNN 推理、复杂计算)都禁止在 QT 的主线程(UI 线程)中执行,否则你的界面会立刻卡死。
-
标准模式:
-
创建一个继承自
QThread的工作线程类(例如CVWorker)。 -
在
CVWorker中实现一个循环(如run()方法),用于cv::VideoCapture::read()和所有 OpenCV 处理。 -
处理完成后(例如得到了一帧绘制好矩形框的图像和检测结果),通过
emit发送一个信号(例如frameReady(QImage image, QString result))。 -
在你的主窗口(UI 线程)中,使用
connect将这个信号连接到一个槽函数(例如updateUI(QImage image, QString result))。 -
在这个槽函数中,安全地更新
QLabel的图像和QStatusBar的文本。
-
-
数据传递: 在线程间传递
cv::Mat时要小心。最安全的方式是将其转换为QImage(QImage是隐式共享和写时复制的,适合跨线程传递),或者在发送信号前对cv::Mat进行深拷贝(.clone())。
3. 项目扩展
-
举一反三: 完成了“文档扫描矫正”,你是否能用它来矫正路标?完成了“人脸检测”,你是否能换个 XML 文件去做“人眼检测”或“车牌检测”?
-
性能考量: 你的实时视频处理能达到 30 FPS 吗?如果不能,瓶颈在哪里?
-
是不是图像分辨率太高了?(尝试
cv::resize) -
是不是算法太复杂了?(CSRT 追踪器比 KCF 慢但准,你需要哪个?)
-
是不是可以并行处理?(OpenCV 很多算法支持
cv::parallel_for_) -
(高级)你的 OpenCV 是否使用 TBB, OpenMP 或 CUDA 编译?
-
4. 保持耐心
-
你会遇到很多挫折: 链接器错误、内存访问冲突、
cv::Mat通道不匹配、DNN 输出解析错误……这些都是正常的。 -
调试技巧:
-
cv::imshow是最简单粗暴的调试器。在 C++ 中,cv::imshow需要配合cv::waitKey(0)(显示图像并等待按键)或cv::waitKey(1)(在循环中显示并短暂等待)。 -
在 QT 中,你不能在工作线程中使用
cv::imshow。你应该将中间结果(例如二值化的掩码、Canny 边缘图)也转换为QImage并发送到 UI 线程的调试QLabel上显示。 -
学会使用 GDB 或 Visual Studio 的调试器单步跟踪,并查看
cv::Mat变量的内容(很多 IDE 有插件可以可视化cv::Mat)。
-
祝你学习顺利!12周后,你将具备非常扎实的 OpenCV C++ 实战能力。
