Dalsa线扫相机SDK二次开发_2
写在前面
本篇文章仅为工作记录,以下是本篇文章的开发环境
开发平台: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(); }