使用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…

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…

【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…

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

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

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

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

信号的捕捉

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

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

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

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

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

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

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

如何防范顶级应用程序安全威胁

如今的网络攻击数量是五年前的两倍多。因此&#xff0c;掌握最新的应用程序安全威胁对于防止数据泄露、经济损失和声誉受损至关重要。您还需要实施强大的安全实践&#xff0c;以保护应用程序免受最常见和最危险的威胁。 顶级应用程序安全威胁......以及如何防范这些威胁 1. 注…

2024年超大跨径钢结构桥梁创新技术论坛暨钢桥联盟年度工作会议顺利召开

12月5日&#xff0c;由中交公路规划设计院有限公司、装配化钢结构桥梁产业技术创新战略联盟主办&#xff0c;保利长大工程有限公司、中交第二航务工程局有限公司、中交第二公路工程局有限公司、中交路桥建设有限公司、中交西安筑路机械有限公司、南京现代综合交通实验室、巨力锁…

配置服务器的免密登录

在服务器中配置别名和免密登录 如果没有生成过公钥和密钥 ssh-keygen然后就生成了公钥和密钥&#xff0c;下一步进入.ssh文件夹 cd .ssh/可以看到文件夹中会多出来三个文件 id_rsa&#xff1a;密钥id_rsa.pub&#xff1a;公钥known_hosts&#xff1a;A通过ssh首次连接到B&am…

计算c++11 lambada表达式的大小

lambada表达式是什么? 详解&#xff1a;lambada表达式详解 我们知道lambada其实是一个匿名函数 &#xff0c; 它属于 可调用对象 类型。在 C 中&#xff0c;lambda 表达式会生成一个隐式定义的类&#xff0c;这个类重载了 operator()&#xff0c;使得该对象可以像函数一样被…

ARMv8-A MacOS调试环境搭建

文章目录 简介安装qemu交叉编译工具链C语言插件 gdb调试测试代码添加调试配置 JLink 调试树莓派 简介 本节主要介绍基于Visual Studio Code在MacOS下调试环境的搭建&#xff0c;Linux发行版上的过程也类型&#xff0c;它主要使用到以下工具链&#xff1a; aarch64 架构的交叉…

React - useActionState、useFormStatus与表单处理

参考文档&#xff1a;react18.3.1官方文档 一些概念&#xff1a; React 的 Canary 和 Experimental 频道是 React 团队用于发布和测试新功能的渠道。 useActionState useActionState 是一个可以根据某个表单动作的结果更新 state 的 Hook。 const [state, formAction, isPe…

解决docker拉取镜像失败问题

下载镜像 [roottest-server-01 ~]# docker pull nginx Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": read tcp 192.168.40.180:37356->54.227.20.253:443: read: connection reset by peer报错&#xff1a;E…

java Random随机数

Randoms是什么 在Java中&#xff0c;Random类是用于生成伪随机数的工具。它位于java.util包中。以下是一些使用Random类生成不同类型的随机数的方法&#xff1a; 1 创建 Random 类的实例 2 生成一个随机的int值&#xff08;范围从Integer.MIN_VALUE到Integer.MAX_VALUE&#…

ollama-webui - Ollama的ChatGPT 风格的 Web 界面

更多AI开源软件&#xff1a; 发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI小众AI&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型。收录了AI搜索引擎&#xff0c;AI绘画工具、AI对话聊天、AI音频工具、AI图片工具、AI视频工具、AI内容检测、AI法律助手、…