使用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;
}
希望能帮助到你!