blobFromImage 将图像转换为神经网络可以接受的输入格式(blob)

cv::Mat blobFromImage(
    cv::InputArray image,
    double scalefactor = 1.0, - 缩放因子   1.0/255.0:将像素值从 [0, 255] 归一化到 [0, 1]1.0:不进行缩放
    const cv::Size& size = cv::Size(),  - 目标尺寸
    const cv::Scalar& mean = cv::Scalar(), - 均值减除
    bool swapRB = false, - 交换红蓝通道
    bool crop = false, - 是否裁剪
    int ddepth = CV_32F - 输出深度
);
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>

using namespace std;
using namespace cv;
using namespace dnn;

int main()
{
    Mat image = imread("../76_jpg.rf.04aea58b8e629bb15b1c3b52d538d3a9.jpg");
    if (image.empty()) {
        cerr << "Error: Could not load image!" << endl;
        return -1;
    }

    cout << "原始图像信息:" << endl;
    cout << "尺寸: " << image.cols << "x" << image.rows << endl;
    cout << "通道数: " << image.channels() << endl;
    cout << "类型: " << image.type() << endl;

    const int INPUT_WIDTH = 640;
    const int INPUT_HEIGHT = 640;

    Mat blob = blobFromImage(image, 1.0, Size(INPUT_WIDTH, INPUT_HEIGHT), Scalar(), true, false);

    cout << "\nBlob信息:" << endl;
    cout << "维度数: " << blob.dims << endl;
    cout << "形状: [" << blob.size[0];
    for (int i = 1; i < blob.dims; i++) {
        cout << ", " << blob.size[i];
    }
    cout << "]" << endl;

    cout << "blob维度: " << blob.size[0] << "-" << blob.size[1]
        << "-" << blob.size[2] << "-" << blob.size[3] << endl;

    cout << "总元素数: " << blob.total() << endl;
    cout << "数据类型: " << blob.type() << endl;

  

    return 0;
}

在这里插入图片描述

读取文件onnx

#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>

using namespace std;
using namespace cv;
using namespace dnn;

int main()
{
	
	Net net = readNetFromONNX("../best.onnx");
	if (net.empty())
	{
		cout << "模型加载失败" << endl;
		return -1;
	}
	cout << "CNN模型模型加载成功" << endl;
	vector<string> layerNames = net.getLayerNames();
	cout << "模型的总层数:" << layerNames.size() << endl;
	for (int i = 0; i < layerNames.size(); i++)
	{
		string layerName = layerNames[i]; //层的名字
		int layerId = net.getLayerId(layerName);
		Ptr<Layer> layer = net.getLayer(layerId);
		cout << "第" << i + 1 << "层\t名称:" << layerName << "\t类型:" << layer->type << endl;
	}

	return 0;
}

读取Caffe 文件

Net net1 = readNetFromCaffe("1.prototxt", "1.caffemodel");

读取Tensorflow文件

Net net2 = readNetFromTensorflow("1.pb");

通用读取文件

  //一个参数:单文件模型
	Net net3 = readNet("resnet18-v1-7.onnx");
	//二个参数:双文件模型
	Net net4 = readNet("deploy.prototxt", "res10_300x300_ssd_iter_140000_fp16.caffemodel");

调用YOLOv11 目标检测

#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <fstream>
#include <algorithm>

using namespace std;
using namespace cv;
using namespace dnn;


vector<string> classes = { "cat", "chicken", "cow", "dog", "fox",
						   "goat", "horse", "person", "racoon", "skunk" };

struct Detection
{
	Rect bbox;
	float confidence;
	int class_id;
};



void processYOLODecectionOutput(const Mat&output,
	vector<Detection>&detections,
	float conf_threshold=0.25f,
	float iou_threshold=0.45f)
{
	//[1, 14, 8400]
	int mun_classess = 10;//类别
	int num_boxes = output.size[2];
	int data_length = output.size[1];

	//重新排列维度
	Mat output_mat = output.reshape(1, data_length);
	output_mat = output_mat.t();

	vector<Rect> boxs;
	vector<float> confidences;
	vector<int> class_ids;

	for (int i = 0; i < num_boxes; i++)
	{
		Mat row = output_mat.row(i);
		//提取边界
		float* data = row.ptr<float>();
		float cx = data[0];
		float cy = data[1];
		float w = data[2];
		float h = data[3];

		//找到最大类别概率
		Mat scores = row.colRange(4,4+ mun_classess);
		Point class_id_point;
		double max_class_score;
		minMaxLoc(scores,nullptr, &max_class_score, nullptr, &class_id_point);

		if (max_class_score > conf_threshold)
		{
			//转换为左上角坐标的宽和高
			float x = cx - w / 2.0f;
			float y = cy - h / 2.0f;

			boxs.emplace_back(x, y, w, h);
			confidences.push_back(max_class_score);
			class_ids.push_back(class_id_point.x);
		}

	}

	//非极大值抑制
	vector<int> indices;
	NMSBoxes(boxs, confidences, conf_threshold, iou_threshold, indices);

	for (int idx : indices)
	{
		Detection det;
		det.bbox = boxs[idx];
		det.confidence = confidences[idx];
		det.class_id = class_ids[idx];
		detections.push_back(det);
	}


}


class YOlODetection
{
private:
	Net net;
	float conf_threshold;
	float iou_threshold;
	int input_width;
	int input_height;
public:
	YOlODetection(const string& model_path, float con_thresh = 0.25f, float iou_thresh = 0.45,
		int width = 640, int height = 640)
	{
		net = readNet(model_path);
		conf_threshold = con_thresh;
		iou_threshold = iou_thresh;
		input_width = width;
		input_height = height;

		net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
	}


	void detect(const Mat& image,vector<Detection>& detection)
	{
		Mat blob;
		blobFromImage(image, blob, 1.0 / 255.0, Size(input_width, input_height), Scalar(), true,false);
		// 设置模型输入
		net.setInput(blob);

		//前向传播,推理
		vector<Mat> outputs;
		net.forward(outputs,net.getUnconnectedOutLayersNames());//getUnconnectedOutLayersNames获取最后一层的名字

		cout << "outputs" << outputs.size() << endl;
		Mat output = outputs[0]; // YOLOv8 ONNX 通常只有一个输出
		cout << "Output shape: [";
		for (int i = 0; i < output.dims; ++i) {
			cout << output.size[i];
			if (i < output.dims - 1) cout << ", ";
		}
		cout << "]" << endl;

		if (!output.empty())
		{
			processYOLODecectionOutput(output, detection, conf_threshold, iou_threshold);
		}

		//坐标转换为原图尺寸
		float x_factor = static_cast<float>(image.cols) / input_width;
		float y_factor = static_cast<float>(image.rows) / input_height;
		for (auto& det : detection)
		{
			det.bbox.x = static_cast<int>(det.bbox.x * x_factor);
			det.bbox.y = static_cast<int>(det.bbox.y * y_factor);
			det.bbox.width = static_cast<int>(det.bbox.width * x_factor);
			det.bbox.height = static_cast<int>(det.bbox.height * y_factor);

		}
	}
};

int main()
{
	YOlODetection detector("../best.onnx");
	Mat img = imread("../73_jpg.rf.4a2e03f9868a026dc1e1e7d166b59340.jpg");
	vector<Detection> detection;
	detector.detect(img, detection);

	//绘制
	for (const auto& det : detection)
	{
		rectangle(img,det.bbox,cv::Scalar(0,255,0),2);
		
		// 2. 构造标签文本:例如 "fox: 0.85"

		string label = format("%s: %.2f", classes[det.class_id].c_str(), det.confidence);


		// 3. 设置文字位置(在框的左上角)
		int x = det.bbox.x;
		int y = det.bbox.y - 10; // 文字在框上方,避免遮挡

		// 防止文字画到图像外面
		if (y < 15) y = det.bbox.y + 15; // 如果太靠上,就画在框内顶部

		// 4. 绘制文字
		putText(img, label, Point(x, y),FONT_HERSHEY_SIMPLEX,0.5,Scalar(0, 255, 0),      2);                     
	}

	imshow("Detection", img);
	waitKey(0);
	return 0;
}

在这里插入图片描述

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐