yolov5 海康相机 工业视觉 海康相机采集的图片使用yolov5进行目标检测,yolov5推理使用c++封装dll,调用海康sdk进行图像采集,支持MFC,qt,labview等调用

在工业现场抓取实时图像做目标检测,总得跟硬件和算法两头较劲。最近用海康工业相机+YOLOv5折腾了个方案,算是打通了从图像采集到实时推理的全流程。这里分享几个关键环节的实战经验,特别是C++封装这块的坑值得重点唠唠。

先说整体架构:海康相机SDK负责图像采集,YOLOv5模型用LibTorch做C++推理,封装成DLL后供上位机调用。实测在i7-10700+RTX3060环境下,1080p分辨率下能跑到35FPS,延迟控制在50ms以内。

yolov5 海康相机 工业视觉 海康相机采集的图片使用yolov5进行目标检测,yolov5推理使用c++封装dll,调用海康sdk进行图像采集,支持MFC,qt,labview等调用

图像采集部分的核心在于处理回调函数。海康的MV-CA016-10GC相机触发模式配置要注意缓冲区管理,这里直接上代码:

// 相机初始化核心代码片段
void InitCamera() {
    MV_CC_DEVICE_INFO_LIST stDeviceList;
    MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
    
    // 创建相机句柄
    MV_CC_CreateHandle(&m_handle, stDeviceList.pDeviceInfo[0]);
    
    // 注册图像数据回调
    MV_CC_RegisterImageCallBackForBGR(m_handle, GrabImageCallback, this);
    
    // 设置触发模式为硬触发
    MV_CC_SetEnumValue(m_handle, "TriggerMode", MV_TRIGGER_MODE_ON);
}

这里有个坑点:海康SDK返回的图像数据是BGR格式,而YOLOv5需要RGB输入。我们直接在回调函数里做转换,避免后续重复处理消耗资源。

推理部分的DLL封装是关键,接口设计要考虑跨平台调用。导出函数采用标准C接口:

// DLL接口定义示例
extern "C" __declspec(dllexport) 
DetectionResult* DetectObjects(
    unsigned char* img_data, 
    int width, 
    int height, 
    float conf_thresh=0.4) 
{
    static Detector detector("yolov5s.torchscript.pt");
    return detector.detect(img_data, width, height, conf_thresh);
}

这里用了LibTorch的TorchScript模型,推理核心代码注意内存管理:

// 推理核心代码简化版
std::vector<torch::jit::IValue> inputs;
inputs.push_back(tensor_img);

// 开启cuda异步推理
at::cuda::CUDAStream stream = at::cuda::getCurrentCUDAStream();
auto outputs = module_.forward(inputs).toTuple()->elements();

// 后处理使用CUDA加速
cudaMemcpyAsync(results, output.data_ptr(), ..., stream);

重点说三个优化点:

  1. 使用双缓冲队列隔离采集和推理线程
  2. 预处理集成GPU加速(OpenCV的cuda::GpuMat)
  3. 输出结果使用共享内存减少拷贝次数

在MFC/Qt调用时,注意UI线程与检测线程的交互。推荐使用事件驱动机制:

// Qt示例:信号槽触发检测
void MainWindow::onFrameReceived(const QImage &image) {
    QFutureWatcher<DetectionResult>* watcher = new QFutureWatcher<this>;
    connect(watcher, &QFutureWatcher::finished, [=](){
        DrawBoundingBoxes(watcher->result());
        watcher->deleteLater();
    });
    
    QFuture<DetectionResult> future = QtConcurrent::run(
        [=](){ return detector->detect(image); });
    watcher->setFuture(future);
}

实测中发现LabVIEW调用时需要特别注意内存对齐问题,建议在DLL中预分配固定大小的内存块,通过指针地址传递检测结果。

部署时遇到的典型问题:

  • 工业现场电磁干扰导致相机断连:增加心跳包机制
  • 模型误检:在预处理增加ROI区域限制
  • 内存泄漏:使用VLD工具定期检查

最后提个实用技巧——用NVIDIA Nsight Systems做性能分析,发现图像缩放操作竟占用了15%的耗时。改用cudaResize后整体帧率直接提升20%。这告诉我们:工业场景下的优化,每个毫秒都得抠。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐