这段代码是使用YOLOv8模型进行目标检测的函数,下面将详细解释每个部分。
函数说明
/**
* @brief 检测图像中的目标。
*
* 此函数接收一帧图像,使用 YOLOv8 模型进行目标检测,并绘制检测结果。
*
* @param frame 输入的 cv::Mat 类型图像,表示待检测的图像帧。
*/
@brief
:简单描述了该函数的目的,即检测输入图像中的目标。@param
:说明了输入参数frame
是一个OpenCV的cv::Mat
类型,表示待处理的图像。
主要逻辑
1. 图像大小调整
int neww = 0, newh = 0, padw = 0, padh = 0;
// 调整输入图像的大小
cv::Mat simg = this->resize_img(frame, &neww, &newh, &padw, &padh);
resize_img
是一个自定义函数,用于调整输入图像大小以适应网络要求,同时计算出新的宽度、高度以及填充量(如果有的话)。
2. 创建Blob用于神经网络输入
// 创建用于神经网络输入的 blob
cv::Mat blob = cv::dnn::blobFromImage(simg, 1.0 / 255.0, cv::Size(this->inpHeight, this->inpWidth), cv::Scalar(0, 0, 0), true, false);
- 使用OpenCV DNN模块创建一个blob,该blob会被用作神经网络的输入。将图像归一化到[0,1]区间,并按指定尺寸调整(由成员变量
inpHeight
和inpWidth
决定)。
3. 设置网络输入并前向传播
// 设置网络输入
this->net.setInput(blob);
std::vector<cv::Mat> outs;
// 前向传播获取输出
this->net.forward(outs, this->net.getUnconnectedOutLayersNames());
- 将blob作为神经网络输入,通过前向传播得到输出,输出保存在向量
outs
中。
4. 获取提案数量和重塑输出矩阵形状
int numproposal = outs[0].size[2]; // 获取提案数量
int nout = outs[0].size[1]; // 获取输出维度
outs[0] = outs[0].reshape(0, nout); // 重塑输出矩阵形状
cv::transpose(outs[0], outs[0]); // 转置输出矩阵
- 从输出中获取提案数量和维度,然后重塑并转置以便后续处理。
5. 提取类别ID、置信度和边界框信息
std::vector<int> ids; // 存储类别 ID 的向量
std::vector<float> confs; // 存储置信度的向量
std::vector<cv::Rect> boxes; // 存储边界框的向量
float ratiow = (float)frame.cols / neww; // 原始宽度与新宽度的比例
float ratioh = (float)frame.rows / newh; // 原始高度与新高度的比例
float* pdata = (float*)outs[0].data;
for (int n = 0; n < numproposal; ++n)
{
float maxss = 0.0;
int idp = 0;
for (int k = 0; k < nout - 4; ++k)
{
if (pdata[k + 4] > maxss)
{
maxss = pdata[k + 4];
idp = k;
}
}
if (maxss >= this->confThreshold)
{
float cx = (pdata[0] - padw) * ratiow;
float cy = (pdata[1] - padh) * ratioh;
float w = pdata[2] * ratiow;
float h = pdata[3] * ratioh;
int left = int(cx - 0.5 * w);
int top = int(cy - 0.5 * h);
boxes.push_back(cv::Rect(left, top, int(w), int(h)));
confs.push_back(maxss);
ids.push_back(idp);
}
pdata += nout;
}
- 遍历每个提案,通过比较置信度来确定类别ID。如果最大置信度高于设定阈值,则计算相应边界框的位置并存储类别ID、置信度及边界框信息。
6. 非极大抑制(NMS)
// 应用非极大抑制(NMS)以消除冗余框
std::vector<int> indices;
cv::dnn::NMSBoxes(boxes, confs, this->confThreshold, this->nmsThreshold, indices);
- 使用非极大抑制算法消除冗余框,以减少重复检测到同一物体时产生的不必要的信息。
7. 绘制检测结果
// 绘制最终检测到的目标结果
for (int idx : indices)
{
this->drawPred(frame, boxes[idx], ids[idx], confs[idx]);
}
- 根据NMS后的索引绘制最终检测出的物体,将其显示在原始帧上。
总结
整体来看,这段代码实现了对给定图像的一次完整的目标检测流程,包括预处理、前向推理、后处理及可视化,是利用YOLOv8进行实时物体识别的重要组成部分。
内容由零声教学AI助手提供,问题来源于学员提问