系列文章目錄
提示:這里是該系列文章的所有文章的目錄
第一章:(一)Qt下實(shí)現(xiàn)多個(gè)??倒I(yè)相機(jī)內(nèi)觸發(fā)采集回調(diào)取流顯示
第二章:(二)Qt下多線(xiàn)程實(shí)現(xiàn)多個(gè)??倒I(yè)相機(jī)內(nèi)觸發(fā)采集回調(diào)取流顯示
前言
在本系列的上一篇文章中,我們講述了實(shí)現(xiàn)海康工業(yè)相機(jī)的連接,采用內(nèi)觸發(fā)采集模式,并使用回調(diào)取流的方式來(lái)獲取圖像并實(shí)現(xiàn)界面上兩個(gè)相機(jī)的顯示,但是發(fā)現(xiàn)在多個(gè)相機(jī)下要寫(xiě)多個(gè)回調(diào)函數(shù)是不太合適的,所以在這里增加了一個(gè)線(xiàn)程類(lèi),使用多線(xiàn)程的方式對(duì)前文的demo進(jìn)行優(yōu)化,這里對(duì)該示例進(jìn)行講解,以便大家學(xué)習(xí),如有錯(cuò)誤之處,歡迎大家批評(píng)指正。
項(xiàng)目效果
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
一、創(chuàng)建線(xiàn)程類(lèi)
在HikSdk文件夾下添加GrabImgThread類(lèi),在類(lèi)的構(gòu)造函數(shù)中賦值相應(yīng)的相機(jī)號(hào),以區(qū)分多個(gè)相機(jī),在線(xiàn)程類(lèi)中設(shè)置相機(jī)指針和相機(jī)回調(diào)函數(shù),以及添加一個(gè)signal_imageReady信號(hào)
//回調(diào)函數(shù)
void __stdcall GrabImgThread::ImageCallback(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser)
{
LOGDEBUG<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz ")<<"回調(diào)函數(shù)執(zhí)行了";
GrabImgThread* pThread = static_cast<GrabImgThread *>(pUser);
//創(chuàng)建QImage對(duì)象
QImage showImage = QImage(pData,pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888);
//發(fā)送信號(hào),通知主界面更新圖像
emit pThread->signal_imageReady(showImage,pThread->m_cameraId);
}
修改后的項(xiàng)目結(jié)構(gòu)如下:
二、關(guān)聯(lián)線(xiàn)程對(duì)象
圖像顯示流程與之前還是一樣的,只不過(guò)在這里將相機(jī)對(duì)象與線(xiàn)程對(duì)象進(jìn)行了關(guān)聯(lián),在初始化的按鈕槽函數(shù)中注冊(cè)了線(xiàn)程對(duì)象中的回調(diào)函數(shù),開(kāi)啟采集后線(xiàn)程對(duì)象通過(guò)信號(hào)與槽的方式將回調(diào)函數(shù)中的圖像數(shù)據(jù)發(fā)送到主界面進(jìn)行顯示
for(int i=0;i<2;i++)
{
//相機(jī)對(duì)象
m_myCamera[i] = new CMvCamera;
//線(xiàn)程對(duì)象
m_grabThread[i] = new GrabImgThread(i);
connect(m_grabThread[i],SIGNAL(signal_imageReady(QImage,int)),this,SLOT(slot_imageReady(QImage,int)),Qt::BlockingQueuedConnection);
···
//設(shè)置線(xiàn)程對(duì)象中的回調(diào)函數(shù)
m_grabThread[i]->setCameraPtr(m_myCamera[i]);
}
三、示例完整代碼
1.grabimgthread.h
#ifndef GRABIMGTHREAD_H
#define GRABIMGTHREAD_H
#include <QThread>
#include <QImage>
#include <QDateTime>
#include "HikSdk/cmvcamera.h"
class GrabImgThread : public QThread
{
Q_OBJECT
public:
explicit GrabImgThread(int cameraId);
~GrabImgThread();
void setCameraPtr(CMvCamera *camera);
void run();
signals:
void signal_imageReady(const QImage &image,int cameraId);
private:
static void __stdcall ImageCallback(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser);
private:
int m_cameraId;
CMvCamera *m_cameraPtr;
};
#endif // GRABIMGTHREAD_H
2.grabimgthread.cpp
#include "grabimgthread.h"
GrabImgThread::GrabImgThread(int cameraId)
: m_cameraId(cameraId)
{
}
GrabImgThread::~GrabImgThread()
{
}
//設(shè)置相機(jī)指針
void GrabImgThread::setCameraPtr(CMvCamera *camera)
{
m_cameraPtr = camera;
//注冊(cè)回調(diào)函數(shù)
//nRet = m_myCamera[i]->RegisterImageCallBack(ImageCallback,this); //單色相機(jī)
int nRet = m_cameraPtr->RegisterImageCallBackRGB(ImageCallback,this); //彩色相機(jī)
if(MV_OK != nRet)
{
LOGDEBUG<<"m_cameraId:"<<m_cameraId<<"注冊(cè)回調(diào)函數(shù)失?。?;
return;
}
}
//線(xiàn)程運(yùn)行
void GrabImgThread::run()
{
}
//回調(diào)函數(shù)
void __stdcall GrabImgThread::ImageCallback(unsigned char * pData,MV_FRAME_OUT_INFO_EX* pFrameInfo,void* pUser)
{
LOGDEBUG<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz ")<<"回調(diào)函數(shù)執(zhí)行了";
GrabImgThread* pThread = static_cast<GrabImgThread *>(pUser);
//創(chuàng)建QImage對(duì)象
QImage showImage = QImage(pData,pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888);
//發(fā)送信號(hào),通知主界面更新圖像
emit pThread->signal_imageReady(showImage,pThread->m_cameraId);
}
3.mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDateTime>
#include "HikSdk/grabimgthread.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 slot_imageReady(const QImage &image,int cameraId);
void on_pb_init_clicked();
void on_pb_start_clicked();
void on_pb_stop_clicked();
private:
Ui::MainWindow *ui;
CMvCamera *m_myCamera[2]; //相機(jī)對(duì)象
GrabImgThread *m_grabThread[2]; //捕獲圖像線(xiàn)程
MV_CC_DEVICE_INFO *m_deviceInfo[2]; //設(shè)備信息
MV_CC_DEVICE_INFO_LIST m_stDevList; //設(shè)備信息列表
};
#endif // MAINWINDOW_H
4.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;
for(int i=0;i<2;i++)
{
if(m_myCamera[i])
{
m_myCamera[i]->Close();
delete m_myCamera[i];
m_myCamera[i] = NULL;
}
}
}
void MainWindow::initWidget()
{
for(int i=0;i<2;i++)
{
//相機(jī)對(duì)象
m_myCamera[i] = new CMvCamera;
//線(xiàn)程對(duì)象
m_grabThread[i] = new GrabImgThread(i);
connect(m_grabThread[i],SIGNAL(signal_imageReady(QImage,int)),this,SLOT(slot_imageReady(QImage,int)),Qt::BlockingQueuedConnection);
}
}
//顯示圖像
void MainWindow::slot_imageReady(const QImage &image,int cameraId)
{
QPixmap showPixmap = QPixmap::fromImage(image).scaled(QSize(250,200),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
if(cameraId == 0)
{
ui->lb_time_1->setText("相機(jī)1:" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz"));
ui->lb_image_1->setPixmap(showPixmap);
}
else
{
ui->lb_time_2->setText("相機(jī)2:" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz"));
ui->lb_image_2->setPixmap(showPixmap);
}
}
//初始化
void MainWindow::on_pb_init_clicked()
{
//枚舉子網(wǎng)內(nèi)所有設(shè)備
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<<"枚舉相機(jī)設(shè)備失?。?;
return;
}
int deviceNum = m_stDevList.nDeviceNum;
LOGDEBUG<<"相機(jī)連接數(shù)量:"<<deviceNum;
if(deviceNum > 2)
{
//我這里只定義了兩個(gè)相機(jī)對(duì)象,所以限制為2,實(shí)際情況需要根據(jù)相機(jī)數(shù)量定義頭文件中的對(duì)象數(shù)
deviceNum = 2;
}
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<<"警告,未知設(shè)備枚舉!";
return;
}
LOGDEBUG<<"i:"<<i<<" strSerialNumber:"<<strSerialNumber;
if(i == 0)
{
ui->lb_name_1->setText(strSerialNumber);
}
else if(i == 1)
{
ui->lb_name_2->setText(strSerialNumber);
}
//根據(jù)相機(jī)序列號(hào)指定相機(jī)對(duì)象,就可以指定某個(gè)窗口進(jìn)行顯示
//if(strSerialNumber == "DA0333897")
//{
// m_deviceInfo[0] = pDeviceInfo;
//}
//else if(strSerialNumber == "DA0424312")
//{
// m_deviceInfo[1] = pDeviceInfo;
//}
//不指定
m_deviceInfo[i] = pDeviceInfo;
//打開(kāi)相機(jī)
int nRet = m_myCamera[i]->Open(m_deviceInfo[i]);
if(MV_OK != nRet)
{
LOGDEBUG<<"i:"<<i<<"打開(kāi)相機(jī)失敗!";
return;
}
else
{
//關(guān)閉觸發(fā)模式
nRet = m_myCamera[i]->SetEnumValue("TriggerMode",0);
if(MV_OK != nRet)
{
LOGDEBUG<<"i:"<<i<<"關(guān)閉觸發(fā)模式失?。?;
return;
}
//設(shè)置線(xiàn)程對(duì)象中的回調(diào)函數(shù)
m_grabThread[i]->setCameraPtr(m_myCamera[i]);
}
}
}
//開(kāi)始取圖
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<<"開(kā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;
}
}
}
5.mainwindow.ui
四、下載鏈接
我的示例百度網(wǎng)盤(pán)鏈接:https://pan.baidu.com/s/1SpWcRc0WnnaBAjS1lfoyfA
提取碼:xxcj
總結(jié)
通過(guò)多線(xiàn)程的方式,就不用寫(xiě)多個(gè)回調(diào)函數(shù)了,也是實(shí)現(xiàn)了多個(gè)??倒I(yè)相機(jī)內(nèi)觸發(fā)采集回調(diào)取流,這樣做是比較簡(jiǎn)便的,同時(shí)也防止了整個(gè)項(xiàng)目代碼過(guò)于冗余。文章線(xiàn)程類(lèi)中注冊(cè)回調(diào)函數(shù)中有提到單色和彩色兩種相機(jī),這個(gè)示例的是彩色相機(jī)的取圖,如果是單色的,需要注意在回調(diào)函數(shù)中進(jìn)行QImage類(lèi)型轉(zhuǎn)換的時(shí)候,要將其中的QImage::Format_RGB888修改為QImage::Format_Indexed8
常用的還可能需要轉(zhuǎn)換為cv::Mat類(lèi)型的圖像,這里也簡(jiǎn)單介紹一下
//創(chuàng)建cv::Mat對(duì)象
cv::Mat showMat(pFrameInfo->nHeight,pFrameInfo->nWidth,CV_8UC1,pData); //單色
cv::Mat showMat(pFrameInfo->nHeight,pFrameInfo->nWidth,CV_8UC3,pData); //彩色文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-575851.html
hello:
共同學(xué)習(xí),共同進(jìn)步,如果還有相關(guān)問(wèn)題,可在評(píng)論區(qū)留言進(jìn)行討論。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-575851.html
到了這里,關(guān)于(二)Qt下多線(xiàn)程實(shí)現(xiàn)多個(gè)海康工業(yè)相機(jī)內(nèi)觸發(fā)采集回調(diào)取流顯示的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!