Windows平台C集成PP-HumanSeg人像分割实战指南在视频会议、直播推流和图像处理应用中人像分割技术正成为提升用户体验的关键功能。本文将手把手带你实现从PaddlePaddle模型获取到ONNX Runtime C推理的全流程特别针对Windows平台下的开发痛点提供解决方案。1. 开发环境搭建与工具链配置1.1 基础软件准备推荐使用以下版本组合确保兼容性组件推荐版本下载方式Visual Studio2019/2022官方安装程序ONNX Runtime1.10.0NuGet包管理器或官网二进制OpenCV4.5.5预编译Windows包CMake3.20官网安装器关键配置步骤在VS中创建x64平台控制台项目通过NuGet添加Microsoft.ML.OnnxRuntime包配置OpenCV环境变量setx -m OPENCV_DIR D:\opencv\build setx -m PATH %PATH%;%OPENCV_DIR%\x64\vc15\bin1.2 模型转换工具链安装Python转换工具pip install paddle2onnx0.9.8 onnxruntime1.10.0注意建议创建独立的Python虚拟环境以避免依赖冲突2. PP-HumanSeg模型获取与转换2.1 模型下载与准备获取飞桨官方预训练模型git clone https://github.com/PaddlePaddle/PaddleSeg.git cd PaddleSeg/contrib/PP-HumanSeg python pretrained_model/download_pretrained_model.pyPP-HumanSeg提供多个变体性能对比如下模型版本输入尺寸FLOPs推理速度(CPU)PP-HumanSeg-Lite192x1920.14G28msPP-HumanSeg-Mobile398x2242.9G95msPP-HumanSeg-Server512x38411.5G210ms2.2 模型转换关键步骤动态图转静态图python ../../export.py \ --config configs/fcn_hrnetw18_small_v1_humanseg_192x192_mini_supervisely.yml \ --model_path pretrained_model/fcn_hrnetw18_small_v1_humanseg_192x192/model.pdparams \ --save_dir export_model/fcn_hrnetw18_small_v1_humanseg_192x192 \ --with_softmax \ --input_shape 1 3 192 192静态图转ONNXpaddle2onnx \ --model_dir ./export_model/fcn_hrnetw18_small_v1_humanseg_192x192/ \ --model_filename model.pdmodel \ --params_filename model.pdiparams \ --save_file onnx_model/model.onnx \ --opset_version 12常见转换问题处理遇到ValueError: not support input type错误时检查paddle2onnx版本输出节点异常时可尝试添加--enable_onnx_checker True参数3. ONNX Runtime C集成实战3.1 核心接口封装创建HumanSeg类封装推理逻辑class HumanSeg { public: HumanSeg(std::wstring model_path, int num_threads 1, std::vectorint64_t input_dims {1,3,192,192}); cv::Mat predict(cv::Mat src); private: Ort::Env env_; Ort::Session session_; std::vectorconst char* input_names_; std::vectorconst char* output_names_; };初始化ONNX Runtime会话HumanSeg::HumanSeg(std::wstring model_path, int num_threads, std::vectorint64_t input_dims) { Ort::SessionOptions options; options.SetIntraOpNumThreads(num_threads); options.SetGraphOptimizationLevel( GraphOptimizationLevel::ORT_ENABLE_EXTENDED); session_ Ort::Session(env_, model_path.c_str(), options); // 获取输入输出节点信息 Ort::AllocatorWithDefaultOptions allocator; input_names_ {session_.GetInputName(0, allocator)}; output_names_ {session_.GetOutputName(0, allocator)}; }3.2 图像预处理实现标准化处理流程cv::Mat HumanSeg::preprocess(cv::Mat image) { cv::Mat resized, normalized; // 调整尺寸 cv::resize(image, resized, cv::Size(192, 192)); // 归一化处理 resized.convertTo(normalized, CV_32F); cv::subtract(normalized, cv::Scalar(127.5, 127.5, 127.5), normalized); cv::divide(normalized, cv::Scalar(127.5, 127.5, 127.5), normalized); // 转换为NCHW格式 std::vectorcv::Mat channels; cv::split(normalized, channels); cv::Mat blob cv::dnn::blobFromImages({normalized}); return blob; }3.3 推理与后处理处理int64输出类型的技巧cv::Mat HumanSeg::predict(cv::Mat src) { // 预处理 cv::Mat blob preprocess(src); // 创建输入张量 auto memory_info Ort::MemoryInfo::CreateCpu( OrtArenaAllocator, OrtMemTypeDefault); Ort::Value input_tensor Ort::Value::CreateTensorfloat( memory_info, blob.ptrfloat(), blob.total(), input_dims_.data(), input_dims_.size()); // 执行推理 auto outputs session_.Run( Ort::RunOptions{nullptr}, input_names_.data(), input_tensor, 1, output_names_.data(), 1); // 处理int64输出 int64_t* mask_data outputs[0].GetTensorMutableDataint64_t(); cv::Mat mask(192, 192, CV_8UC1); for(int i0; i192*192; i) { mask.data[i] mask_data[i] ? 255 : 0; } // 还原原始尺寸 cv::resize(mask, mask, src.size()); return mask; }4. 性能优化与工程实践4.1 多线程加速方案// 在SessionOptions中设置并行线程数 options.SetIntraOpNumThreads(4); options.SetInterOpNumThreads(2); // 启用执行提供器如可用 Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CPU( options, true));4.2 内存管理最佳实践使用Ort::AllocatorWithDefaultOptions管理内存避免频繁创建/销毁Ort::Value对象对视频流处理实现帧缓存池4.3 实时视频处理实现void processVideoStream() { cv::VideoCapture cap(0); HumanSeg seg(Lmodel.onnx); while(true) { cv::Mat frame; cap frame; auto start std::chrono::high_resolution_clock::now(); cv::Mat mask seg.predict(frame); auto end std::chrono::high_resolution_clock::now(); // 显示FPS float fps 1e6 / std::chrono::duration_caststd::chrono::microseconds(end-start).count(); cv::putText(frame, std::to_string(fps), cv::Point(10,30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0,255,0), 2); // 应用掩码 cv::Mat result; frame.copyTo(result, mask); cv::imshow(Output, result); if(cv::waitKey(1) 27) break; } }4.4 常见问题排查指南模型加载失败检查ONNX文件路径是否为宽字符格式(L...)验证模型是否完整使用Netron查看输入输出不匹配// 打印输入输出维度信息 auto input_info session_.GetInputTypeInfo(0); auto output_info session_.GetOutputTypeInfo(0);性能瓶颈分析使用ONNX Runtime的Profiling功能单独测试预处理/推理/后处理各阶段耗时
保姆级教程:用C++和ONNX Runtime在Windows上跑通飞桨PP-HumanSeg人像抠图
发布时间:2026/6/10 14:51:27
Windows平台C集成PP-HumanSeg人像分割实战指南在视频会议、直播推流和图像处理应用中人像分割技术正成为提升用户体验的关键功能。本文将手把手带你实现从PaddlePaddle模型获取到ONNX Runtime C推理的全流程特别针对Windows平台下的开发痛点提供解决方案。1. 开发环境搭建与工具链配置1.1 基础软件准备推荐使用以下版本组合确保兼容性组件推荐版本下载方式Visual Studio2019/2022官方安装程序ONNX Runtime1.10.0NuGet包管理器或官网二进制OpenCV4.5.5预编译Windows包CMake3.20官网安装器关键配置步骤在VS中创建x64平台控制台项目通过NuGet添加Microsoft.ML.OnnxRuntime包配置OpenCV环境变量setx -m OPENCV_DIR D:\opencv\build setx -m PATH %PATH%;%OPENCV_DIR%\x64\vc15\bin1.2 模型转换工具链安装Python转换工具pip install paddle2onnx0.9.8 onnxruntime1.10.0注意建议创建独立的Python虚拟环境以避免依赖冲突2. PP-HumanSeg模型获取与转换2.1 模型下载与准备获取飞桨官方预训练模型git clone https://github.com/PaddlePaddle/PaddleSeg.git cd PaddleSeg/contrib/PP-HumanSeg python pretrained_model/download_pretrained_model.pyPP-HumanSeg提供多个变体性能对比如下模型版本输入尺寸FLOPs推理速度(CPU)PP-HumanSeg-Lite192x1920.14G28msPP-HumanSeg-Mobile398x2242.9G95msPP-HumanSeg-Server512x38411.5G210ms2.2 模型转换关键步骤动态图转静态图python ../../export.py \ --config configs/fcn_hrnetw18_small_v1_humanseg_192x192_mini_supervisely.yml \ --model_path pretrained_model/fcn_hrnetw18_small_v1_humanseg_192x192/model.pdparams \ --save_dir export_model/fcn_hrnetw18_small_v1_humanseg_192x192 \ --with_softmax \ --input_shape 1 3 192 192静态图转ONNXpaddle2onnx \ --model_dir ./export_model/fcn_hrnetw18_small_v1_humanseg_192x192/ \ --model_filename model.pdmodel \ --params_filename model.pdiparams \ --save_file onnx_model/model.onnx \ --opset_version 12常见转换问题处理遇到ValueError: not support input type错误时检查paddle2onnx版本输出节点异常时可尝试添加--enable_onnx_checker True参数3. ONNX Runtime C集成实战3.1 核心接口封装创建HumanSeg类封装推理逻辑class HumanSeg { public: HumanSeg(std::wstring model_path, int num_threads 1, std::vectorint64_t input_dims {1,3,192,192}); cv::Mat predict(cv::Mat src); private: Ort::Env env_; Ort::Session session_; std::vectorconst char* input_names_; std::vectorconst char* output_names_; };初始化ONNX Runtime会话HumanSeg::HumanSeg(std::wstring model_path, int num_threads, std::vectorint64_t input_dims) { Ort::SessionOptions options; options.SetIntraOpNumThreads(num_threads); options.SetGraphOptimizationLevel( GraphOptimizationLevel::ORT_ENABLE_EXTENDED); session_ Ort::Session(env_, model_path.c_str(), options); // 获取输入输出节点信息 Ort::AllocatorWithDefaultOptions allocator; input_names_ {session_.GetInputName(0, allocator)}; output_names_ {session_.GetOutputName(0, allocator)}; }3.2 图像预处理实现标准化处理流程cv::Mat HumanSeg::preprocess(cv::Mat image) { cv::Mat resized, normalized; // 调整尺寸 cv::resize(image, resized, cv::Size(192, 192)); // 归一化处理 resized.convertTo(normalized, CV_32F); cv::subtract(normalized, cv::Scalar(127.5, 127.5, 127.5), normalized); cv::divide(normalized, cv::Scalar(127.5, 127.5, 127.5), normalized); // 转换为NCHW格式 std::vectorcv::Mat channels; cv::split(normalized, channels); cv::Mat blob cv::dnn::blobFromImages({normalized}); return blob; }3.3 推理与后处理处理int64输出类型的技巧cv::Mat HumanSeg::predict(cv::Mat src) { // 预处理 cv::Mat blob preprocess(src); // 创建输入张量 auto memory_info Ort::MemoryInfo::CreateCpu( OrtArenaAllocator, OrtMemTypeDefault); Ort::Value input_tensor Ort::Value::CreateTensorfloat( memory_info, blob.ptrfloat(), blob.total(), input_dims_.data(), input_dims_.size()); // 执行推理 auto outputs session_.Run( Ort::RunOptions{nullptr}, input_names_.data(), input_tensor, 1, output_names_.data(), 1); // 处理int64输出 int64_t* mask_data outputs[0].GetTensorMutableDataint64_t(); cv::Mat mask(192, 192, CV_8UC1); for(int i0; i192*192; i) { mask.data[i] mask_data[i] ? 255 : 0; } // 还原原始尺寸 cv::resize(mask, mask, src.size()); return mask; }4. 性能优化与工程实践4.1 多线程加速方案// 在SessionOptions中设置并行线程数 options.SetIntraOpNumThreads(4); options.SetInterOpNumThreads(2); // 启用执行提供器如可用 Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CPU( options, true));4.2 内存管理最佳实践使用Ort::AllocatorWithDefaultOptions管理内存避免频繁创建/销毁Ort::Value对象对视频流处理实现帧缓存池4.3 实时视频处理实现void processVideoStream() { cv::VideoCapture cap(0); HumanSeg seg(Lmodel.onnx); while(true) { cv::Mat frame; cap frame; auto start std::chrono::high_resolution_clock::now(); cv::Mat mask seg.predict(frame); auto end std::chrono::high_resolution_clock::now(); // 显示FPS float fps 1e6 / std::chrono::duration_caststd::chrono::microseconds(end-start).count(); cv::putText(frame, std::to_string(fps), cv::Point(10,30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0,255,0), 2); // 应用掩码 cv::Mat result; frame.copyTo(result, mask); cv::imshow(Output, result); if(cv::waitKey(1) 27) break; } }4.4 常见问题排查指南模型加载失败检查ONNX文件路径是否为宽字符格式(L...)验证模型是否完整使用Netron查看输入输出不匹配// 打印输入输出维度信息 auto input_info session_.GetInputTypeInfo(0); auto output_info session_.GetOutputTypeInfo(0);性能瓶颈分析使用ONNX Runtime的Profiling功能单独测试预处理/推理/后处理各阶段耗时