C++ Qt 测试程序例程
本页介绍 OpenIVS 中 dlcv_infer_cpp_qt_demo 的启动步骤,以及模型加载、图像推理和结果读取代码。
获取代码
git clone https://github.com/dl-cv/OpenIVS.git
也可以在代码托管页面下载 ZIP 并解压。
Qt 例程源码位于 dlcv_infer_cpp_qt_demo,C++ 接口源码位于 dlcv_infer_cpp。
配置开发环境
安装依赖
使用 Windows x64,先安装高性能 SDK 套件,再准备以下开发组件:
| 软件 | 版本与组件 | 官方下载 |
|---|---|---|
| Visual Studio | Visual Studio 2022,安装“使用 C++ 的桌面开发”、MSVC v143 和 Windows SDK | Visual Studio 2022 Community 安装器 |
| Qt | Qt 6.10.2,选择 MSVC 2022 64-bit 组件 | Qt 官方在线安装器 |
| OpenCV | OpenCV 4.10.0 Windows x64 | OpenCV 官网 · 4.10.0 Windows 下载 |
Qt 安装目录使用 C:\Qt;OpenCV 解压后,将 opencv 文件夹放到 C:\opencv。
设置环境变量
- 在 Windows 搜索“编辑系统环境变量”,打开后单击“环境变量”。
- 在“用户变量”区域新建以下两个变量;已有同名变量时编辑其值:
| 变量名 | 变量值 |
|---|---|
Qt6_DIR | C:\Qt\6.10.2\msvc2022_64\lib\cmake |
OpenCV_DIR | C:\opencv\build\x64\vc16\lib |


- 单击“确定”保存各窗口。关闭已打开的 Visual Studio,再重新启动,使新进程读取环境变量。
完成安装与环境变量设置后,无需手工修改项目的头文件目录和库目录。
启动工程
- 打开
OpenIVS.sln,在顶部工具栏选择Release和x64。 - 在右侧“解决方案资源管理器”中找到
dlcv_infer_cpp_qt_demo,右键该项目,选择“设为启动项目”。 - 确认顶部启动项目名称为
dlcv_infer_cpp_qt_demo,按 F5 编译并运行。
C++ 程序使用 Release 编译,以获得最佳推理性能。Debug 编译的程序在多线程推理测速时会明显偏慢,这是正常现象。
在右侧找到红框标出的项目:

加载模型
在“选择显卡”中选择设备,单击左上角“加载模型”,选择模型文件:

MainWindow.cpp 中,按钮点击执行 onLoadModel,选择文件后调用 loadModelFromPath 创建模型。核心代码如下:
void MainWindow::onLoadModel()
{
QFileDialog dialog(this, "选择模型");
dialog.setNameFilter("AI模型 (*.dvt *.dvo *.dvr *.dvst);;所有文件 (*.*)");
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.exec();
loadModelFromPath(dialog.selectedFiles().front());
}
bool MainWindow::loadModelFromPath(const QString& selectedModelPath)
{
model_.reset();
const std::string modelPathLocal8 = selectedModelPath.toLocal8Bit().toStdString();
model_ = std::make_unique<dlcv_infer::Model>(modelPathLocal8, selectedDeviceId());
modelPath_ = selectedModelPath;
onGetModelInfo();
return true;
}
local8 是系统本地的 8 位编码。Windows 下 toLocal8Bit() 使用系统 ANSI 代码页:本例为 936(GBK);系统代码页为 65001 时返回 UTF-8。toStdString() 只保存字节,不转换编码。
加载成功后,左侧显示模型信息。
普通模型 .dvt 与流程模型 .dvst 使用相同的 dlcv_infer::Model 加载接口和 InferBatch 推理接口。
直接传入宽字符串路径,分别加载 DVT 与 DVST,默认使用第一张显卡:
dlcv_infer::Model dvtModel(LR"(D:\dlcv_demo\气球-语义分割_PLUS_s.dvt)");
dlcv_infer::Model dvstModel(LR"(D:\dlcv_demo\AOI-元件提取_PLUS_s.dvst)");
图像推理
使用气球语义分割模型与气球图片,按以下步骤运行:
- 加载
气球-语义分割_PLUS_s.dvt。 - 单击“打开图片推理”,选择
气球.jpg,程序立即推理。 - 左侧显示模型路径、图片路径、推理耗时及目标信息;右侧显示检测框与分割 mask。
- 单击“单次推理”可再次使用当前图片;调整
threshold后程序也会自动重新推理。

DVST 流程模型:AOI 元件提取
- 单击“加载模型”,选择
AOI-元件提取_PLUS_s.dvst。 - 单击“打开图片推理”,选择
1786969663716.jpg。 - 查看左侧对象列表和右侧检测框。该图片共检出 10 个对象:4 个字符、5 个二极管和 1 个电阻。
图片尺寸为 438 × 624 像素。字符检测框标出元件表面文字,二极管与电阻检测框标出对应元件。
标注文字重叠时,单击图像区,再连续按 - 缩小字体;+ 放大,0 恢复默认大小。
图像推理按钮代码
“单次推理”按钮调用 MainWindow.cpp 中的 onInfer,核心代码如下:
void MainWindow::onInfer()
{
cv::Mat image;
loadCurrentImage(image, false);
const cv::Mat inferImage = prepareImageForInference(image);
const dlcv_infer::Result output = model_->InferBatch({inferImage});
imageViewer_->setImageAndResults(image, output.sampleResults.front().results);
outputText_->setPlainText(formatResultText(output));
}
调用批量推理
以 1.bmp、2.bmp、3.bmp、4.bmp 四张图片的批量推理为例:先读取图片,组成图片列表 images,再调用 InferBatch。
以下代码放在 MainWindow.cpp 的按钮处理中,model_ 是已加载的模型;图片准备复用同文件已有的 prepareImageForInference。同批图片的宽、高须一致。
const cv::Mat image1 = prepareImageForInference(cv::imread("1.bmp"));
const cv::Mat image2 = prepareImageForInference(cv::imread("2.bmp"));
const cv::Mat image3 = prepareImageForInference(cv::imread("3.bmp"));
const cv::Mat image4 = prepareImageForInference(cv::imread("4.bmp"));
std::vector<cv::Mat> images = {image1, image2, image3, image4};
const dlcv_infer::Result output = model_->InferBatch(images);
output.sampleResults[0] 到 output.sampleResults[3] 依次对应四张输入图片,按下节代码读取各图片中的对象。
结果读取
AOI 图片的结果列表如下,左侧逐个显示类别、分数、检测框坐标与面积字段:

结构化结果定义在 dlcv_infer_cpp/dlcv_infer.h:
dlcv_infer::Result::sampleResults与输入图片列表顺序对应。dlcv_infer::SampleResult::results是单张图片的对象列表。dlcv_infer::ObjectResult保存类别、分数、检测框和 mask;withBbox和withMask表示对应数据是否存在。
按图片顺序遍历结果,再读取每张图片中的对象:
for (size_t i = 0; i < output.sampleResults.size(); ++i) {
const auto& sample = output.sampleResults[i];
std::cout << "image=" << i + 1 << std::endl;
for (const auto& object : sample.results) {
std::cout << "category=" << object.categoryName
<< ", score=" << object.score << std::endl;
if (object.withBbox && object.bbox.size() >= 4) {
std::cout << "bbox=["
<< object.bbox[0] << ", " << object.bbox[1] << ", "
<< object.bbox[2] << ", " << object.bbox[3] << "]"
<< std::endl;
}
}
}
流程模型的判定状态通过 dlcv_infer::Model::GetLastInspectionStatus 读取。存在有效判定状态时,窗口显示第一张图片的 OK/NG 与原因。
完整字段与接口说明参见 高性能 SDK 套件 - C++ 接口。
查看 JSON
单击“推理JSON”,程序对当前图片调用 InferOneOutJson,将格式化 JSON 显示到左侧文本区。
同一 AOI 图片中,第一个字符对象的主要 JSON 字段:
{
"category_id": 3,
"category_name": "字符90",
"score": 1,
"bbox": [
221,
375,
33,
50
],
"with_bbox": true,
"with_mask": false
}
bbox 按 [x, y, width, height] 读取,单位为输入图像像素。category_name 是类别名称,score 是分数,with_bbox 与 with_mask 表示对应数据是否存在。
void MainWindow::onInferJson()
{
cv::Mat image;
loadCurrentImage(image, false);
const auto result = model_->InferOneOutJson(prepareImageForInference(image));
outputText_->setPlainText(QString::fromStdString(result.dump(2)));
}
查看模型信息
单击“获取模型信息”,左侧显示当前模型的类别、输入形状和任务等信息。

GetModelInfo() 返回的主要字段如下:
{
"classes": [
"0",
"180",
"270",
"90"
],
"num_classes": 4,
"in_channels": 3,
"task_type": "分类",
"input_shapes": {
"input": {
"max_shape": [
4,
3,
640,
640
],
"min_shape": [
1,
3,
160,
160
],
"opt_shape": [
4,
3,
640,
640
]
}
},
"category_map": {
"字符90": "字符",
"二极管90": "二极管",
"0402电阻90": "0402电阻",
"IC90": "IC",
"LED90": "LED",
"三极管90": "三极管",
"电阻90": "电阻",
"电容90": "电容",
...... // 类别数量较多,以下内容省略
}
}
classes 和 num_classes 表示返回的类别列表及数量;in_channels 是输入通道数。input_shapes 的维度顺序为 [批量大小, 通道数, 高, 宽],min_shape、opt_shape、max_shape 分别给出最小、推荐和最大输入形状。category_map 给出类别名称到显示名称的映射。
获取并显示模型信息的代码:
void MainWindow::onGetModelInfo()
{
const auto info = model_->GetModelInfo();
outputText_->setPlainText(QString::fromStdString(info.dump(2)));
}
释放模型
“释放模型”按钮调用 onFreeModel,通过 reset() 销毁当前模型:
void MainWindow::onFreeModel()
{
model_.reset();
outputText_->setPlainText("模型已释放");
}
“释放所有模型”按钮调用 onFreeAllModels,同时执行全局释放接口:
void MainWindow::onFreeAllModels()
{
model_.reset();
dlcv_infer::Utils::FreeAllModels();
outputText_->setPlainText("所有模型已释放");
}
单击“释放模型”后,左侧显示“模型已释放”:
