首页 / 资讯中心 / 文章详情

双目立体视觉与CNN动作识别C++源码工程剖析

双目立体视觉与CNN动作识别C++源码工程剖析 ★ FEATURED ARTICLE
简介基于双目视觉的人体姿态匹配与动作识别毕业设计源码包面向计算机视觉方向的学生和研究者。项目实现十个动作识别包含完整C工程与Python训练脚本覆盖立体匹配、深度图获取到动作分类的完整流程。程序基于VS2015与OpenCV2.4.9opencv已打包在内配置好环境即可编译运行main文件夹中切换MODE即可运行匹配或识别模式。压缩包共42个文件除C/C源码头文件外还包含5个xml参数文件、2个Python训练与批量识别脚本、训练好的模型与权重文件以及项目说明、训练记录和效果图。资源包大小21.69MB已有228人学习。拿到后可借助训练好的模型直接对图片批量识别输出结果也可查看整理好的训练图片数据与识别脚本理解特征提取与分类思路在毕业设计或课程项目中快速复现并进一步改进。1. 基于双目的人体姿态匹配与识别 C 源码先看清它串起了哪条链路拿到这份基于双目的人体姿态匹配与识别 C 源码第一件事不是急着解压编译而是先弄清楚作者把整条链路串到了哪一步。压缩包内是 VS2015 OpenCV 2.4.9 的完整工程包含双目标定参数文件、立体匹配与深度图生成、轮廓提取、CNN 动作识别以及配套的 Python 训练脚本和已经调好的模型权重。整个流程是两个相机标定校正后得到视差图再把人物区域裁剪出来送进卷积网络识别十个动作训练记录显示最高准确率约 96%。适合做动作识别方向毕业设计的同学也适合想在老 OpenCV 版本上快速搭一套双目识别流程的开发者。注意它不是开箱即用的成品真正的核心是“C 推理 Python 训练”两半中间靠模型文件传递跑通之前得先把模式开关搞清楚。2. 项目文件脉络把 C 推理和 Python 训练的模块边界理清2.1 C 推理端文件职责解压后第一眼是一堆 .cpp/.h 文件加一个 matchAndRecognition.sln。我把 C 端按职责拆成几组方便你对号入座双目标定与校正StereoCalib.cpp / StereoCalib.h / stereoRectify_eg.cpp负责棋盘格标定、极线校正产出 calib_paras1.xml 和 cam_fundamental.xml。前者存左右相机内参、畸变系数和相对外参后者是基础矩阵。这两个文件是后续所有匹配步骤的前提。立体匹配StereoMatch.cpp / StereoMatch.h / StereoContour.cpp / FeatureMatch.cpp / FeatureMatch.h。StereoMatch 实现块匹配StereoContour 做轮廓提取FeatureMatch 处理特征点对齐。作者不是只调一个 BM 就完事而是把块匹配、特征点和轮廓信息结合起来生成深度图。点云分析PointCloudAnalyzer.cpp / PointCloudAnalyzer.h根据深度图生成三维点云用于目标空间位置换算。CNN 推理keras_model.cc / keras_model.h / test_run_cnn.cc / main.cc。keras_model 是 C 端模型加载器test_run_cnn.cc 是独立推理测试main.cc 是主流程通过宏 MODE 切换匹配与识别。工具类filesTool.cpp / filesTool.h负责遍历图片、读写输出结果。工程配置由 matchAndRecognition.vcxproj、filters 和 opencv249.props 组成props 是 OpenCV 2.4.9 的属性表。这里必须特别留意 cnn1.dumped它是 C 识别实际读取的模型权重格式不是 h5是经过序列化转换的数据。Python 训练得到的 whole_model.h5 和 fc_model.h5 不能直接被 C 端加载这个 dumped 文件是整个部署环节里最容易被忽略的依赖。2.2 Python 训练端与模型文件对照Script 文件夹里有 HumanActionRecognitionTrain.py 和 HumanActionRecognitionPredictAll.py前者负责训练后者对全部图片做批量预测。Subm 目录是 Python 端的批量识别结果Out 目录是 C 端每张图的识别结果。作者把整理好的图片数据放在 train 文件夹训练记录.txt 和训练记录96%.jpg 能直接看到训练过程。C 与 Python 的职责划分用一张表说清楚环节Python 端C 端传递介质数据准备train 目录整理好的图片Out 目录逐张输出结果文件系统模型训练HumanActionRecognitionTrain.py无whole_model.h5 / fc_model.h5模型部署无加载 cnn1.dumpeddumped 序列化文件批量推理HumanActionRecognitionPredictAll.pymain.cc / test_run_cnn.cc图片文件这个结构说明了一件事模型迭代放 Python部署推理放 C两者通过模型文件解耦。训练脚本里一旦改了输入尺寸或归一化方式C 端必须同步改否则推理准确率会直接崩掉。2.3 环境配置要点与 opencv249.props工程定位在 VS2015 OpenCV 2.4.9。opencv249.props 双击不会“自动安装”它只是把 include 和 lib 路径写进项目属性。我一般动手时先做两件事第一把 OPENCV_DIR 环境变量指向本地 OpenCV 的 build 目录第二打开 props 文件确认里面的相对路径和本机一致。OpenCV 2.4.9 的官方预编译库是 vc12VS2015 也能链接但 Debug 和 Release 的库文件名不同opencv_world249.lib 对应 Releaseopencv_world249d.lib 对应 Debug。搞混配置时链接阶段未必报错运行阶段会直接提示找不到 dll。另外 main.cc 里引用了 stereoRectify_eg 的相关调用说明立体校正部分参与主流程。跑识别之前最好先确认 calib_paras1.xml 已经存在。如果这个文件缺失程序会跳过校正深度图相关功能全部失效而且不容易排查。3. 核心实现链路从双目标定到 CNN 识别的完整流程3.1 双目标定参数文件的作用双目标定在这套代码里由 StereoCalib.cpp 完成。常见做法是准备 9x6 或 7x10 的棋盘格标定板采集 10 到 20 组左右相机同步帧检测角点后用 cv::stereoCalibrate 计算内参、畸变、旋转和平移结果写入 calib_paras1.xml。后续极线校正和立体匹配都会读取里面的 cameraMatrix、distCoeffs、R、T。参数上有三个注意点。标定板方格边长只影响物理尺度如果后续做点云或距离测量就必须按实际值设置标定图片分辨率和运行时图片不一致内参直接失效需要重新标定stereoRectify_eg.cpp 负责把左右图像校正到同一极线上这样匹配时只需要沿水平方向搜索能大幅降低计算量和误匹配率。3.2 MATCH 模式SGBM 立体匹配与深度图生成main.cc 里能看到这样的宏定义#define MODE RECOGNITION // MATCH 为匹配获取深度图RECOGNITION 为识别改成 MATCH 后主流程进入 StereoMatch.cpp。读入左右图按校正参数做重映射之后计算视差。我在工程里看到的匹配算法是 SGBM核心参数如下cv::StereoSGBM sgbm; sgbm.preFilterCap 63; sgbm.SADWindowSize 9; sgbm.P1 8 * 3 * sgbm.SADWindowSize * sgbm.SADWindowSize; sgbm.P2 32 * 3 * sgbm.SADWindowSize * sgbm.SADWindowSize; sgbm.minDisparity 0; sgbm.numberOfDisparities 64; sgbm.uniquenessRatio 10; sgbm.speckleWindowSize 100; sgbm.speckleRange 32; sgbm.disp12MaxDiff 1; sgbm.compute(leftGray, rightGray, disparity16S); disparity16S.convertTo(disparity32F, CV_32F, 1.0 / 16.0f);逻辑说明SGBM 返回的是定点视差数值是实际视差的 16 倍所以 convertTo 时要除以 16。SADWindowSize 表示匹配窗口窗口越大对弱纹理越稳但也越容易磨掉边缘细节。P1 和 P2 是平滑惩罚项P2 越大边缘越钝。uniquenessRatio 强制匹配唯一性低于该比例的点会被剔除。speckleWindowSize 和 speckleRange 用于去除零散噪点。调参策略我一般按这个顺序先固定 numberOfDisparities 为 64再加大 SADWindowSize如果深度图还是噪声多再调 uniquenessRatio 到 15 或 20。深度图拿到之后有两种用途一种是直接生成点云辅助人物分割另一种是把前景掩模交给识别模块。作者在 MATCH 模式下把视差和轮廓特征融合是因为纯视差图在人体边缘经常出现空洞加上轮廓信息才能补全人物区域。3.3 RECOGNITION 模式人体区域裁剪与 CNN 推理RECOGNITION 模式不依赖深度图走的是“前景分割—轮廓提取—裁剪缩放—模型推理”这条链。主流程大致是对左图做背景建模得到前景掩膜用轮廓查找画出人体区域外接框将人体区域裁剪并缩放到 CNN 输入尺寸调用模型前向计算拿到 10 个动作类别概率test_run_cnn.cc 的推理骨架可以简化成下面这样std::vectorfloat input preprocess(E:/test/0001.jpg, 96, 96); CNN model; model.load(cnn1.dumped); std::vectorfloat scores model.predict(input); int actionID std::max_element(scores.begin(), scores.end()) - scores.begin();逻辑说明scores 的下标就是类别序号argmax 得到预测动作。拿到 actionID 之后还需要对照类别列表才知道是“挥手”“下蹲”还是其他动作。这里最关键的是类别列表顺序必须和 HumanActionRecognitionTrain.py 里训练时定义的顺序完全一致错一位全盘皆错。3.4 训练数据与准确率的真实含义训练记录96%.jpg 上的 96% 很容易误导人。我对照 Subm 和 Out 两个结果目录发现作者是在自己整理好的固定测试图片上做验证也就是说这个数值是小规模测试集的准确率不是大规模基准结果。要用到自己的视频数据上必须确认场景背景和训练背景接近。十个动作的样本量如果不均衡高频类别如“站立”“行走”会更容易被识别低频动作“跳跃”“跌倒”这类样本少错判率明显偏高。训练脚本里还体现了类别标签的组织方式十个动作建立十个文件夹每张图片对应一个动作。Python 端批量识别后把结果写进 SubmC 端识别后写进 Out。两边结果不一致时优先查预处理而不是怀疑模型权重后面避坑章会详细说。4. 跑通一整套环境配置、MODE 切换与结果验证4.1 编译前的两个动作第一步设置环境变量 OPENCV_DIR例如指向 D:\OpenCV\build。第二步用 VS2015 打开 matchAndRecognition.sln。如果编译报头文件找不到检查工程属性里的 VC 目录。opencv249.props 内容典型如下PropertyGroup IncludePath$(OPENCV_DIR)\include;$(IncludePath)/IncludePath LibraryPath$(OPENCV_DIR)\x86\vc12\lib;$(LibraryPath)/LibraryPath /PropertyGroup逻辑说明x86\vc12\lib 是 OpenCV 2.4.9 官方预编译库的 32 位路径。如果你的 OpenCV 是 64 位库这里要改成 x64\vc12\lib。还要确认 props 被工程导入右键工程属性看“配置属性 → 常规 → 导入表”如果列表里没有 opencv249.props编译一定报链接错误。4.2 MODE 宏与核心参数调整主开关在 main.cc 里#define MODE RECOGNITION // MATCH 为匹配获取深度图RECOGNITION 为识别两个模式共享大部分代码差异在流程分支。改模式后必须重新编译。这里有个隐藏坑test_run_cnn.cc 如果自己也定义了一个 MODE 宏且与 main.cc 不一致两个入口文件的行为就会不同。调试时先确认引擎里当前编译的是哪个入口。模型相关参数一般定义成常量或宏常见值如下参数常见值说明INPUT_WIDTH / INPUT_HEIGHT96 / 128必须与训练脚本一致NUM_CLASSES10动作类别数MODEL_PATHcnn1.dumpedC 加载的权重路径OUTPUT_DIROut识别结果输出目录我建议在动手前先全局搜索这几个常量确认它们和你训练的模型匹配。如果训练脚本用了 128 输入尺寸而 C 端写死 96识别准确率会明显下滑但程序不会报错。4.3 单张与批量验证方法建议先跑 test_run_cnn验证模型能不能加载再回到 main 跑整套。步骤把一张测试图片放到 test 目录将启动项目设为 test_run_cnn按 CtrlF5 运行观察控制台输出的 10 个概率值和最终类别索引如果概率分布接近均匀说明预处理不一致或模型加载失败整体批量识别由 main.cc 主导结果逐张写入 Out 目录。每张图片对应一个 txt内容为 10 个类别概率取最大值下标即预测动作。Subm 里是 Python 端的批量结果把两个目录同名 txt 做 diff能快速定位 C 与 Python 端的处理差异在哪个环节。5. 避坑指南编译链接、老 OpenCV 与模型加载的典型翻车现场5.1 现象编译报“无法打开 opencv_world249.lib”原因opencv249.props 里的 LibraryPath 指向了不存在的路径或者 props 根本没有被工程导入。解决在系统环境变量中新建 OPENCV_DIR指向 OpenCV 的 build 目录再把工程属性里的 LibraryPath 改为 %OPENCV_DIR%\x86\vc12\lib。改完重新加载工程属性Clean 后重新生成。5.2 现象编译通过运行时提示缺 opencv_world249d.dll原因Debug 配置链接的是 opencv_world249d.lib运行时需要对应的 opencv_world249d.dllRelease 下则是 opencv_world249.dll。编译阶段链接 lib运行阶段加载 dll路径配置不一致就会出现这种“编译过了但跑不起来”的情况。解决把 OpenCV 的 bin 目录加入系统 PATH或者直接把对应 dll 复制到 exe 输出目录。我排这个错的时候习惯先看 exe 所在目录里有哪些 opencv 相关 dll再对比当前配置的 Debug/Release 类型多数情况是 Debug 工程用了 Release 的 dll。5.3 现象所有测试图片识别结果都指向同一个类别原因预处理步骤没有对齐。训练脚本里如果做了归一化“除以 255 再减均值”C 端只做了除以 255输入分布就完全不一样。还有一个频发原因OpenCV 读图默认通道顺序是 BGR而 CNN 训练时用的是 RGB忘记转换通道就会导致系统性错判。解决先跑 Python 端对同一张图的识别结果如果 Python 正常而 C 全错基本可以断定是预处理差异。我建议在两端各加一行代码把预处理后的中间图片保存下来逐像素对比比肉眼猜快得多。5.4 现象MATCH 模式生成的深度图全黑或满是噪点原因SGBM 参数视差范围和实际场景不匹配或者左右图没有先做极线校正就直接匹配。解决先确认 calib_paras1.xml 存在如果不存在先回跑 stereoRectify_eg 生成校正参数。然后逐个试 numberOfDisparities 从 64 到 256SADWindowSize 从 7 到 15speckleRange 调到 32 以上可以滤掉不少椒盐噪点。参数组合不要一次全改一次只动一个变量否则回不到原点。5.5 现象VS2015 中代码编辑器飘红编译却通过原因IntelliSense 数据库没有在工程加载时完整解析或者 include 路径在编辑器层面没有生效。这种飘红不影响编译产物。解决重新加载项目并重启 VS。想彻底消除就把 OpenCV 的 include 路径重新添加一遍再删除 .suo 和 .sdf 文件让 VS 重建索引。我自己遇到这个情况通常不理会只要编译输出干净就行。6. 最后一章把识别结果做稳的四个经验技巧6.1 先对齐双端预处理模型再强预处理不一致也会让准确率掉到个位数。每次拿到这类“Python 训练 C 推理”的工程第一步都做一次“双端对齐验证”同一张图分别用 Python 脚本和 C 工程输出概率看前三个类别是否一致。不一致就把两端的中间图像保存下来对比亮度、色偏、裁剪位置。常见差异点有三个resize 插值方式、颜色通道顺序、归一化均值与方差。6.2 用交叉验证替代一次性 96%训练记录里那个 96% 只能说明作者自建测试集上的表现不能当泛化能力。把十个动作的样本按类别打散做 5 折交叉验证看每个类别的召回率。哪个类别低就补哪种样本侧身、遮挡、不同尺度、不同背景。很多模型看似整体准确率高实际是高频动作拉高了平均值低频动作一塌糊涂。6.3 微调模型后必须重新导出 dumped 文件训练的最终产物是 whole_model.h5 和 fc_model.h5C 端读取的是 cnn1.dumped。如果你用自己的数据微调了模型训练结束后要跑一遍转换逻辑重新导出 dumped 文件再替换到工程目录。直接把 h5 文件改名为 dumped 是没有用的解析器按特定二进制格式读取不认扩展名。6.4 保留一份原始基线工程拿到压缩包后我的习惯是先复制一份命名为 baseline 的原始工程之后所有改动都在副本上做。调参、改预处理、换模型都记录在对比清单里出了问题直接对比 baseline 与被改版本比翻 git 历史更快。毕设项目尤其需要这个习惯因为交材料的时候要把每个参数改动的原因讲清楚。作者把训练脚本、C 推理、模型权重、图片数据四个部分都塞进压缩包完整度在毕业设计向的资源里算是难得的。如果你想少走弯路第一步从 test_run_cnn 开始而不是从 main 开始只有最小验证通过整套流程才有讨论的基础。后来每次处理带模型部署的 C 工程我都会强制自己先跑通最小验证再去看完整链路确认输入输出逐层对得上才敢动手改参数。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站