使用mmdeploy框架C++预测mask并绘制最小外接矩形

目录

解决目标

逻辑思路

代码实现

第1部分

第2部分


解决目标

这段代码实现了,一个基于深度学习的图像检测程序。它使用mmdeploy框架,加载一个预训练的模型【实例分割模型】来检测图像中的物体。

逻辑思路

程序首先加载模型,然后,在指定的输入文件夹中,遍历所有JPG图像,对每张图像进行重复检测(默认2次),并绘制每个检测到的物体掩码的最大区域的最小外接矩形。这些矩形以绿色线条绘制在图像上,并且每次检测的结果都会保存到输出文件夹中。

同时,检测结果(包括图像名称、预测次数、标签ID和得分)会被记录到一个文本文件中。程序完成后,会提示用户按Enter键退出。

代码实现

我们有两部分代码。第一部分是每一次预测的结果框,都绘制到一个单独的图上。第二部分是,每一次预测结果都绘制到同一个图上。

第1部分

#include <filesystem>
#include <mmdeploy/detector.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include "utils/visualize.h"// 指定模型路径和输入图像文件夹路径
const std::string sModelPath = "path_to_model";
const std::string sInputFolderPath = "path_to_images";  // 替换为你的图像文件夹路径
const std::string sOutputFolderPath = "output_images";  // 输出图像文件夹路径
const float fDetectionThreshold = 0.9;
const std::string sDevice = "cpu"; // 根据实际情况选择设备(默认为cpu)
int iWarmUpCount = 20;  // 预热次数
int iRepetitions = 10000;  // 重复遍历次数// 加载图像
bool LoadImageFromFile(const std::string& sFilePath, cv::Mat& matImage) {matImage = cv::imread(sFilePath);if (matImage.empty()) {fprintf(stderr, "Failed to load image: %s\n", sFilePath.c_str());return false;}return true;
}// 查找最大轮廓
std::vector<cv::Point> GetLargestContour(const std::vector<std::vector<cv::Point>>& vecContours) {double dMaxArea = 0.0;std::vector<cv::Point> vecLargestContour;for (const auto& vecContour : vecContours) {double dArea = cv::contourArea(vecContour);if (dArea > dMaxArea) {dMaxArea = dArea;vecLargestContour = vecContour;}}return vecLargestContour;
}int main() {std::ofstream ofsResultFile("detection_results.txt"); // 输出结果的文本文件// 初始化性能分析器mmdeploy::Profiler profiler("/tmp/profile.bin");// 创建上下文环境mmdeploy::Context context;context.Add(mmdeploy::Device(sDevice));context.Add(profiler);// 创建检测器实例mmdeploy::Detector detector(mmdeploy::Model{ sModelPath }, context);// 获取所有jpg文件路径std::vector<std::string> vecImagePaths;for (const auto& entry : std::filesystem::directory_iterator(sInputFolderPath)) {if (entry.is_regular_file() && entry.path().extension() == ".jpg") {vecImagePaths.push_back(entry.path().generic_u8string());}}// 预热cv::Mat matImage;if (LoadImageFromFile(vecImagePaths[0], matImage)) { // 使用vecImagePaths的第一个元素for (int i = 0; i < iWarmUpCount; ++i) {detector.Apply(matImage);}} else {std::cerr << "Failed to load image during warm-up!" << std::endl;}// 遍历图像文件for (const auto& entry : std::filesystem::directory_iterator(sInputFolderPath)) {const std::string sInputImagePath = entry.path().generic_u8string();std::string sCurrentImageName = entry.path().filename().string();std::cout << "Predicting on image: " << sCurrentImageName << std::endl;cv::Mat matImage;if (!LoadImageFromFile(sInputImagePath, matImage)) {continue;}// 创建原图副本用于绘制外接矩形cv::Mat matColoredRects = matImage.clone();for (int iRepetition = 0; iRepetition < iRepetitions; ++iRepetition) {mmdeploy::Detector::Result result = detector.Apply(matImage);if (result.size() == 0) {std::cout << "Error: result.size() == 0" << std::endl;std::cin.get();}// 绘制外接矩形for (const mmdeploy_detection_t& detection : result) {if (detection.score > fDetectionThreshold && detection.mask) {cv::Mat matMaskImage(matImage.size(), CV_8UC1, cv::Scalar(0)); // 掩码图像cv::Rect rect(static_cast<int>(detection.bbox.left), static_cast<int>(detection.bbox.top),static_cast<int>(detection.bbox.right - detection.bbox.left),static_cast<int>(detection.bbox.bottom - detection.bbox.top));// 提取并调整掩码尺寸cv::Mat matMask(detection.mask->height, detection.mask->width, CV_8UC1, detection.mask->data);cv::resize(matMask, matMask, rect.size());matMask.copyTo(matMaskImage(rect));// 寻找轮廓std::vector<std::vector<cv::Point>> vecContours;cv::findContours(matMaskImage, vecContours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);// 找到最大轮廓std::vector<cv::Point> vecLargestContour = GetLargestContour(vecContours);// 计算最小外接矩形if (!vecLargestContour.empty()) {cv::RotatedRect rotatedRect = cv::minAreaRect(vecLargestContour);cv::Point2f points[4];rotatedRect.points(points);// 绘制矩形for (int j = 0; j < 4; j++) {cv::line(matColoredRects, points[j], points[(j + 1) % 4], cv::Scalar(0, 255, 0), 8);}}std::cout << "Image: " << sCurrentImageName << " Iteration " << iRepetition<< ", Label: " << detection.label_id << ", Score: " << detection.score << std::endl;ofsResultFile << "Image: " << sCurrentImageName << " Iteration " << iRepetition<< ", Label: " << detection.label_id << ", Score: " << detection.score << "\n";}}// 保存图像副本std::string sOutputImagePath = sOutputFolderPath + "/" + entry.path().stem().string() + "_iteration_" + std::to_string(iRepetition) + ".png";cv::imwrite(sOutputImagePath, matColoredRects);ofsResultFile << "----" << std::endl;}}ofsResultFile.close();std::cout << "Program finished. Press Enter to exit..." << std::endl;std::cin.get();return 0;
}

第2部分

#include "filesystem"
#include "mmdeploy/detector.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "utils/visualize.h"
#include <iostream>
#include <vector>
#include <string>
#include <fstream>// 配置文件路径和参数
const std::string cfgModelPath = "path_to_model";
const std::string cfgInputDir = "input_images";  // 指定图像文件夹路径
const std::string cfgOutputDir = "output_results";  // 结果输出文件夹路径
const float cfgThreshold = 0.9;
const std::string cfgDevice = "cpu"; // 设备选择(默认为cpu)
int cfgWarmups = 20;  // 预热次数
int cfgIterations = 10000;  // 重复次数// 图像加载函数
bool imgLoader(const std::string& file_path, cv::Mat& matrix) {matrix = cv::imread(file_path);if (matrix.empty()) {fprintf(stderr, "Error loading image: %s\n", file_path.c_str());return false;}return true;
}// 最大轮廓查找函数
std::vector<cv::Point> maxContourFinder(const std::vector<std::vector<cv::Point>>& contourList) {double largestArea = 0.0;std::vector<cv::Point> maxContour;for (const auto& contour : contourList) {double area = cv::contourArea(contour);if (area > largestArea) {largestArea = area;maxContour = contour;}}return maxContour;
}// 绘制颜色数组
const cv::Scalar drawColors[] = {cv::Scalar(0, 255, 0), // Greencv::Scalar(0, 0, 255), // Redcv::Scalar(255, 0, 0), // Bluecv::Scalar(0, 255, 255), // Cyancv::Scalar(255, 255, 0), // Yellowcv::Scalar(255, 0, 255), // Magentacv::Scalar(128, 0, 0), // Dark Redcv::Scalar(0, 128, 0), // Dark Greencv::Scalar(0, 0, 128), // Dark Blue// Additional colors can be added here
};int main() {std::ofstream outputLog("analysis_results.txt"); // 结果日志文件// 性能分析器初始化mmdeploy::Profiler perfProfiler("/tmp/perf_profile.bin");// 上下文环境配置mmdeploy::Context envContext;envContext.Add(mmdeploy::Device(cfgDevice));envContext.Add(perfProfiler);// 检测器实例化mmdeploy::Detector objectDetector(mmdeploy::Model{ cfgModelPath }, envContext);// 读取图像文件路径std::vector<std::string> filePaths;for (const auto& dirEntry : std::filesystem::directory_iterator(cfgInputDir)) {if (dirEntry.is_regular_file() && dirEntry.path().extension() == ".jpg") {filePaths.push_back(dirEntry.path().generic_u8string());}}// 预热操作cv::Mat warmupImg;if (imgLoader(filePaths[0], warmupImg)) { // 使用filePaths的第一个元素进行预热for (int i = 0; i < cfgWarmups; ++i) {objectDetector.Apply(warmupImg);}} else {std::cerr << "Failed to load image during warm-up!" << std::endl;}// 处理图像文件for (const auto& dirEntry : std::filesystem::directory_iterator(cfgInputDir)) {const std::string imgFilePath = dirEntry.path().generic_u8string();std::string imgFileName = dirEntry.path().filename().string();std::cout << "Processing image: " << imgFileName << std::endl;cv::Mat imageMatrix;if (!imgLoader(imgFilePath, imageMatrix)) {continue;}for (int iter = 0; iter < cfgIterations; ++iter) {// 绘制副本cv::Mat drawingCopy = imageMatrix.clone();mmdeploy::Detector::Result detectionResults = objectDetector.Apply(imageMatrix);if (detectionResults.size() == 0) {std::cout << "Error: Empty detection results" << std::endl;std::cin.get();}// 绘制检测结果for (const mmdeploy_detection_t& detection : detectionResults) {if (detection.score > cfgThreshold && detection.mask) {// 选择颜色cv::Scalar color = drawColors[iter % (sizeof(drawColors) / sizeof(cv::Scalar))];cv::Mat maskImage(imageMatrix.size(), CV_8UC1, cv::Scalar(0)); // 掩码图像初始化cv::Rect region(static_cast<int>(detection.bbox.left), static_cast<int>(detection.bbox.top),static_cast<int>(detection.bbox.right - detection.bbox.left),static_cast<int>(detection.bbox.bottom - detection.bbox.top));// 掩码调整cv::Mat mask(detection.mask->height, detection.mask->width, CV_8UC1, detection.mask->data);cv::resize(mask, mask, region.size());mask.copyTo(maskImage(region));// 轮廓查找std::vector<std::vector<cv::Point>> contourList;cv::findContours(maskImage, contourList, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);// 最大轮廓std::vector<cv::Point> largestContour = maxContourFinder(contourList);// 最小外接矩形计算if (!largestContour.empty()) {cv::RotatedRect minRect = cv::minAreaRect(largestContour);cv::Point2f rectPoints[4];minRect.points(rectPoints);// 绘制矩形for (int j = 0; j < 4; j++) {cv::line(drawingCopy, rectPoints[j], rectPoints[(j + 1) % 4], color, 8);}}std::cout << "Image: " << imgFileName << " Iteration " << iter<< ", Label: " << detection.label_id << ", Confidence: " << detection.score << std::endl;outputLog << "Image: " << imgFileName << " Iteration " << iter<< ", Label: " << detection.label_id << ", Confidence: " << detection.score << "\n";}}// 结果保存std::string resultImagePath = cfgOutputDir + "/" + "result_" + dirEntry.path().stem().string() + ".png";cv::imwrite(resultImagePath, drawingCopy);}outputLog << "----" << std::endl;}outputLog.close();std::cout << "Processing complete. Press Enter to exit..." << std::endl;std::cin.get();return 0;
}

希望能帮助到你!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/63550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java --- JVM编译运行过程

目录 一.Java编译与执行流程&#xff1a; 二.编译过程&#xff1a; 1.编译器&#xff08;javac&#xff09;&#xff1a; 2.字节码文件&#xff08;.class&#xff09;&#xff1a; 三.执行过程&#xff1a; 1.启动JVM&#xff08;Java虚拟机&#xff09;&#xff1a; 2…

【Makefile】编译日志之输出重定向符号 >

用法1 make all >& compilelog.txt make all > compilelog.txt这两个编译命令在功能上有一些细微的区别&#xff0c;主要在于标准输出和标准错误的处理方式。 make all >& compilelog.txt 这个命令会将标准输出&#xff08;stdout&#xff09;和标准错误&a…

使用 `typing_extensions.TypeAlias` 简化类型定义:初学者指南

使用 typing_extensions.TypeAlias 简化类型定义&#xff1a;初学者指南 什么是 TypeAlias&#xff1f;安装 typing_extensions示例代码&#xff1a;如何使用 TypeAlias示例 1&#xff1a;为简单类型定义别名示例 2&#xff1a;为复杂类型定义别名示例 3&#xff1a;结合 Union…

11.关于vim编辑器的简单配置

1. 说明 在linux系统中编辑文件内容的方式有很多种&#xff0c;比如直接在系统中暗中某些IDE&#xff0c;方便快捷&#xff0c;也可以直接在windows系统中编辑好文件后上传到linux系统中&#xff0c;这些方式对于编写内容较多的文件或者整个项目的文件还是非常适合的。不过有时…

qq空间管理小助手教程代码演示

headers {"Authorization": "Bearer YOUR_ACCESS_TOKEN","Content-Type": "application/json" }# 发布说说示例&#xff08; def post_moment(content):url "https://qzone-api.example.com/post_moment"data {"con…

pytest 的简单介绍

官方文档&#xff1a;pytest 文档 1. pytest 概述 pytest 是一个功能强大的 Python 测试框架&#xff0c;旨在简化单元测试和功能测试的编写与执行。它不仅支持简单的单元测试&#xff0c;还能进行更复杂的测试&#xff0c;如数据驱动的测试、并发测试等。pytest 支持自动化发…

【ArcGIS微课1000例】0133:二维建筑物依据高度生成三维模型

拓展阅读:【ArcGIS Pro微课1000例】0032:创建具有指定高程Z值的矢量数据 文章目录 一、二维面要素拉伸实现三维显示二、依据高度实现要素转3D一、二维面要素拉伸实现三维显示 打开ArcScene软件,加载实验配套数据0133.rar中的建筑物.shp数据,如下图: 数据属性表中的Z为建筑…

快速搭建SpringBoot3+Vue3+ElementPlus管理系统

快速搭建SpringBoot3Vue3管理系统 前端项目搭建&#xff08;默认开发环境&#xff1a;node20,Jdk17&#xff09;创建项目并下载依赖--执行以下命令 前端项目搭建&#xff08;默认开发环境&#xff1a;node20,Jdk17&#xff09; 创建项目并下载依赖–执行以下命令 创建项目 y…

力扣--LCR 134.Pow(x,n)

题目 实现 pow(x, n) &#xff0c;即计算 x 的 n 次幂函数&#xff08;即&#xff0c;xn&#xff09;。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000 示例 2&#xff1a; 输入&#xff1a;x 2.10000, n 3 输出&#xff1a;9.2610…

道可云人工智能元宇宙每日资讯|全国工商联人工智能委员会成立会议在南京举办

道可云元宇宙每日简报&#xff08;2024年12月5日&#xff09;讯&#xff0c;今日元宇宙新鲜事有&#xff1a; 全国工商联人工智能委员会成立会议在南京举办 全国工商联人工智能委员会成立会议日前在江苏省南京市举办。中央统战部副部长、全国工商联党组书记沈莹出席会议并讲话…

基于Qt的文字处理软件(二)

这期文章我们进行主窗口的一些函数的定义&#xff0c;同时导入一些文字处理软件的状态栏会用到的图标。下面图片是图标导入到项目后的一个示例&#xff0c;图标可以到阿里矢量图标库里面找到。 一、导入图标资源: 1.首先在项目目录的位置创建一个images的文件,然后将收集好的图…

如何使用WinCC DataMonitor基于Web发布浏览Excel报表文档

本文介绍使用 WinCC DataMonitor 的 "Excel Workbooks" 功能&#xff0c;通过 Excel 表格显示 WinCC 项目的过程值、归档变量值和报警归档消息。并可以通过 Web 发布浏览访问数据 1&#xff0e;WinCC DataMonitor是什么 ? DataMonitor 是 SIMATIC WinCC 工厂智能中…

element plus table组件多选获取数据id

首先给table加上 selection-change"handleSelectionChange"事件 示例 <el-table selection-change"handleSelectionChange" stripe:data"data?.slice((currentPage3 - 1) * pageSize3, currentPage3 * pageSize3)" style"width: 100%…

信号的捕捉

目录 一、内核态与用户态的切换 二、 sigaction 参数介绍​编辑 三、 signal 四、某个信号在正在捕捉期间&#xff0c;该信号不允许再次被递达 五、可重入与不可重入函数&#xff08;描述函数的特性&#xff09; 六、volatile关键字 七、SIGCHLD信号 一、内核态与用户态的…

UTS 2022 致命问题修复:达梦数据库,记录数支持100万条

UTS 数据传输系统升级说明 升级内容&#xff1a; 致命问题修复 达梦数据库作为数据源&#xff1a; 当单个时间戳的记录数超过 10,000 条时&#xff0c;系统读取可能出现问题&#xff0c;已针对该场景优化数据处理逻辑&#xff0c;提升读取性能与稳定性。当单个时间戳值的重复…

华为HCIE-Datacom认证笔试+实验考试介绍

华为HCIE数通认证考试是面向那些希望成为数通网络领域专家的人员&#xff0c;考试通常两部分&#xff1a;笔试和实验考试。 考试科目&#xff1a; HCIE-Datacom笔试考试内容&#xff1a; HCIE-Datacom V1.0考试覆盖数据通信领域路由交换高阶技术、企业网络架构全景、园区网络…

【Linux】NUMA如何梆核

在 NUMA&#xff08;非统一内存访问&#xff09;架构中&#xff0c;“绑核” 通常是指将特定的 CPU 核心&#xff08;或者 NUMA 节点&#xff09;与特定的内存区域绑定&#xff0c;以提高内存访问的局部性&#xff0c;减少跨节点的内存访问延迟。这个操作通常用于性能优化&…

vue实现页面自动滚动,鼠标悬浮暂停,移开继续

1、给div一个id <div class"kb_nei_new_left" id"chartsContainer">2、定义一个自动滚动的方法 autoSroll(Id) {// flag 为true时停止滚动var flag false;// 定时器var timer;function roll() {var h -1;timer setInterval(function () {flag …

可靠的人形探测,未完待续(I)

HI&#xff0c;there&#xff01;从紧张的项目中出来冒个泡&#xff01; 刚好想要验证一下mmWave在有人检测方面的应用&#xff0c;就看到了这个活动 - 瞌睡了有枕头属于是&#xff0c;活动策划好评&#xff01; 朋友曾关注汽车相关的技术领域&#xff0c;跟我吐槽过&#xff0…

Fastadmin地图插件在表单中的使用

表单中实现地图选择获取经纬度 1.Fastadmin后台安装地图选择插件地图位置(经纬度)选择插件 - 支持百度地图、高德地图、腾讯地图 – 基于ThinkPHP和Bootstrap的极速后台开发框架 2.腾讯地图开放平台后台创建应用创建KEY&#xff0c;配置逆地址解析额度。插件配置中配置腾讯地图…