目标检测是计算机视觉领域中的一个重要任务,其目的是检测图像或视频中存在的目标。YOLOV3是一种常用的目标检测算法,它基于深度学习技术,能够在高速和准确性之间取得良好的平衡。
本文将介绍如何使用OpenCV和YOLOV3实现对图片的目标检测,并提供详细的代码实现过程。
一、YOLOV3简介
YOLO(You Only Look Once)是一种基于深度学习的目标检测算法,具有较快的检测速度和较高的检测精度。YOLOV3是YOLO系列的最新版本,主要改进了网络结构和训练方式。YOLOV3采用Darknet-53作为特征提取网络,可以检测80个不同类别的目标。
二、OpenCV安装
在实现YOLOV3目标检测前,我们需要先安装OpenCV库。以下是在Windows操作系统上安装OpenCV的步骤:
-
下载并安装CMake。
-
下载OpenCV源码:opencv.org/releases/
-
解压下载的源码文件并创建一个名为build的文件夹。
-
运行cmake-gui.exe,设置源码路径和生成路径。
-
点击“Configure”按钮,并选择Visual Studio版本和Windows平台。
-
等待配置完成后,点击“Generate”按钮。
-
打开生成路径,并使用Visual Studio打开OpenCV.sln文件。
-
在Visual Studio中选择Build -> Build Solution。
-
完成编译后,在系统环境变量中添加OpenCV库的路径。
三、YOLOV3目标检测实现
以下是使用OpenCV和YOLOV3实现对图片的目标检测的代码:
# include <opencv2/opencv.hpp>
# include <opencv2/dnn.hpp>
# include <iostream>
using namespace cv;
using namespace dnn;
using namespace std;
int main(int argc, char** argv)
{
// 加载预训练模型和类别名称
String modelConfiguration = "yolov3.cfg";
String modelWeights = "yolov3.weights";
String classNamesFile = "coco.names";
// 加载类别名称
vector<String> classNamesVec;
ifstream classNamesFileIn(classNamesFile);
if (classNamesFileIn.is_open()){
string className = "";
while (std::getline(classNamesFileIn, className)){
classNamesVec.push_back(className);
}
}
// 加载模型配置和权重文件
Net net = readNetFromDarknet(modelConfiguration, modelWeights);
// 加载图片并进行预处理
Mat image = imread("test.jpg");
Mat blob;
blobFromImage(image, blob, 1 / 255.0, Size(416, 416), Scalar(), true, false);
// 将输入数据送入网络
net.setInput(blob);
// 获取输出层信息
vector<Mat> outs;
vector<String> outNames = net.getUnconnectedOutLayersNames();
net.forward(outs, outNames);
// 处理网络输出结果
vector<float> confidences;
vector<Rect> boxes;
vector<int> classIds;
for (size_t i = 0; i < outs.size(); i++){
float* data = (float*)outs[i].data;
for (int j = 0; j < outs[i].rows; j++, data += outs[i].cols){
Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
Point classIdPoint;
double confidence;
minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
if (confidence > 0.5){
int centerX = (int)(data[0] * image.cols);
int centerY = (int)(data[1] * image.rows);
int width = (int)(data[2] * image.cols);
int height = (int)(data[3] * image.rows);
int left =(int)(centerX - width / 2);
int top = (int)(centerY - height / 2);
confidences.push_back((float)confidence);
boxes.push_back(Rect(left, top, width, height));
classIds.push_back(classIdPoint.x);
}
}
}
// 进行非极大值抑制(NMS)
vector<int> indices;
NMSBoxes(boxes, confidences, 0.5, 0.4, indices);
// 绘制检测结果
for (size_t i = 0; i < indices.size(); i++){
int idx = indices[i];
Rect box = boxes[idx];
float confidence = confidences[idx];
int classId = classIds[idx];
// 绘制边框和类别名称
rectangle(image, box, Scalar(0, 0, 255), 2);
String label = classNamesVec[classId] + ": " + format("%.2f", confidence);
int baseline;
Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseline);
rectangle(image, Point(box.x, box.y - labelSize.height - baseline), Point(box.x + labelSize.width, box.y), Scalar(255, 255, 255), FILLED);
putText(image, label, Point(box.x, box.y - baseline), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0), 1);
}
// 显示检测结果
imshow("Object detection", image);
waitKey();
return 0;
}
在这个例子中,我们使用YOLOV3模型对一张图片进行目标检测。首先,我们加载预训练模型和类别名称,并使用OpenCV的dnn模块读取模型文件。然后,我们加载图片并进行预处理,将输入数据送入网络,获取输出层信息,并根据置信度阈值过滤检测结果。最后,我们使用非极大值抑制(NMS)算法对重叠的检测框进行去重,并在原始图片上绘制检测结果。