我使用带有 OpenCV 的 DNN 模块的 Basler 相机来运行 SSD 对象检测模型 (mobilenetv2_050_Opset18.onnx),并在 C++ 上启用 CUDA 支持。 Basler 相机正确捕获帧,OpenCV 正在处理图像,但 SSD 模型没有检测到任何物体,即使置信度阈值低至 0.0001 也没有检测到。
关键细节: 相机:Basler 相机配置为 640x480 分辨率和 BGR8 像素格式。
模型:SSD模型(mobilenetv2_050_Opset18.onnx)使用带有CUDA后端(DNN_BACKEND_CUDA)的OpenCV DNN模块加载。
CUDA 支持:使用 CUDA 编译的 OpenCV 和使用 cmake 的 cuDNN 支持。后端设置为使用 CUDA (net.setPreferableBackend(DNN_BACKEND_CUDA)),目标也设置为 CUDA (net.setPreferableTarget(DNN_TARGET_CUDA))。
问题:即使置信度阈值低至 0.0001,模型也未检测到任何物体。我已经验证相机和 CUDA 环境都按预期运行。
我的代码有什么问题?
#include <iostream>
#include <pylon/PylonIncludes.h>
#include <pylon/InstantCamera.h>
#include <pylon/BaslerUniversalInstantCamera.h>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/core/cuda.hpp>
using namespace Pylon;
using namespace GenApi;
using namespace std;
using namespace cv;
using namespace cv::dnn;
int main() {
PylonInitialize();
try {
// Basler camera setup
CInstantCamera camera(CTlFactory::GetInstance().CreateDevice(CDeviceInfo().SetSerialNumber("40432296")));
camera.Open();
// Configure the camera settings
INodeMap& nodemap = camera.GetNodeMap();
CIntegerParameter width(nodemap, "Width");
CIntegerParameter height(nodemap, "Height");
CEnumParameter pixelFormat(nodemap, "PixelFormat");
CFloatParameter exposureTime(nodemap, "ExposureTime");
CFloatParameter acquisitionFrameRate(nodemap, "AcquisitionFrameRate");
CIntegerParameter xOffset(nodemap, "OffsetX");
CIntegerParameter yOffset(nodemap, "OffsetY");
width.SetValue(640, IntegerValueCorrection_Nearest);
height.SetValue(480, IntegerValueCorrection_Nearest);
pixelFormat.SetValue("BGR8");
exposureTime.SetValue(15000.0);
acquisitionFrameRate.SetValue(5000.0);
xOffset.SetValue(0);
yOffset.SetValue(0);
CGrabResultPtr grabResult;
// Load SSD model
Net net = readNetFromONNX("mobilenetv2_050_Opset18.onnx");
net.setPreferableBackend(DNN_BACKEND_CUDA);
net.setPreferableTarget(DNN_TARGET_CUDA);
camera.StartGrabbing();
Mat frame;
while (camera.IsGrabbing()) {
camera.RetrieveResult(5000, grabResult, TimeoutHandling_ThrowException);
if (grabResult->GrabSucceeded()) {
uint8_t* buffer = (uint8_t*)grabResult->GetBuffer();
frame = Mat(grabResult->GetHeight(), grabResult->GetWidth(), CV_8UC3, buffer);
// Run SSD model
Mat blob = blobFromImage(frame, 1.0, Size(640, 480), Scalar(), true, false);
net.setInput(blob);
Mat detections = net.forward();
for (int i = 0; i < detections.size[2]; ++i) {
float confidence = detections.ptr<float>(0)[i * 7 + 2]; // Access confidence
if (confidence > 0.0001) {
int xLeftBottom = static_cast<int>(detections.ptr<float>(0)[i * 7 + 3] * frame.cols);
int yLeftBottom = static_cast<int>(detections.ptr<float>(0)[i * 7 + 4] * frame.rows);
int xRightTop = static_cast<int>(detections.ptr<float>(0)[i * 7 + 5] * frame.cols);
int yRightTop = static_cast<int>(detections.ptr<float>(0)[i * 7 + 6] * frame.rows);
rectangle(frame, Point(xLeftBottom, yLeftBottom), Point(xRightTop, yRightTop), Scalar(0, 255, 0), 2);
}
}
imshow("SSD Detection", frame);
if (waitKey(1) == 27) break; // Press 'ESC' to exit
}
}
camera.Close();
}
catch (const GenericException& e) {
std::cerr << "Error: " << e.GetDescription() << std::endl;
}
PylonTerminate();
return 0;
}
我是计算机视觉新手,我的目标是高性能(100+ fps)实时对象检测模型,以处理 640x480 等低分辨率素材。OpenCv 是一个好的起点,还是我应该跳过 C++ 并使用 Python更好的支持等。在对象检测模型性能方面,使用 C++ 是否比 Python 更有优势?
而不是
blobFromImage(frame, 1.0, Size(640, 480), Scalar(), true, false);
尝试
Mat blob = blobFromImage(frame, 1/127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), true, false);
net.setInput(blob);
Mat detections = net.forward();