MIL转Mat失败版,优化opencv_onnx功能将输出结果按照原图片大小进行输出掩膜

This commit is contained in:
zjc-zjc-123 2024-11-26 14:35:53 +08:00
parent f83d435ddc
commit 6e0ad63020
8 changed files with 276 additions and 128 deletions

View File

@ -1,36 +1,34 @@
//
// Created by zjc on 24-11-19.
//
#include <opencv2/opencv.hpp>
#include <opencv2/dnn/dnn.hpp>
#include <iostream>
// 参数
const float CONFIDENCE_THRESHOLD = 0.2; // 置信度阈值
const float NMS_THRESHOLD = 0.2; // 非极大值抑制阈值
const int INPUT_WIDTH = 640; // 模型输入宽度
const int INPUT_HEIGHT = 640; // 模型输入高度
// Parameters
const float CONFIDENCE_THRESHOLD = 0.2; // Confidence threshold
const float NMS_THRESHOLD = 0.2; // Non-maximum suppression threshold
const int INPUT_WIDTH = 640; // Model input width
const int INPUT_HEIGHT = 640; // Model input height
// 检测结构体
// Detection structure
struct Detection {
cv::Rect box;
float confidence;
};
class Timer {
public:
Timer() : start_time(std::chrono::high_resolution_clock::now()) {}
// 重新启动定时器
// Restart the timer
void restart() {
start_time = std::chrono::high_resolution_clock::now();
}
// 获取并打印从上次启动到当前的时间差
// Get and print the time elapsed since last start
void printElapsedTime(const std::string& message) {
auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = end_time - start_time;
std::cout << message << ": " << elapsed.count() << " seconds" << std::endl;
// 重新启动定时器以供下次测量
// Restart the timer for the next measurement
start_time = end_time;
}
@ -38,195 +36,164 @@ private:
std::chrono::high_resolution_clock::time_point start_time;
};
// 在图像上绘制检测框
void drawDetections(cv::Mat& inputImage, const std::vector<Detection>& detections) {
for (const auto& detection : detections) {
cv::rectangle(inputImage, detection.box, cv::Scalar(0, 255, 0), 2);
std::string label = "Object: " + cv::format("%.2f", detection.confidence);
int baseLine;
cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
cv::rectangle(inputImage, cv::Point(detection.box.x, detection.box.y - labelSize.height - baseLine),
cv::Point(detection.box.x + labelSize.width, detection.box.y), cv::Scalar(0, 255, 0), cv::FILLED);
cv::putText(inputImage, label, cv::Point(detection.box.x, detection.box.y - baseLine), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0), 1);
}
}
// Function to resize and pad the input image
cv::Mat resizeAndPad(const cv::Mat& image, int targetWidth, int targetHeight, int& padTop, int& padLeft, float& scale, const cv::Scalar& padColor) {
int originalWidth = image.cols;
int originalHeight = image.rows;
// 计算缩放比例
// Calculate scaling factor
scale = std::min((float)targetWidth / originalWidth, (float)targetHeight / originalHeight);
// 缩放后的新尺寸
// New dimensions after scaling
int newWidth = static_cast<int>(originalWidth * scale);
int newHeight = static_cast<int>(originalHeight * scale);
// 缩放图像
// Resize the image
cv::Mat resizedImage;
cv::resize(image, resizedImage, cv::Size(newWidth, newHeight));
// 计算填充值
// Padding calculations
padTop = (targetHeight - newHeight) / 2;
int padBottom = targetHeight - newHeight - padTop;
padLeft = (targetWidth - newWidth) / 2;
int padRight = targetWidth - newWidth - padLeft;
// 在图像周围添加填充,使用灰色 (128, 128, 128) 填充
// Add padding around the image (using gray color)
cv::Mat paddedImage;
cv::copyMakeBorder(resizedImage, paddedImage, padTop, padBottom, padLeft, padRight, cv::BORDER_CONSTANT, padColor);
return paddedImage;
}
// Function to create an image with only detected regions filled as white (rest black) in the original image size
cv::Mat createDetectionMask(const cv::Mat& originalImage, const std::vector<Detection>& detections, float scale, int padTop, int padLeft) {
// Create a black image with the same size as the original image
cv::Mat mask = cv::Mat::zeros(originalImage.size(), CV_8UC1); // Single channel for black and white mask
// Fill the detected regions with white
for (const auto& detection : detections) {
// Rescale the coordinates from the padded image back to the original image
int x = static_cast<int>((detection.box.x - padLeft) / scale);
int y = static_cast<int>((detection.box.y - padTop) / scale);
int w = static_cast<int>(detection.box.width / scale);
int h = static_cast<int>(detection.box.height / scale);
// Ensure coordinates are within the bounds of the original image
x = std::max(0, std::min(x, originalImage.cols - 1));
y = std::max(0, std::min(y, originalImage.rows - 1));
w = std::min(w, originalImage.cols - x);
h = std::min(h, originalImage.rows - y);
cv::rectangle(mask, cv::Rect(x, y, w, h), cv::Scalar(255), cv::FILLED); // White color for detections
}
return mask;
}
int main() {
// 模型路径和图片路径
// Model and image paths
std::string modelPath = "C:\\Users\\zjc\\Desktop\\dimo_11.14.onnx";
std::string imagePath = "C:\\Users\\zjc\\Desktop\\dimo.bmp";
Timer timer1;
// 加载模型
cv::dnn::Net net = cv::dnn::readNetFromONNX(modelPath);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); // 设置为使用 CUDA 后端
net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); // 设置为在 GPU 上运行
timer1.printElapsedTime("Time to load the model");
// 读取输入图像
// Load the model
cv::dnn::Net net = cv::dnn::readNetFromONNX(modelPath);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); // Use CUDA backend
net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); // Run on GPU
timer1.printElapsedTime("Time to load the model");
// Read the input image
timer1.restart();
cv::Mat image = cv::imread(imagePath);
if (image.empty()) {
std::cerr << "Could not read the image: " << imagePath << std::endl;
return -1;
}
// 设置填充颜色为灰色
// Set padding color (gray)
cv::Scalar padColor(128, 128, 128);
// 预处理图像并添加填充
// Preprocess image and add padding
int padTop, padLeft;
float scale;
cv::Mat inputImage = resizeAndPad(image, INPUT_WIDTH, INPUT_HEIGHT, padTop, padLeft, scale, padColor);
// 显示调整和填充后的图像
// cv::imshow("Resized and Padded Image", inputImage);
// 预处理图像
// Prepare image for model input
cv::Mat blob = cv::dnn::blobFromImage(inputImage, 1 / 255.0, cv::Size(INPUT_WIDTH, INPUT_HEIGHT), cv::Scalar(0, 0, 0), true, false);
net.setInput(blob);
timer1.printElapsedTime("Time to preprocessing");
timer1.restart();
for(int j = 0; j <1; j++) {
// 推理模型
timer1.printElapsedTime("Time to preprocess image");
for (int j = 0; j < 1; j++) {
// Run inference
cv::Mat output = net.forward();
// 处理输出数据
// Process output data
std::vector<Detection> detections;
float* data = (float*)output.data;
for (int i = 0; i < 25200; ++i) {
float confidence = data[i * 6 + 4]; // 置信度
float confidence = data[i * 6 + 4]; // Confidence score
if (confidence >= CONFIDENCE_THRESHOLD) {
// 获取检测框并映射到图像坐标
// Remove the unnecessary multiplication
// Get bounding box coordinates
float cx = data[i * 6];
float cy = data[i * 6 + 1];
float w = data[i * 6 + 2];
float h = data[i * 6 + 3];
// If needed, adjust for differences between input image size and model input size
// Since they are the same in your case, this step can be omitted or kept as is
// Map to image coordinates
cx = cx * inputImage.cols / INPUT_WIDTH;
cy = cy * inputImage.rows / INPUT_HEIGHT;
w = w * inputImage.cols / INPUT_WIDTH;
h = h * inputImage.rows / INPUT_HEIGHT;
// Proceed with the rest of your code
int left = static_cast<int>(cx - w / 2);
int top = static_cast<int>(cy - h / 2);
int width = static_cast<int>(w);
int height = static_cast<int>(h);
// Ensure coordinates are within image bounds
left = std::max(0, std::min(left, inputImage.cols - 1));
top = std::max(0, std::min(top, inputImage.rows - 1));
width = std::min(width, inputImage.cols - left);
height = std::min(height, inputImage.rows - top);
// Add detection
// Add detection to vector
detections.push_back({cv::Rect(left, top, width, height), confidence});
}
}
// 非极大值抑制
// Non-Maximum Suppression
std::vector<int> indices;
std::vector<cv::Rect> boxes;
std::vector<float> scores;
for (const auto& detection : detections) {
boxes.push_back(detection.box);
scores.push_back(detection.confidence);
}
cv::dnn::NMSBoxes(boxes, scores, CONFIDENCE_THRESHOLD, NMS_THRESHOLD, indices);
std::cout << "Number of detections after NMS: " << indices.size() << std::endl;
if (indices.empty()) {
std::cout << "No boxes passed NMS." << std::endl;
}
for (int idx : indices) {
Detection detection = detections[idx];
std::cout << "Drawing box at: (" << detection.box.x << ", " << detection.box.y
<< "), width: " << detection.box.width << ", height: " << detection.box.height << std::endl;
drawDetections(inputImage, {detection});
}
std::vector<Detection> finalDetections;
for (int idx : indices) {
finalDetections.push_back(detections[idx]);
}
for (int i = 0; i < 25200; ++i) {
float confidence = data[i * 6 + 4];
if (confidence >= CONFIDENCE_THRESHOLD) {
// std::cout << "Detection " << i << ": confidence=" << confidence << std::endl;
}
}
// 绘制检测框并显示图像
drawDetections(image, finalDetections);
// Create the mask for the detected regions (matching original image size)
cv::Mat detectionMask = createDetectionMask(image, finalDetections, scale, padTop, padLeft);
// Show the mask
cv::imshow("Detection Mask", detectionMask);
// Save the result as an image
std::string savepath = "C:\\Users\\zjc\\Desktop\\suspect_mask.png";
cv::imwrite(savepath, detectionMask);
timer1.printElapsedTime("Time to run inference");
}
int depth = inputImage.depth(); // 图像数据类型
int channels = inputImage.channels(); // 通道数
// 判断图像深度和通道数,打印类型
std::string depthStr;
switch (depth) {
case CV_8U:
depthStr = "8-bit unsigned integer";
break;
case CV_8S:
depthStr = "8-bit signed integer";
break;
case CV_16U:
depthStr = "16-bit unsigned integer";
break;
case CV_16S:
depthStr = "16-bit signed integer";
break;
case CV_32S:
depthStr = "32-bit signed integer";
break;
case CV_32F:
depthStr = "32-bit floating point";
break;
case CV_64F:
depthStr = "64-bit floating point";
break;
default:
depthStr = "Unknown depth";
break;
}
std::cout << "Image Depth: " << depthStr << std::endl;
std::cout << "Number of Channels: " << channels << std::endl;
cv::imshow("Detections", inputImage);
cv::waitKey(0);
return 0;
}
//
}

View File

@ -5,9 +5,18 @@ add_library(Matrox
Matrox/template_matching.cpp
Matrox/mask.cpp
)
#
target_include_directories(Matrox PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
#
target_link_libraries(Matrox PUBLIC Qt6::Widgets ${OpenCV_LIBS} ${MIL_LIBS})
#CVDL
add_library(CVDL
CVDL/OnnxRunner.cpp
)
#
target_include_directories(CVDL PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
#
target_link_libraries(CVDL PUBLIC Qt6::Widgets ${OpenCV_LIBS} ${MIL_LIBS})

View File

@ -265,7 +265,7 @@ void TemplateMatcher::FindTemplates( const MIL_ID& inputImage, MIL_ID& outputIma
// TODO: Opencv ONNX runner,
// 1. 构建相应的模型加载和模型运行函数
// 1. 构建相应的模型加载和模型运行函数-
// 2. 在src里头添加另一个cvdl库专用于视觉深度学习
// 3. 添加一个类OnnxRunner

View File

@ -9,7 +9,8 @@
#include <vector>
#include <cmath>
#include <opencv2/core/mat.hpp>
#include "Mil.h"
#include <opencv2/opencv.hpp>
using namespace std;
/**
@ -121,4 +122,106 @@ void read_params_from_file(const std::string& filename, std::map<std::string, in
}
// 图片转换函数输入4096*1024*3的图片输出为(4096 / n_valves) * (1024 / n_merge_vertical) * 1
// Mat Mil2cvImage(MIL_ID &input_image,Mat) {}
#include "mil.h" // 包含 MIL 库的头文件
// cv::Mat milToMat(MIL_ID milImage, MIL_ID MilSystem) {
// // 获取图像的宽度、高度和像素格式
// int width, height, channels;
// MbufInquire(milImage, M_SIZE_X, &width); // 获取图像宽度
// MbufInquire(milImage, M_SIZE_Y, &height); // 获取图像高度
// MbufInquire(milImage, M_SIZE_BAND, &channels); // 获取图像通道数
//
// // 为图像数据分配内存
// byte* buf = new byte[width * height](); // 初始化内存
//
// // 如果是彩色图像,则转换为灰度图
// if (channels > 1) {
// MIL_ID grayscaleImage;
// // 分配一个新的灰度图像缓冲区
// MbufAlloc2d(MilSystem, width, height, 8 + M_UNSIGNED, M_IMAGE + M_PROC + M_DISP, &grayscaleImage);
// // 将彩色图像转换为灰度图
// MimConvert(milImage, grayscaleImage, M_RGB_TO_L);
// // 获取转换后的灰度图像数据
// MbufGet(grayscaleImage, buf);
// MbufFree(grayscaleImage); // 释放灰度图像缓冲区
// } else {
// // 如果本身是灰度图像,直接获取数据
// MbufGet(milImage, buf);
// }
//
// // 将数据封装成OpenCV Mat对象
// cv::Mat cvMat(height, width, CV_8UC1, buf);
// return cvMat;
// }
cv::Mat milToMat(MIL_ID milImage) {
// 获取图像的宽度、高度和像素格式
int width, height;
MIL_INT pixelFormat;
MbufInquire(milImage, M_SIZE_X, &width); // 获取图像宽度
MbufInquire(milImage, M_SIZE_Y, &height); // 获取图像高度
MbufInquire(milImage, M_TYPE, &pixelFormat); // 获取图像像素格式
// 判断像素格式并选择适当的数据类型
// MIL_INT 和 M_UINT8 是典型的像素格式OpenCV 处理不同的类型会有不同的实现
cv::Mat matImage;
if (pixelFormat == M_RGB)
{
// 如果是RGB图像
matImage = cv::Mat(height, width, CV_8UC3);
}
else
{// 如果是其他类型的图像,你需要根据实际格式进行调整
std::cerr << "Unsupported MIL image format!" << std::endl;
return matImage;
}
// 获取图像数据并复制到 OpenCV Mat
MbufGet(milImage, matImage.data); // 获取 MIL 图像数据并拷贝到 Mat 对象
return matImage;
}
void processImage(cv::Mat& img) {
// 1. 将图像从BGR转换到HSV色彩空间
cv::Mat hsv;
cv::cvtColor(img, hsv, cv::COLOR_BGR2HSV);
// 2. 定义绿色的HSV色彩范围
cv::Scalar lower_green(35, 40, 40); // 低阈值 (H, S, V)
cv::Scalar upper_green(85, 255, 255); // 高阈值 (H, S, V)
// 3. 根据绿色范围创建掩膜
cv::Mat green_mask;
cv::inRange(hsv, lower_green, upper_green, green_mask);
// 4. 使用形态学操作去除噪点,增强绿色区域
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
cv::morphologyEx(green_mask, green_mask, cv::MORPH_CLOSE, kernel);
// 5. 查找轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(green_mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 6. 创建一个黑色背景图像
cv::Mat result = cv::Mat::zeros(img.size(), img.type());
// 7. 遍历轮廓,找到矩形框并将其内部填充为白色
for (size_t i = 0; i < contours.size(); i++) {
// 通过近似多边形来检测矩形
std::vector<cv::Point> approx;
cv::approxPolyDP(contours[i], approx, cv::arcLength(contours[i], true) * 0.02, true);
// 如果是四边形,认为是矩形
if (approx.size() == 4) {
// 计算矩形的bounding box
cv::Rect rect = cv::boundingRect(approx);
// 仅在绿色区域内将矩形框填充为白色
cv::rectangle(result, rect, cv::Scalar(255, 255, 255), cv::FILLED);
}
}
// 8. 显示结果图像
cv::imshow("Processed Image", result);
cv::waitKey(0);
}

View File

@ -12,6 +12,7 @@
#include <fstream>
#include <string>
#include <map>
#include"opencv2/opencv.hpp"
#include <sstream>
// 声明全局变量(注意:这里只是声明,不是定义)
@ -38,5 +39,6 @@ MIL_ID convert_to_uint8(MIL_ID input_img);
std::wstring convert_to_wstring(const std::string& str);
void read_params_from_file(const std::string& filename, std::map<std::string, int>& params) ;
cv::Mat milToMat(MIL_ID MilImage);
void processImage(cv::Mat& img);
#endif //UTILS_H

View File

@ -9,16 +9,20 @@ target_link_libraries(test_color_range Matrox ${OpenCV_LIBS} ${MIL_LIBS})
# 2: template_template_matching
add_executable(test_template_matching
${CMAKE_CURRENT_SOURCE_DIR}/test_template_matching.cpp
)
${CMAKE_CURRENT_SOURCE_DIR}/test_template_matching.cpp)
# Matrox
target_link_libraries(test_template_matching Matrox ${OpenCV_LIBS} ${MIL_LIBS})
add_executable(test_mask
${CMAKE_CURRENT_SOURCE_DIR}/test_mask.cpp
)
# 3test_mask
add_executable(test_mask
${CMAKE_CURRENT_SOURCE_DIR}/test_mask.cpp)
# Matrox
target_link_libraries(test_mask Matrox ${OpenCV_LIBS} ${MIL_LIBS})
target_link_libraries(test_mask Matrox ${OpenCV_LIBS} ${MIL_LIBS})
# 4test_onnx
add_executable(test_onnx
${CMAKE_CURRENT_SOURCE_DIR}/test_onnx.cpp)
# Matrox
target_link_libraries(test_onnx Matrox ${OpenCV_LIBS} ${MIL_LIBS})

66
tests/test_onnx.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "vector"
#include"iostream"
#include"string"
#include"Matrox/utils.h"
#include"opencv2/opencv.hpp"
#define IMAGE_PATH MIL_TEXT("C:\\Users\\zjc\\Desktop\\8.bmp")
#define SAVE_PATH MIL_TEXT("C:\\Users\\zjc\\Desktop\\suspect.png")
// int main() {
// MIL_ID MilImage = M_NULL;
// MIL_ID MilApplication = M_NULL, MilSystem = M_NULL, MilDisplay = M_NULL;
//
// MappAllocDefault(M_DEFAULT, &MilApplication, &MilSystem, &MilDisplay, M_NULL,
// M_NULL);
// MbufRestore(IMAGE_PATH, MilSystem, &MilImage);
// cv::Mat opencvImage = milToMat(MilImage);
// imshow("opencv", opencvImage);
// // MosGetch();
//
// return 0;
// }
int main() {
MIL_ID MilApplication = M_NULL, MilSystem = M_NULL, MilDisplay = M_NULL;
MIL_ID MilImage = M_NULL;
// 初始化 MIL 应用程序、系统和显示
MappAllocDefault(M_DEFAULT, &MilApplication, &MilSystem, &MilDisplay, M_NULL, M_NULL);
if (MilApplication == M_NULL || MilSystem == M_NULL || MilDisplay == M_NULL) {
std::cerr << "MIL Initialization failed!" << std::endl;
return -1;
}
// 加载图像
MbufRestore(IMAGE_PATH, MilSystem, &MilImage);
if (MilImage == M_NULL) {
std::cerr << "Failed to load MIL image!" << std::endl;
MappFreeDefault(MilApplication, MilSystem, MilDisplay, M_NULL,M_NULL);
return -1;
}
// 转换并显示
cv::Mat opencvImage = milToMat(MilImage);
if (!opencvImage.empty()) {
cv::imshow("opencv", opencvImage);
cv::waitKey(0);
}
std:: string savepath="C:\\Users\\zjc\\Desktop\\suspect.png";
cv::imwrite(savepath,opencvImage);
// 释放资源
MbufFree(MilImage);
MappFreeDefault(MilApplication, MilSystem, MilDisplay, M_NULL,M_NULL); // 使用 MappFreeDefault 代替 MappFree
return 0;
}
// int main() {
// cv::Mat img = cv::imread("C:\\Users\\zjc\\Desktop\\suspect.png");
// if (img.empty()) {
// std::cout << "图像加载失败!" << std::endl;
// return -1;
// }
//
// // 处理图像
// processImage(img);
// }

View File

@ -19,8 +19,6 @@ MIL_ID MilApplication = M_NULL, MilSystem = M_NULL, MilDisplay = M_NULL;
int main() {
using namespace std;
std::map<std::string, int> params;
read_params_from_file("C:\\Users\\zjc\\Desktop\\config\\template_color_config.txt", params);
// Initialize MIL application
@ -61,6 +59,5 @@ int main() {
MbufFree(detection_result);
MbufFree(MilImage);
return 0;
}