Dalsa线扫相机SDK二次开发(内触发 QT开发)

写在前面

本篇文章仅为工作记录,以下是本篇文章的开发环境
开发平台:Windows11
开发环境:QT5.15.2
开发语言:C++
编译器:MSVC 2019 64bit
线扫相机:LA-CM-16K05A-00-R
SDK版本:SaperaLTSDKSetup_8.20
采集卡:Xtium-CL_MX4

1、安装Sapera Lt

这没什么好说的,去官网下载SaperaLTSDKSetup_8.20安装即可;
默认安装路径;C:\Program Files\Teledyne DALSA;说明文档和示例程序(c++、c#)以及动/静态库都在该文件夹下
本项目基于c++开发,需要的文件有Classes、Include、Lib,Classes是一些基本类,Include是必须的头文件,Lib是编译好的库,
help包含各种接口参数说明,不懂得就去里面找。
Sapera文件结构如下:
在这里插入图片描述
需要把Classes、Include、Lib拷贝到QT项目工作目录,如下图:

在这里插入图片描述

2、QT项目构建

在使用api接口时.pro文件一定要包含一下命令,链接基本的库文件

win32: LIBS += -L$$PWD/Lib/Win64/ -lSapClassBasic
win32: LIBS += -L$$PWD/Lib/Win64/ -lcorapi

INCLUDEPATH += $$PWD/Include
DEPENDPATH += $$PWD/Include

INCLUDEPATH += $$PWD/Classes/Basic
DEPENDPATH += $$PWD/Classes/Basic

构造相机类CCamera

基本流程:设备初始化(相机、采集卡)->创建底层资源->等待采集命令;

定义头文件包含一些基础功能:相机初始化、采集卡初始化、连续采图函数、单次采图函数、保存图像、各种硬件设备的抽象表示等等,头文件如下:

#pragma once

#include <QObject>
#include <QDebug>

#include "SapClassBasic.h"//所有类的头文件,必须包含
#include <SapBuffer.h>

class CCamera : public QObject
{
    Q_OBJECT
public:
    CCamera(QObject *parent = nullptr);
    ~CCamera();
    void free();                                              //释放资源
    bool init_camera();                                       //初始化相机
    bool initDevice(char *m_serverName, const char *ccfPath); //初始化采集卡
    bool grabOnce();                                          //非连续采图
    bool grabContinues();                                     //连续采图
    void saveImages();                                        //保存图像
    void stop();                                              //停止采图

    char *m_ServerName{nullptr};            //服务器名称、即采集卡名称
    SapAcquisition *m_Acquisition{nullptr}; //控制与板卡相连接的设备,即线扫相机,仅用于存储采集资源参数,
    SapBufferWithTrash *m_Buffers{nullptr}; //垃圾缓冲区,实时处理时建立垃圾缓冲区用于存放转换数据(常用于处理速度跟不上数据采集速度时)
    //SapView *m_View{nullptr};               //在窗口中显示SapBuffer对象的资源
    SapTransfer *m_Xfer{nullptr};           //管理通用传输过程的功能,即将数据从一个源节点传输到目标节点的操作

private:
};

如果需要在窗口上实时显示采集到的图像打开SapView的注释即可,记得也要打开.cpp里面相应的注释,如果开显示功能,在获取图像进行后续操作后记得释放缓冲区地址,通过函数ReleaseAddress()释放,使用方法见Sapera++Prog.pdf,如果显示卡顿且相机采样率不能改变,可以将缓冲区开的多一点。

定义文件功能实现,代码如下:

注意ccfPath 为相机的配置文件,可以通过相机专家软件根据操作指南配置相机,然后保存配置参数就行了,ccfPath 就是保存的参数文件

#include <QDebug>

#include "CCamera.h"

BYTE *pData{nullptr};
static int framcount = 0; //传输帧计数

void XferCallBack(SapXferCallbackInfo *pInfo) //缓冲区传输图像数据时的回调函数
{
    CCamera *myCamera = static_cast<CCamera *>(pInfo->GetContext());
    // myCamera->m_View->Show();
    myCamera->saveImage();

    //以下代码测试用
    // if (framcount <= 10) {
    //     myCamera->saveImage(); //保存图像
    // } else {
    //     qDebug() << "Grab Finished"; //停止采集
    //     // myCamera->stopGrab();
    //     qDebug() << "count: " << count;
    //     qDebug() << "framcount: " << framcount;
    //     myCamera->m_Xfer->Abort();
    // }
}

CCamera::CCamera(QObject *parent)
    : QObject(parent)
{
    init_camera();
}

CCamera::~CCamera()
{
    free();
}

bool CCamera::init_camera() //初始化相机
{
    m_ServerName = new char[MAX_PATH];                                                          //采集卡名称
    std::string ccfPath = "C:\\Program Files\\Teledyne DALSA\\Sapera\\gxf\\ExternalConfig.ccf"; //配置文件路径
    SapManager::GetServerName(0, SapManager::ResourceAcq, m_ServerName);                        //获得采集卡名称
    if (initDevice(m_ServerName, ccfPath.c_str())) {
        qDebug() << "open " << m_ServerName << " success";
    } else {
        qDebug() << "m_ServerName: " << m_ServerName;
        qDebug() << "ccfPath: " << QString::fromStdString(ccfPath);
        qDebug() << "Open " << m_ServerName << " Failed!";
        free();
        return false;
    }
    m_Buffers->GetAddress((void **)&pData);
    return true;
}

bool CCamera::initDevice(char *m_serverName, const char *ccfPath) //初始化采集卡
{
    qDebug() << "Sapera Console Grab Example (C++ version)";
    SapLocation loc(m_serverName, 0); //初始化采集卡,物理设备的抽象表示,采集卡、资源序号
    qDebug() << SapManager::GetResourceCount(m_serverName, SapManager::ResourceAcq);
    if (SapManager::GetResourceCount(m_serverName, SapManager::ResourceAcq) > 0) {  
    m_Acquisition = new SapAcquisition(loc, ccfPath);      //控制与板卡相连接的设备
    m_Buffers = new SapBufferWithTrash(10, m_Acquisition); //带有垃圾缓冲区的缓冲区
    //m_View = new SapView(m_Buffers, SapHwndAutomatic);                    
    m_Xfer = new SapAcqToBuf(m_Acquisition, m_Buffers, XferCallBack, this); //管理通用传输过程的功能
    }
    //创建底层资源
if (m_Acquisition && !*m_Acquisition && !m_Acquisition->Create()) {
    return false;
    }
    if (m_Buffers && !*m_Buffers) {
        if (!m_Buffers->Create()) {
            return false;
        } else {
            m_Buffers->Clear(); //创建底层资源后清空缓冲区内容
        }
    }
    // if (m_View && !*m_View && !m_View->Create()) {
    //     return false;
    // }
    if (m_Xfer && m_Xfer->GetPair(0)) {
        if (!m_Xfer->GetPair(0)->SetCycleMode(SapXferPair::CycleNextWithTrash)) { //缓冲模式:下一个空缓冲区->垃圾缓冲区
            return false;
        }
    }
    if (m_Xfer && !*m_Xfer && !m_Xfer->Create()) {
        return false;
    }
    return true;
}

bool CCamera::grabContinues() //连续传输
{
    framcount = 1;
    count = 1;
    bool isok = m_Xfer->IsGrabbing();
    qDebug() << isok;
    if (!isok) {
        isok = m_Xfer->Grab();
        m_Xfer->Wait(1000);
    }
    qDebug() << isok;
    return isok;
}

bool CCamera::grabOnce() //传输5张
{
    framcount = 1;
    count = 1;
    bool isok = false;
    if (m_Xfer->IsGrabbing()) {
        m_Xfer->Freeze();
        if (!m_Xfer->Wait(1000)) {
            m_Xfer->Abort();
        }
        return false;
    } else {
        isok = m_Xfer->Snap(5);
        m_Xfer->Wait(1000);
    }
    return isok;
}

bool CCamera::stopGrab() //关闭采集
{
    bool isok = m_Xfer->IsGrabbing();
    qDebug() << isok;
    if (isok) {
        isok = m_Xfer->Freeze();
        qDebug() << isok;
        if (!m_Xfer->Wait(5000)) {
            isok = m_Xfer->Abort();
            qDebug() << isok;
        }
    }
    return isok;
}

void CCamera::saveImage()
{
    std::stringstream ss;
    ss << "D:\\test\\bmp\\" << framcount << ".bmp";//图像保存位置
    std::string name = ss.str();
    const char *savename = name.c_str();
    m_Buffers->Save(savename, "-format bmp"); //保存为bmp格式
    qDebug() << "framcount: " << framcount;
    framcount++;
}

void CCamera::free() //释放资源
{
    if (m_ServerName) {
        delete[] m_ServerName;
        m_ServerName = nullptr;
    }

    if (m_Xfer) {
        m_Xfer->Destroy();
        delete m_Xfer;
        m_Xfer = nullptr;
    }
    // if (m_View) {
    //     m_View->Destroy();
    //     delete m_View;
    //     m_View = nullptr;
    // }
    if (m_Buffers) {
        m_Buffers->Destroy();
        delete m_Buffers;
        m_Buffers = nullptr;
    }
    if (m_Acquisition) {
        m_Acquisition->Destroy();
        delete m_Acquisition;
        m_Acquisition = nullptr;
    }
}

至此内触发模式下的相机类封装完成,为了测试采图功能是否正常可以写个QT界面,
本文仅测试单次采图、连续采图、停止彩图、保存图像是否正常,仅写了简单的界面,没有显示功能
图像保存在 “D:\test\bmp\”,路径一定要用双反斜杠,每次文件命名从1开始,会覆盖之前的数据,跑对此文件记得备份;
另外如果图像的分辨率和相机采样率很高,切记不要跑太久,存储空间占用会很大,
QT界面文件如下:
头文件:

#pragma once

#include <QMainWindow>
#include <QPushButton>
#include <QHBoxLayout>
#include <QWidget>

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private:
    QPushButton *grabContinues, *gradOnce, *stopgrab;
    QHBoxLayout *mainlayout;
};

源文件:

#include "MainWindow.h"
#include "CCamera.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    grabContinues = new QPushButton("连续采集100张", this);
    gradOnce = new QPushButton("单词采集1张", this);
    stopgrab = new QPushButton("停止采集", this);
    QWidget *centralwidget = new QWidget(this); //设置中央部件和布局管理
    setCentralWidget(centralwidget);
    mainlayout = new QHBoxLayout(centralwidget);
    mainlayout->addWidget(grabContinues);
    mainlayout->addWidget(gradOnce);
    mainlayout->addWidget(stopgrab);

    CCamera *cam = new CCamera();
    connect(grabContinues, &QPushButton::clicked, cam, &CCamera::grabContinues);
    connect(gradOnce, &QPushButton::clicked, cam, &CCamera::grabOnce);
    connect(stopgrab, &QPushButton::clicked, cam, &CCamera::stopGrab);
    // connect()
}

MainWindow::~MainWindow()
{
}

main文件:

#include "MainWindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.resize(800, 600);
    w.show();
    return a.exec();
}

以上工作为个人笔记,如有错误欢迎指教!
下篇文章:Dalsa线扫相机SDK二次开发(外触发 QT开发)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值