系列文章目录
提示:这里是该系列文章的所有文章的目录
第一章:(一)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:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。文章来源:https://www.toymoban.com/news/detail-564984.html
参考博客:海康工业相机采集图像的流程和采集模式分类文章来源地址https://www.toymoban.com/news/detail-564984.html
到了这里,关于(一)Qt下实现多个海康工业相机内触发采集回调取流显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!