(一)Qt下实现多个海康工业相机内触发采集回调取流显示

系列文章目录

提示:这里是该系列文章的所有文章的目录
第一章:(一)Qt下实现多个海康工业相机内触发采集回调取流显示
第二章:(二)Qt下多线程实现多个海康工业相机内触发采集回调取流显示



前言

在我之前所记录的关于海康工业相机的系列文章中 ,讲述的是使用外触发采集模式中的软触发,并采用超时机制获取一帧图片主动取流的,但在后期的测试过程中发现会出现失帧的的情况,所以决定采用内触发采集模式,并使用回调取流的方式来获取图像。本文主要讲述了在Qt下使用回调取流的方式来实现两个相机的显示,并结合相应的示例进行讲解,以便大家学习,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、环境配置

同样的,要在Qt下实现海康工业相机的采集,需要将相关SDK集成到项目中去,这里按照前文使用pri的方式将海康SDK添加到pro项目中去,具体的可查看该篇文章(一)Qt+OpenCV调用海康工业相机SDK示例开发,我的示例项目是MSVC 64位,所以在pro中也是添加了字符的设置:

#设置字符
contains( CONFIG,"msvc" ):QMAKE_CXXFLAGS += /source-charset:utf-8 /execution-charset:utf-8
contains( CONFIG,"msvc" ):QMAKE_CFLAGS +=/source-charset:utf-8 /execution-charset:utf-8

#海康SDK
include (./HikSdk/HikSdk.pri)

示例项目结构如下:
请添加图片描述

二、图像显示流程

海康工业相机使用回调取流的整个流程如下:
1.枚举所连接的相机信息列表,我这里进行了GIGE和USB类型的相机的枚举
2.可以获取相机序列号来指定相机设备并打开相机
3.使用SetEnumValue(“TriggerMode”,0)关闭外触发模式
4.在开启采集前进行回调函数的注册
5.开启采集,并在回调函数中将图像数据转换为QImage类型并显示到界面

//初始化相机对象,完成开启采集前的流程
void MainWindow::initWidget()
{
    //相机对象
    for(int i=0;i<2;i++)
    {
        m_myCamera[i] = new CMvCamera;
    }

    //枚举子网内所有设备
    memset(&m_stDevList,0,sizeof(MV_CC_DEVICE_INFO_LIST));
    int nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE,&m_stDevList);
    if(MV_OK != nRet)
    {
        LOGDEBUG<<"枚举相机设备失败!";
        return;
    }

    int deviceNum = m_stDevList.nDeviceNum;
    LOGDEBUG<<"deviceNum:"<<deviceNum;
    for(int i=0;i<deviceNum;i++)
    {
        MV_CC_DEVICE_INFO *pDeviceInfo = m_stDevList.pDeviceInfo[i];
        QString strSerialNumber = "";
        if(pDeviceInfo->nTLayerType == MV_GIGE_DEVICE)
        {
            strSerialNumber = (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber;
        }
        else if(pDeviceInfo->nTLayerType == MV_USB_DEVICE)
        {
            strSerialNumber = (char*)pDeviceInfo->SpecialInfo.stUsb3VInfo.chSerialNumber;
        }
        else
        {
            LOGDEBUG<<"警告,未知设备枚举!";
            return;
        }
        LOGDEBUG<<"i:"<<i<<"   strSerialNumber:"<<strSerialNumber;

        //根据相机序列号指定相机对象
        //if(strSerialNumber == "DA0333897")
        //{
        //    m_deviceInfo[0] = pDeviceInfo;
        //}
        //else if(strSerialNumber == "DA0424312")
        //{
        //    m_deviceInfo[1] = pDeviceInfo;
        //}

        //不指定
        m_deviceInfo[i] = pDeviceInfo;

        //打开相机
        int nRet = m_myCamera[i]->Open(m_deviceInfo[i]);
        if(MV_OK != nRet)
        {
            LOGDEBUG<<"i:"<<i<<"打开相机失败!";
            return;
        }

        //关闭触发模式
        nRet = m_myCamera[i]->SetEnumValue("TriggerMode",0);
        if(MV_OK != nRet)
        {
            LOGDEBUG<<"i:"<<i<<"关闭触发模式失败!";
            return;
        }

        //注册回调函数
        //nRet = m_myCamera[i]->RegisterImageCallBack(ImageCallback,this);    //单色相机
        //nRet = m_myCamera[i]->RegisterImageCallBackRGB(ImageCallback_1,this);   //彩色相机
        //if(MV_OK != nRet)
        //{
        //    LOGDEBUG<<"i:"<<i<<"注册回调函数失败!";
        //    return;
        //}
    }

    //注册回调函数
    nRet = m_myCamera[0]->RegisterImageCallBackRGB(ImageCallback_1,this);
    if(MV_OK != nRet)
    {
        LOGDEBUG<<"相机1注册回调函数失败!";
        return;
    }

    nRet = m_myCamera[1]->RegisterImageCallBackRGB(ImageCallback_2,this);
    if(MV_OK != nRet)
    {
        LOGDEBUG<<"相机2注册回调函数失败!";
        return;
    }
}

//回调函数1
void __stdcall MainWindow::ImageCallback_1(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser)
{
    LOGDEBUG<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz ")<<"回调函数1执行了";
    MainWindow* pThis = (MainWindow*)pUser;
    QImage showImage = QImage(pData, pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888);
    pThis->showImage(showImage,1);
}

三、示例完整代码

1.HikSdk.pri整个文件夹中有相应的头文件源文件及dll,可直接通过后文的下载链接进行下载,这里对修改的一处进行展示,其它的在这里就不做展示了(也可以在之前的海康系列文章中查看下)

//cmvcamera.h
// ch:注册彩色图像数据回调
int RegisterImageCallBackRGB(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser);

//cmvcamera.cpp
// ch:注册彩色图像数据回调
int CMvCamera::RegisterImageCallBackRGB(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser)
{
    return MV_CC_RegisterImageCallBackForRGB(m_hDevHandle, cbOutput, pUser);
}

2.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDateTime>
#include "HikSdk/cmvcamera.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void initWidget();

    void showImage(QImage showImage,int index);

private slots:
    void on_pb_start_clicked();
    void on_pb_stop_clicked();

private:
    static void __stdcall ImageCallback_1(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser);
    static void __stdcall ImageCallback_2(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser);

private:
    Ui::MainWindow *ui;

    CMvCamera *m_myCamera[2];             //相机对象
    MV_CC_DEVICE_INFO *m_deviceInfo[2];   //设备信息
    MV_CC_DEVICE_INFO_LIST m_stDevList;   //设备信息列表
};
#endif // MAINWINDOW_H

3.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->initWidget();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initWidget()
{
    //相机对象
    for(int i=0;i<2;i++)
    {
        m_myCamera[i] = new CMvCamera;
    }

    //枚举子网内所有设备
    memset(&m_stDevList,0,sizeof(MV_CC_DEVICE_INFO_LIST));
    int nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE,&m_stDevList);
    if(MV_OK != nRet)
    {
        LOGDEBUG<<"枚举相机设备失败!";
        return;
    }

    int deviceNum = m_stDevList.nDeviceNum;
    LOGDEBUG<<"deviceNum:"<<deviceNum;
    for(int i=0;i<deviceNum;i++)
    {
        MV_CC_DEVICE_INFO *pDeviceInfo = m_stDevList.pDeviceInfo[i];
        QString strSerialNumber = "";
        if(pDeviceInfo->nTLayerType == MV_GIGE_DEVICE)
        {
            strSerialNumber = (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber;
        }
        else if(pDeviceInfo->nTLayerType == MV_USB_DEVICE)
        {
            strSerialNumber = (char*)pDeviceInfo->SpecialInfo.stUsb3VInfo.chSerialNumber;
        }
        else
        {
            LOGDEBUG<<"警告,未知设备枚举!";
            return;
        }
        LOGDEBUG<<"i:"<<i<<"   strSerialNumber:"<<strSerialNumber;

        //根据相机序列号指定相机对象
        //if(strSerialNumber == "DA0333897")
        //{
        //    m_deviceInfo[0] = pDeviceInfo;
        //}
        //else if(strSerialNumber == "DA0424312")
        //{
        //    m_deviceInfo[1] = pDeviceInfo;
        //}

        //不指定
        m_deviceInfo[i] = pDeviceInfo;

        //打开相机
        int nRet = m_myCamera[i]->Open(m_deviceInfo[i]);
        if(MV_OK != nRet)
        {
            LOGDEBUG<<"i:"<<i<<"打开相机失败!";
            return;
        }

        //关闭触发模式
        nRet = m_myCamera[i]->SetEnumValue("TriggerMode",0);
        if(MV_OK != nRet)
        {
            LOGDEBUG<<"i:"<<i<<"关闭触发模式失败!";
            return;
        }

        //注册回调函数
        //nRet = m_myCamera[i]->RegisterImageCallBack(ImageCallback,this);    //单色相机
        //nRet = m_myCamera[i]->RegisterImageCallBackRGB(ImageCallback_1,this);   //彩色相机
        //if(MV_OK != nRet)
        //{
        //    LOGDEBUG<<"i:"<<i<<"注册回调函数失败!";
        //    return;
        //}
    }

    //注册回调函数
    nRet = m_myCamera[0]->RegisterImageCallBackRGB(ImageCallback_1,this);
    if(MV_OK != nRet)
    {
        LOGDEBUG<<"相机1注册回调函数失败!";
        return;
    }

    nRet = m_myCamera[1]->RegisterImageCallBackRGB(ImageCallback_2,this);
    if(MV_OK != nRet)
    {
        LOGDEBUG<<"相机2注册回调函数失败!";
        return;
    }

}

void MainWindow::showImage(QImage showImage,int index)
{
    QPixmap showPixmap = QPixmap::fromImage(showImage).scaled(QSize(250,200),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
    if(index == 1)
    {
        ui->lb_image_1->setPixmap(showPixmap);
    }
    else
    {
        ui->lb_image_2->setPixmap(showPixmap);
    }
}

void MainWindow::on_pb_start_clicked()
{
    //开始取图
    for(int i=0;i<2;i++)
    {
        int nRet = m_myCamera[i]->StartGrabbing();
        if (MV_OK != nRet)
        {
            LOGDEBUG<<"i:"<<i<<"开始取图失败!";
            return;
        }
    }
}

void MainWindow::on_pb_stop_clicked()
{
    //停止取图
    for(int i=0;i<2;i++)
    {
        int nRet = m_myCamera[i]->StopGrabbing();
        if (MV_OK != nRet)
        {
            LOGDEBUG<<"i:"<<i<<"停止取图失败!";
            return;
        }
    }
}

//回调函数1
void __stdcall MainWindow::ImageCallback_1(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser)
{
    LOGDEBUG<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz ")<<"回调函数1执行了";
    MainWindow* pThis = (MainWindow*)pUser;
    QImage showImage = QImage(pData, pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888);
    pThis->showImage(showImage,1);
}

//回调函数2
void __stdcall MainWindow::ImageCallback_2(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser)
{
    LOGDEBUG<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz ")<<"回调函数2执行了";
    MainWindow* pThis = (MainWindow*)pUser;
    QImage showImage = QImage(pData, pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888);
    pThis->showImage(showImage,2);
}

4.mainwindow.ui
在这里插入图片描述

四、下载链接

我的示例百度网盘链接:https://pan.baidu.com/s/1J35z54pcP5k0Ss8jlcIY1g
提取码:xxcj


总结

可以看到Qt下连接海康工业相机使用回调取流的整个流程就是这样的,注意一点就是要在打开相机后才能修改相机的各个参数,使用回调取流的方式,会根据你相机的帧率来获取图像的。在这个示例中,使用了两个相机,结果需要两个回调函数来获取对应的图像,如果相机个数更多个呢?那这样是不是就不太方便了,大家可以思考下如何改进下这个问题呢?


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考博客:海康工业相机采集图像的流程和采集模式分类

  • 10
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 在使用Qt加C++显示多个海康相机时,可以通过以下步骤实现: 1. 引入海康相机SDK:首先,在Qt工程中引入海康相机SDK,这可以通过将SDK的头文件和库文件添加到工程中来完成。 2. 创建相机实例:使用SDK提供的接口,创建一个或多个相机实例对象,每个实例都代表一个连接的相机。 3. 设置相机参数:可以通过相机实例对象设置相机的参数,如分辨率、曝光时间、白平衡等。 4. 打开相机连接:使用相机实例对象调用连接相机的函数,打开相机与电脑之间的连接通道。 5. 获取图像数据:通过相机实例对象调用获取图像数据的函数,获取相机实时采集的图像数据。 6. 图像处理与显示:对于每个相机获得的图像数据,可以进行图像处理操作,如图像增强、滤波等。然后,将处理后的图像数据显示Qt的窗口中。 7. 实时更新显示:通过一个Qt的定时器,不断更新图像显示窗口的内容,以实现相机的实时视频显示效果。 8. 释放资源:在程序退出或相机不再使用时,需要释放相机实例对象和关闭相机连接,以释放资源。 通过以上步骤,我们可以通过Qt加C++实现多个海康相机的显示,每个相机都可以实时显示采集到的图像。当然,具体实现的细节还需根据SDK和Qt库的具体使用方法进行调试和优化。 ### 回答2: Qt是一种跨平台的C++开发框架,而海康相机是指海康威视公司生产的监控相机设备。要使用Qt显示多个海康相机视频画面,首先需要使用海康SDK提供的API来获取相机的视频数据,然后使用Qt的图像显示组件来展示视频画面。 在Qt中,可以使用QThread类创建一个后台线程来与海康相机进行通信,并获取相机的视频数据。通过在后台线程中运行相机视频数据获取的逻辑,可以实现在主线程中不阻塞的情况下获取视频数据。 在获取到相机的视频数据后,可以将其转换为Qt支持的图像格式,例如QImage,然后使用Qt提供的图像显示组件,如QLabel或QGraphicsView,在界面上显示这些视频画面。 为了显示多个海康相机的视频画面,可以创建多个图像显示组件,然后分别将不同相机的视频数据分配给对应的图像显示组件。可以使用布局管理器来管理这些图像显示组件的位置和大小,以确保它们在界面上合理地排列。 此外,还可以使用一些Qt的UI控件来实现一些功能,例如选择不同相机进行预览、切换不同的预览布局、调整视频画面的参数等。 综上所述,通过使用Qt以及海康SDK提供的API,我们可以在界面上显示多个海康相机的视频画面。这样做可以有效地提高监控系统的可视化能力,并提供更好的用户体验。 ### 回答3: 要在Qt显示多个海康相机,可以使用Qt的多线程编程以及海康相机的SDK来实现。 首先,需要在Qt中创建一个多线程的类来处理海康相机的显示。在这个类中,可以使用海康相机的SDK提供的接口来初始化相机,并设置采集参数、图像帧率等。接着,可以通过调用相机的采集函数来获取图像数据。获取到图像数据后,可以通过Qt的图像显示控件来显示图像,例如QLabel或QGraphicsView。 在主线程中,可以创建多个海康相机的实例,并分别将它们传递给多线程类的对象。这样每个相机都在独立的线程中运行,可以同时显示多个相机的图像。 另外,为了避免多个相机的图像显示混乱,可以为每个相机设置一个独立的图像显示控件,在多线程类中将图像数据显示到对应的控件中。 需要注意的是,海康相机的SDK一般提供了基于C的编程接口,可以通过在Qt中使用外部C函数来调用这些接口。此外,为了确保相机的正常运行,可能需要在不同相机之间进行同步操作,例如设置采集帧率一致或者设置触发模式。 综上所述,要在Qt显示多个海康相机,需要使用多线程编程和海康相机的SDK来实现相机图像的采集显示。通过将相机实例传递给多线程类对象,可以在独立的线程中显示每个相机的图像。同时,为了避免图像混乱,可以为每个相机设置独立的图像显示控件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值