openCV DNN 模块仅支持图像和视频的深度学习推理,它不支持训练。OpenCV DNN 模块的优点之一是它针对英特尔处理器进行了高度优化。在对实时视频进行推理以进行对象检测和图像分割应用程序时,我们可以获得良好的 FPS。OpenCV DNN 模块支持从不同框架加载不同模型,我们可以使用这些模型执行多种深度学习功能。大部分深度学习和计算机视觉任务支持,如以下列表:
图像分类。
物体检测。
图像分割。
文本检测和识别。
姿势评估。
深度评估。
人和人脸验证和检测。
等等
OpenCV DNN 模块支持许多流行的深度学习框架。以下是 OpenCV DNN 模块支持的深度学习框架。
Caffe
要将预训练的 Caffe 模型与 OpenCV DNN 一起使用,我们需要做两件事。一种是包含预训练权重的 model.caffemodel 文件。另一个是具有 .prototxt 扩展名的模型架构文件。它就像一个纯文本文件,具有类似 JSON 的结构,包含所有神经网络层的定义。
TensorFlow
为了加载预训练的 TensorFlow 模型,我们还需要两个文件。模型权重文件和protobuf文本文件包含模型配置。权重文件有一个 .pb 扩展名,它是一个包含所有预训练权重的 protobuf 文件。如果您之前使用过 TensorFlow,您会知道 .pb 文件是我们在保存模型并冻结权重后得到的模型检查点。模型配置保存在 protobuf 文本文件中,该文件具有 .pbtxt 文件扩展名。
Torch和 PyTorch
为了加载 Torch 模型文件,我们需要包含预训练权重的文件。通常,此文件具有 .t7 或 .net 扩展名。但是对于具有 .pth 扩展名的最新 PyTorch 模型,首先转换为 ONNX 是继续进行的最佳方式。转换为 ONNX 后,您可以直接加载它们,因为 OpenCV DNN 支持 ONNX 模型。但是opencv的dnn模块不支持读取pytorch的训练模型文件的。如果想要把pytorch的训练模型.pth文件加载到opencv的dnn模块里,需要先把pytorch的训练模型.pth文件转换到.onnx文件,然后才能载入到opencv的dnn模块里。
Darknet
OpenCV DNN 模块也支持著名的 Darknet 框架。如果他们使用了带有Darknet框架的官方 YOLO 模型。通常,要加载Darknet模型,我们需要一个具有 .weights 扩展名的模型权重文件。对于 Darknet 模型,网络配置文件是 .cfg 文件。
使用从 Keras 和 PyTorch 等不同框架转换为 ONNX 格式的模型
通常,在 PyTorch 或 TensorFlow 等框架中训练的模型可能无法直接与 OpenCV DNN 模块一起使用。在这些情况下,我们通常将模型转换为 ONNX 格式(开放式神经网络交换),然后可以按原样使用,甚至可以转换为其他框架支持的格式,如 TensorFlow 或 PyTorch。要加载 ONNX 模型,我们只需要 OpenCV DNN 模块的 .onnx 权重文件。
1.从磁盘加载类名文本文件并提取所需的标签。
2.从磁盘加载预训练的神经网络模型。
3.从磁盘加载图像并将图像准备为深度学习模型的正确输入格式。
4.通过模型前向传播输入图像并获得输出。
从磁盘加载预训练的ResNet模型:
使用 PyTorch深度学习框架训练的model_detect.onnx模型,模型已经转换为.onnx格式,
DNN 模块还提供了从特定框架加载模型的函数,如:readNetFromONNX():我们可以使用它来加载 ONNX 模型,只需要提供 ONNX 模型文件的路径。
cv::dnn::Net net = cv::dnn::readNetFromONNX("D://model//model_detect.onnx"); // 加载训练好的识别模型
读取图像并为模型输入做好准备:
i我们将像往常一样使用 OpenCV 的imread() 函数从磁盘读取图像。使用 DNN 模块加载的预训练模型不直接将读取的图像作为输入。在此之前我们需要做一些预处理。 opencv dnn 模块提供blobFromImage() 函数以便我们已正确的格式准备图像以输入模型
函数原型:
CV_EXPORTS void blobFromImage(InputArray image, OutputArray blob, double scalefactor=1.0,
const Size& size = Size(), const Scalar& mean = Scalar(),
bool swapRB=false, bool crop=false, int ddepth=CV_32F);
参数说明:
image:使用 imread() 函数读取的输入图像。
scalefactor:此值按提供的值缩放图像。它的默认值为 1,这意味着不执行缩放。
size:这是图像将被调整到的大小。
mean: 平均论点非常重要。这些实际上是从图像的 RGB 颜色通道中减去的平均值。这对输入进行了归一化,并使最终输入对不同的照明尺度保持不变
swapRB:是否交换第一个和最后一个通道,一般需要交换,因为imread()函数以BGR读取图像,而模型需要的是RGB格式。
crop:是否在调整大小后是否裁剪图像
ddepth:输出blob的深度。 选择CV_32F或CV_8U。 默认CV_32F。
cv::Mat image = cv::imread(fileName, cv::IMREAD_COLOR); // 读取图片
if (image.empty())
{
std::cout << fileName <<"image.empty";
return 0;
}
cv::namedWindow("image", WINDOW_NORMAL);
cv::imshow("image", image);
double inpWidth = image.cols;
double inpHeight = image.rows;
Scalar img_mean = Scalar(123.675, 116.28, 103.53);
Scalar img_std = Scalar(0.229, 0.224, 0.225);
double scale = 0.00390625f;
cv::Mat blob;
cv::dnn::blobFromImage(image, blob, scale, Size(inpWidth, inpHeight), img_mean, true, false);
if (img_std.val[0] != 0.0 && img_std.val[1] != 0.0 && img_std.val[2] != 0.0)
{
divide(blob, img_std, blob);
}
通过模型前向传播输入
net.setInput(blob); // 设置模型输入
cv::Mat predict = net.forward(); // 推理出结果
Point minLoc, maxcLoc;;
double min, max;
cv::minMaxLoc(predict, &min, &max, &minLoc, &maxcLoc);