上一篇分享了一下Yolov8的检测部署,
YOLOV8使用Opencv部署实现(C++版)-CSDN博客
这一篇再分享一下OBB旋转检测的部署,也是仅使用Opencv的dnn库的C++部署。
首先,在官网上下载好自己想要的obb预训练模型,转为onnx。也可以训练自己的模型,export为onnx。拿到onnx模型之后我们可以看看模型的输入输出。
以我自己的模型为例,输入为1*3*640*640,输出为1*7*8400。这里的输入是640*640的3通道图,输出可以看作是8400行7列的一个矩阵,每一行对应的值依次为预测框的中心坐标(x, y)和框的宽高w,h。 最后一个值是预测框对应的旋转弧度,范围为 -pi/4 到 3pi/4。剩下的两个值就是模型的类别了。在明确这些只的信息之后,我们就可以编写部署代码了。
首先,将onnx模型和图片加载,将图片归一化处理之后进行预测,得到secoutput的输出矩阵。
cv::Mat modelInput = input;
cv::Mat blob;
cv::dnn::blobFromImage(modelInput, blob, 1.0 / 255.0, modelShape, cv::Scalar(), true, false);
obbDetectNet.setInput(blob);
std::vector<cv::Mat> outputs;
obbDetectNet.forward(outputs, obbDetectNet.getUnconnectedOutLayersNames());
float* data = (float*)outputs[0].data;
cv::Mat secOutput = outputs[0];
可以看一下这个矩阵长什么样子:
可以对照上文的描述看看每一列对应的内容。根据输出的内容,我们可以建一个结构体,便于后面存储和使用。
struct ObbDetection
{
int class_id;
std::string className;
float confidence;
cv::Scalar color;
cv::Rect box;
float theta;
};
对模型类别的判断使用minMaxLoc函数比较方便,包括各分类网络也都是使用取输出向量的最大值来获取类别的。
minMaxLoc(scores, 0, &maxClassScore, 0, &class_id);
到这里,其实就很简单了,剩下的就是遍历每一行,并将对应的值放到自己的结构体里面,供后面画框的时候使用了。
for (unsigned long i = 0; i < result.size(); ++i)
{
result.class_id = class_ids[i];
result.confidence = confidences[i];
result.theta = theta[i];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(100, 255);
result.color = cv::Scalar(dis(gen),
dis(gen),
dis(gen));
result.className = obb_classes[result.class_id];
result.box = boxes[i];
obbDetection.push_back(result);
}
最后直接拿obbDetection里的值取用就行了。具体的预测结果跟训练数据处理和参数设置等也会有关系。