当前位置:   article > 正文

大恒水星相机SDK(实时采集)基于QT与C++_大恒相机库

大恒相机库

资料文档下载

1.环境搭建

本次的开发环境是基于vs2019使用QT的框架对大恒相机的SDK进行实时采集的操作。我们从零开始讲,根据上面的资料文档我们来添加一个新的项目,并且将C++的库文件添加进去。

首先,我们新建的时候使用QT的模板。
在这里插入图片描述

记住我们新建的路径,下面添加库文件的时候用得到
在这里插入图片描述

创建之后会让我们选择QT的模板,直接默认就好了,等待项目创建完成。待项目新建完成,根据资料文档根据以下路径/Samples/C++ SDK 找到两个文件夹,分别是inclib这两个文件都是大恒相机的库文件,我们导入就可以了。

在这里插入图片描述

库文件导入后需要在vs中进行设置,打开vs–右键解决方案–属性
在这里插入图片描述

在这里插入图片描述

到这里,其实我们已经基本搭建完了。不过下面还有一项我们可以选择一下,默认是窗口模式,我们选择控制台。因为窗口模式在我们调试的时候window的控制台不会显示从来,打印的信息就看不到了,所以可以设置一下。
在这里插入图片描述

前面的环境我们已经配置完成了,现在先来验证一下。在 .h的头文件里添加#include <GalaxyIncludes.h>,这是相机的SDK基本都在里面,具体是什么意思可以查看资料文件。添加完成后,运行程序如果正常运行且不报错,环境搭建就算是完成了,我们可以进行下一步了。

2.整体流程

初始化设备
枚举设备
打开设备
设置参数
开始采集
采集图像/图像处理
停止采集
关闭相机

这是整体的流程思路。点击vs里面的资源管理器,有一个UI的文件,打开并建立四个按钮控制设备的打开与关闭,采集和停止,再插入一个标签的控件用来显示图像。所以我们的画面一共有五个控件。在左侧的属性控制器——属性——objectName,可以修改控件对象名字。对于UI的画面,这里就已经完成了,后面就是代码的部分。

在这里插入图片描述

3.代码示例

这里是部分代码块的讲解,后是会有完整代码的。可能会有些不足,但大体思路是这样的,可以根据自己的理解去进行调整。

#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication1.h"
#include <qdebug.h>
#include <qlabel.h>
#include <qthread.h>
#include <qqueue.h>
#include <GalaxyIncludes.h>

#pragma execution_character_set("utf-8")

class QtWidgetsApplication1 : public QMainWindow
{
    Q_OBJECT

public:
    QtWidgetsApplication1(QWidget* parent = Q_NULLPTR);

    Ui::QtWidgetsApplication1Class ui;


    bool m_bisOpen = false;
    bool m_bisSnap = false;                                     //按钮的显示(是否能点击)

    QQueue <QPixmap> ImageQueue;                                            //建立图像缓存队列

    void UpdataUI();                                            //用于更新画面

private slots:
    void open_camera();                                         //打开设备
    void close_camera();                                        //关闭设备
    void start_acquisition();                                   //开始采集
    void close_acquisition();                                   //关闭采集
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

这是QT的一个类,新建项目的时候就会一起新建出来QtWidgetsApplication1是我的项目的名字。根据自己下项目名字的不同,它也不同。这里除了建立一些信号槽和变量外,需要建立一个缓存队列。因为更新画面的时候我们读取图片是在通道里面读取,如果不放入缓存队列里再读取,会造成内存错误,这一点是需要注意的。

class CSampleCaptureEventHandler : public ICaptureEventHandler
{
public:
    CSampleCaptureEventHandler(QtWidgetsApplication1* mainWindow)
        : pMainWindow(mainWindow)
    {
    }
    void DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam);

private:
    QtWidgetsApplication1* pMainWindow;                 //用于更新画面的一个指针
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这是相机SDK里面的一个回调采集类,我们获取图片的方法有两种。一种是采单帧,另一种是回调采集,这些文档里面是有讲的,具体可以去查看文档。回调采集只是获取的图片,我们还需要将获取到的图片更新到显示窗口,下面就建立了一个指针用来更新画面。到这里头文件已经完成了,下面就是cpp文件的实现。


下面是cpp的全部代码,我会分别讲解每一个块的作用于联系

#include "QtWidgetsApplication1.h"

CGXDevicePointer objDeviceptr;
CGXStreamPointer ObjStreamPtr;
CGXFeatureControlPointer ObjFeatureControlPtr;

QImage blackImage;                                                      //用于黑色背景
ICaptureEventHandler* pCaptureEventHandler=nullptr;                     //建立回调采集变量


QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    connect(ui.open_camear_button, &QPushButton::clicked, this, &QtWidgetsApplication1::open_camera);
    connect(ui.close_camear_button, &QPushButton::clicked, this, &QtWidgetsApplication1::close_camera);
    connect(ui.start_acquisition_button, &QPushButton::clicked, this, &QtWidgetsApplication1::start_acquisition);
    connect(ui.close_acquisition_button, &QPushButton::clicked, this, &QtWidgetsApplication1::close_acquisition);

    QImage blackImage(ui.label_picture->size(), QImage::Format_RGB888);
    blackImage.fill(Qt::black);
    ui.label_picture->setPixmap(QPixmap::fromImage(blackImage));// 设置 label 的 pixmap 为黑色背景图片

    UpdataUI();
}

void QtWidgetsApplication1::open_camera()
{
    IGXFactory::GetInstance().Init();                                               //初始化设备
    GxIAPICPP::gxdeviceinfo_vector vectorDeviceInfo;
    IGXFactory::GetInstance().UpdateDeviceList(1000, vectorDeviceInfo);             //枚举设备

    if (vectorDeviceInfo.size() <= 0)
    {
        qDebug() << "无可用设备!";
        m_bisOpen = false;
    }
    else
    {
        qDebug() << vectorDeviceInfo[0].GetModelName() << endl;
        GxIAPICPP::gxstring strSN = vectorDeviceInfo[0].GetSN();
        objDeviceptr = IGXFactory::GetInstance().OpenDeviceBySN(strSN, GX_ACCESS_EXCLUSIVE);        //通过SN码连接设备
        m_bisOpen = true;
    }
    UpdataUI();
}

void QtWidgetsApplication1::close_camera()
{
    try
    {
        
        if (m_bisSnap)
        {
        	
            ObjFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();      //发送停止命令
            ObjStreamPtr->StopGrab();										//停止流通道采集 		
            ObjStreamPtr->UnregisterCaptureCallback();
            delete pCaptureEventHandler;
            pCaptureEventHandler = nullptr;						//停采、注销采集回调函数 
            
            ObjStreamPtr->Close();							//关闭流通道 
            objDeviceptr->Close();	
            IGXFactory::GetInstance().Uninit();   			//反初始化设备
        }
    }
    catch (...)
    {

    }
    qDebug() << "成功关闭设备";
    m_bisOpen = false;
    m_bisSnap = false;

    QImage blackImage(ui.label_picture->size(), QImage::Format_RGB888);
    blackImage.fill(Qt::black);
    ui.label_picture->setPixmap(QPixmap::fromImage(blackImage));// 设置 label 的 pixmap 为黑色背景图片

    UpdataUI();
}

void QtWidgetsApplication1::start_acquisition()
{
    if (m_bisOpen && !m_bisSnap)
    {
        
        ObjStreamPtr = objDeviceptr->OpenStream(0);

        ICaptureEventHandler* pCaptureEventHandler = new CSampleCaptureEventHandler(this);
        ObjStreamPtr->RegisterCaptureCallback(pCaptureEventHandler, NULL);                      //注册回调采集函数

        ObjStreamPtr->StartGrab();                                                      //开启流通道采集

        ObjFeatureControlPtr = objDeviceptr->GetRemoteFeatureControl();
        ObjFeatureControlPtr->GetEnumFeature("ExposureAuto")->SetValue("Off");                  //设置曝光模式
        ObjFeatureControlPtr->GetFloatFeature("ExposureTime")->SetValue(9000);                    //设置曝光度

        ObjFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();                     //发送开采命令

        m_bisSnap = true;
        qDebug() << "开始采集";
        UpdataUI();
    }
}

void QtWidgetsApplication1::close_acquisition()
{
    if (m_bisSnap)
    {
      
        // 等待子线程完成
        ObjFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();              //停止采集
        ObjStreamPtr->StopGrab();
        ObjStreamPtr->UnregisterCaptureCallback();

        delete pCaptureEventHandler;
        pCaptureEventHandler = nullptr;
        ObjStreamPtr->Close();                                                              //关闭通道
        m_bisSnap = false;
        UpdataUI();
    }
}

void QtWidgetsApplication1::UpdataUI()                                                      //更新
{
    ui.open_camear_button->setEnabled(!m_bisOpen);
    ui.close_camear_button->setEnabled(m_bisOpen);
    ui.start_acquisition_button->setEnabled(m_bisOpen && !m_bisSnap);
    ui.close_acquisition_button->setEnabled(m_bisOpen && m_bisSnap);                        //更新按钮UI

    if (!ImageQueue.empty())
    {
        QPixmap newImage = ImageQueue.dequeue();
        QMetaObject::invokeMethod(this, [this, newImage]() {
            ui.label_picture->setScaledContents(true);
            ui.label_picture->setPixmap(newImage);
         });
    }                                                                           //读取队列里的图片并显示

}                               
void CSampleCaptureEventHandler::DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam)
{
        if (objImageDataPointer->GetStatus() == GX_FRAME_STATUS_SUCCESS)
        {
            qint64 m_width = objImageDataPointer->GetWidth();
            qint64 m_height = objImageDataPointer->GetHeight();
            uchar* pbit = (uchar*)objImageDataPointer->GetBuffer();

            QImage newImage(pbit, m_width, m_height, QImage::Format_Indexed8);
            newImage = newImage.scaled(m_width, m_height, Qt::KeepAspectRatio, Qt::SmoothTransformation);

            double d = ObjFeatureControlPtr->GetFloatFeature("CurrentAcquisitionFrameRate")->GetValue();
            qDebug() << "当前帧率:" << d;

            pMainWindow->ImageQueue.enqueue(QPixmap::fromImage(newImage));
            pMainWindow->UpdataUI();
            
        }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162

QtWidgetsApplication1

里面的四个connect分别对应了UI画面里的四个按钮功能,而下面的设置黑色背景图片可以设置也可以不设置。不设置就是在不获取图像的时候因为label没有东西可以显示,它是白色的也就是看不到了。设置完成了,记得更新画面UpdataUI这个程序相当于一个初始化的作用了。

   QImage blackImage(ui.label_picture->size(), QImage::Format_RGB888);
    blackImage.fill(Qt::black);
    ui.label_picture->setPixmap(QPixmap::fromImage(blackImage));// 设置 label 的 pixmap 为黑色背景图片

    UpdataUI();
  • 1
  • 2
  • 3
  • 4
  • 5

open_camera(打开设备)

根据上面流程图可以知道进来的第一步就是先初始化设备,然后就是寻找设备了(枚举设备),上面的程序有注释这里就不显示代码了。
枚举设备后,根据找到的设备数量进行判断。m_bisOpen就是设置按钮的状态了,如果成功打开设备UI上面的按钮就不能再按钮了,所以要如果成功打开了就设置为不可用,后面的其他程序也是一个道理。qDebug相当于cout输出一些信息在控制台方便调试,连接设备的方式有四种,这里使用SN码的方式连接,其他方法请查看手册

    if (vectorDeviceInfo.size() <= 0)
    {
        qDebug() << "无可用设备!";
        m_bisOpen = false;
    }
    else
    {
        qDebug() << vectorDeviceInfo[0].GetModelName() << endl;
        GxIAPICPP::gxstring strSN = vectorDeviceInfo[0].GetSN();
        objDeviceptr = IGXFactory::GetInstance().OpenDeviceBySN(strSN, GX_ACCESS_EXCLUSIVE);        //通过SN码连接设备
        m_bisOpen = true;
    }
    UpdataUI();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

close_camera(关闭设备)

有开必有关,根据m_bisOpen判断设备是否被打开了。后面就不管相机处于什么状态都给它停止并关闭了,这个程序跟close_acquisition意思是差不多的,后面我就不讲这个程序了。两个程序的区别一个是停止设备,另一个是先停止关闭这个很好理解。

start_acquisition(开始采集)

打开设备后,已经完成了流程图上面的三个步骤,这里将完成设置参数开始采集的操作。具体的程序上面的注释已经有了,但这里我讲一个需要注意的小点也是我自己做的时候遇到的问题——曝光度。通过程序去设置的曝光度是会影响画面的帧率的,设置的越高帧率越低,后面可以自行尝试。到这一个程序的最后一步,只是发送了开采命令并没有对图像进行读取与显示的操作,后面的两个程序才是关键的。

DoOnImageCaptured(回调采集类里面的操作)

到这里就正式开始了对图像的处理了,首先建立的三个变量是获取图片的基本信息。

qint64 m_width = objImageDataPointer->GetWidth();
qint64 m_height = objImageDataPointer->GetHeight();
uchar* pbit = (uchar*)objImageDataPointer->GetBuffer();
  • 1
  • 2
  • 3

建立一个QImage将刚刚获取的图像数据放进去,注意QImage::Format_Indexed8根据自己相机能获取到的图像数据进行赋值,具体是写什么去官网查看自己相机的参数,我的相机的原始数据是Mono8的一个灰度图。而且下面的代码调用了scaled()函数对新创建的图像进行缩放操作,使用Qt::KeepAspectRatio保持宽高比的方式进行缩放,并使用Qt::SmoothTransformation参数来指定平滑的缩放。

QImage newImage(pbit, m_width, m_height, QImage::Format_Indexed8);
newImage = newImage.scaled(m_width, m_height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  • 1
  • 2

下面就是一个读取当前相机帧率的操作,可有可无,自己看着办。

double d = ObjFeatureControlPtr->GetFloatFeature("CurrentAcquisitionFrameRate")->GetValue();
qDebug() << "当前帧率:" << d;
  • 1
  • 2

这个就重要了,再上面处理好的图像先放到缓存队列enqueue里面,再调用UpdataUI进行画面的更新,这个函数是专门用来进行UI画面的显示与更新的。传上去这里就不管它了,它的任务已经完成了。

pMainWindow->ImageQueue.enqueue(QPixmap::fromImage(newImage));
pMainWindow->UpdataUI();
  • 1
  • 2

会不会有疑问,明明没有调用这个程序,为什么它能采集图像呢?它是相机SDK里面的一个虚基类,开启回调采集的时候,相机获取到图片的时候就告诉你,它有一张图片。你拿到之后又告诉相机“我要下一张图片”,相机获取到了图片又跟你说了一遍,一直循环下去。而且控制它开始与停止的就是下面的两个函数,它们位于是start_acquisitionclose_acquistion里面。

ObjFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();                     //发送开采命令
ObjFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();              //停止采集
  • 1
  • 2

UpdataUI(更新画面)

这是最后一个了,累死啦!!!
程序分两个部分,上半部分是更新UI界面的按钮的,下半部分就是更新图片进行实时显示的操作。

    ui.open_camear_button->setEnabled(!m_bisOpen);
    ui.close_camear_button->setEnabled(m_bisOpen);
    ui.start_acquisition_button->setEnabled(m_bisOpen && !m_bisSnap);
    ui.close_acquisition_button->setEnabled(m_bisOpen && m_bisSnap);                        //更新按钮UI
  • 1
  • 2
  • 3
  • 4

这一部分就是通过读取缓存队列里面的图像,然后进行显示。在缓存队列里面我们是先进先出的原则,这样做无论在什么时候对采集进行停止还是关闭设备,都不会因为没有来得及显示图片而进行内存管理错误,来不及显示的图片就暂时放在了队列里面,保证了程序的安全与稳定。

    if (!ImageQueue.empty())
    {
        QPixmap newImage = ImageQueue.dequeue();
        QMetaObject::invokeMethod(this, [this, newImage]() {
            ui.label_picture->setScaledContents(true);
            ui.label_picture->setPixmap(newImage);
         });
    }                                                                           //读取队列里的图片并显示
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4.结果显示

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/806872
推荐阅读
相关标签
  

闽ICP备14008679号