目录
1.新建工程
2.文件及属性配置
2.1文件拷贝
2.2VS项目属性配置
2.2.1包含目录和库目录添加
2.2.2附加依赖项添加
3.添加基于官方mfc代码改写的CGXBitmap类
3.1添加CGXBitmap类
3.2编写CGXBitmap.h和.cpp文件
4.编写Qt .h和 .cpp文件
5.运行效果
6.下载链接
7.双相机代码移植Qt版
1.新建工程
该项目是通过阅读大恒官方C++项目的代码进行移植的一个Qt简单demo,废话不多说直接上步骤。
至此一个Qt项目创建完毕。
2.文件及属性配置
因为需要使用大恒官方的API,那么就需要使用官方提供的库文件和头文件。可以通过该步骤添加到项目中。(方法不唯一,这里为了移植到其他电脑才这样做的)
2.1文件拷贝
2.2VS项目属性配置
2.2.1包含目录和库目录添加
2.2.2附加依赖项添加
至此整个项目的属性配置和文件就配置完成了。
3.添加基于官方mfc代码改写的CGXBitmap类
CGXBitmap类是我基于大恒官方提供的C++代码中mfc版CGXBitmap类改写的。具体功能有:显示图像、保存图像等功能。具体步骤如下:
3.1添加CGXBitmap类
3.2编写CGXBitmap.h和.cpp文件
在添加的CGXBitmap.h 填写如下内容
//
/*CGXBitmap.h*/
/
#pragma once
#include <QWidget>
#include "ui_CGXBitmap.h"
#include <QLabel>
#include <iostream>
#include <GalaxyIncludes.h>
using namespace std;
#pragma execution_character_set("utf-8")
class CGXBitmap : public QWidget
{
Q_OBJECT
public:
CGXBitmap(QWidget *parent = Q_NULLPTR);
~CGXBitmap();
private:
Ui::CGXBitmap ui;
bool m_bIsColor; //是否支持彩色相机
int64_t m_nImageHeight; //原始图像高
int64_t m_nImageWidth; //原始图像宽
BITMAPINFO *m_pBmpInfo; //BITMAPINFO 结构指针,显示图像时使用
char m_chBmpBuf[2048]; //BIMTAPINFO 存储缓冲区,m_pBmpInfo即指向此缓冲区
uchar *m_pImageBuffer; //保存翻转后的图像用于显示
private:
CGXBitmap& operator=(const CGXBitmap&);
CGXBitmap(const CGXBitmap&);
public:
QLabel *m_pLabel;
QImage *m_pImage;
//显示图像
void Show(CImageDataPointer& objCImageDataPointer);
//图像处理后并显示图像
void ShowImageProcess(CImageProcessConfigPointer& objCfg, CImageDataPointer& objCImageDataPointer);
//存储Bmp图像
void SaveBmp(CImageDataPointer& objCImageDataPointer, const std::string& strFilePath);
//存储Raw图像
void SaveRaw(CImageDataPointer& objCImageDataPointer, const std::string& strFilePath);
//通过GX_PIXEL_FORMAT_ENTRY获取最优Bit位
GX_VALID_BIT_LIST GetBestValudBit(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry);
LPCWSTR stringToLPCWSTR(std::string orig);
void addDevicePtr(CGXDevicePointer& objCGXDevicePointer);
private:
//判断PixelFormat是否为8位
bool __IsPixelFormat8(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry);
//为彩色相机图像显示准备资源
void __ColorPrepareForShowImg();
//为黑白相机图像显示准备资源
void __MonoPrepareForShowImg();
//判断是否兼容
bool __IsCompatible(BITMAPINFO *pBmpInfo, uint64_t nWidth, uint64_t nHeight);
//更新Bitmap的信息
void __UpdateBitmap(CImageDataPointer& objCImageDataPointer);
//将m_pBufferRGB中图像显示到界面
void __DrawImg(uchar* pBuffer);
//计算宽度所占的字节数
int64_t __GetStride(int64_t nWidth, bool bIsColor);
//是否支持彩色
void __IsSupportColor(CGXDevicePointer& objCGXDevicePointer, bool &bIsColorFilter);
};
在添加的CGXBitmap.cpp填写如下内容:
#include "CGXBitmap.h"
//---------------------------------------------------------------------------------
/**
\brief 构造函数
\param objCGXDevicePointer 图像设备指针
\param parent 窗体指针
\return 无
*/
//----------------------------------------------------------------------------------
CGXBitmap::CGXBitmap(QWidget *parent)
: QWidget(parent)
, m_bIsColor(false)
, m_nImageHeight(0)
, m_nImageWidth(0)
, m_pImage(NULL)
, m_pBmpInfo(NULL)
, m_pImageBuffer(NULL)
{
ui.setupUi(this);
//初始化绘图框
m_pLabel = new QLabel(this);
m_pLabel->move(0, 0);
m_pLabel->resize(751, 551);
}
void CGXBitmap::addDevicePtr(CGXDevicePointer& objCGXDevicePointer)
{
if (objCGXDevicePointer.IsNull())
{
throw std::runtime_error("Argument is error");
}
memset(m_chBmpBuf, 0, sizeof(m_chBmpBuf));
gxstring strValue = "";
//获得图像宽度、高度等
m_nImageWidth = (int64_t)objCGXDevicePointer->GetRemoteFeatureControl()->GetIntFeature("Width")->GetValue();
m_nImageHeight = (int64_t)objCGXDevicePointer->GetRemoteFeatureControl()->GetIntFeature("Height")->GetValue();
//获取是否为彩色相机
__IsSupportColor(objCGXDevicePointer, m_bIsColor);
if (m_bIsColor)
{
__ColorPrepareForShowImg();
}
else
{
__MonoPrepareForShowImg();
}
}
//---------------------------------------------------------------------------------
/**
\brief 析构函数
\return 无
*/
//----------------------------------------------------------------------------------
CGXBitmap::~CGXBitmap()
{
}
//----------------------------------------------------------------------------------
/**
\brief 判断PixelFormat是否为8位
\param emPixelFormatEntry 图像数据格式
\return true为8为数据,false为非8位数据
*/
//----------------------------------------------------------------------------------
bool CGXBitmap::__IsPixelFormat8(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry)
{
bool bIsPixelFormat8 = false;
const unsigned PIXEL_FORMATE_BIT = 0x00FF0000; ///<用于与当前的数据格式进行与运算得到当前的数据位数
unsigned uiPixelFormatEntry = (unsigned)emPixelFormatEntry;
if ((uiPixelFormatEntry & PIXEL_FORMATE_BIT) == GX_PIXEL_8BIT)
{
bIsPixelFormat8 = true;
}
return bIsPixelFormat8;
}
//----------------------------------------------------------------------------------
/**
\brief 通过GX_PIXEL_FORMAT_ENTRY获取最优Bit位
\param emPixelFormatEntry 图像数据格式
\return 最优Bit位
*/
//----------------------------------------------------------------------------------
GX_VALID_BIT_LIST CGXBitmap::GetBestValudBit(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry)
{
GX_VALID_BIT_LIST emValidBits = GX_BIT_0_7;
switch (emPixelFormatEntry)
{
case GX_PIXEL_FORMAT_MONO8:
case GX_PIXEL_FORMAT_BAYER_GR8:
case GX_PIXEL_FORMAT_BAYER_RG8:
case GX_PIXEL_FORMAT_BAYER_GB8:
case GX_PIXEL_FORMAT_BAYER_BG8:
{
emValidBits = GX_BIT_0_7;
break;
}
case GX_PIXEL_FORMAT_MONO10:
case GX_PIXEL_FORMAT_BAYER_GR10:
case GX_PIXEL_FORMAT_BAYER_RG10:
case GX_PIXEL_FORMAT_BAYER_GB10:
case GX_PIXEL_FORMAT_BAYER_BG10:
{
emValidBits = GX_BIT_2_9;
break;
}
case GX_PIXEL_FORMAT_MONO12:
case GX_PIXEL_FORMAT_BAYER_GR12:
case GX_PIXEL_FORMAT_BAYER_RG12:
case GX_PIXEL_FORMAT_BAYER_GB12:
case GX_PIXEL_FORMAT_BAYER_BG12:
{
emValidBits = GX_BIT_4_11;
break;
}
case GX_PIXEL_FORMAT_MONO14:
{
//暂时没有这样的数据格式待升级
break;
}
case GX_PIXEL_FORMAT_MONO16:
case GX_PIXEL_FORMAT_BAYER_GR16:
case GX_PIXEL_FORMAT_BAYER_RG16:
case GX_PIXEL_FORMAT_BAYER_GB16:
case GX_PIXEL_FORMAT_BAYER_BG16:
{
//暂时没有这样的数据格式待升级
break;
}
default:
break;
}
return emValidBits;
}
//---------------------------------------------------------------------------------
/**
\brief 为彩色相机图像显示准备资源
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::__ColorPrepareForShowImg()
{
//--------------------------------------------------------------------
//---------------------------初始化bitmap头---------------------------
m_pBmpInfo = (BITMAPINFO *)m_chBmpBuf;
m_pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_pBmpInfo->bmiHeader.biWidth = (LONG)m_nImageWidth;
m_pBmpInfo->bmiHeader.biHeight = (LONG)m_nImageHeight;
m_pBmpInfo->bmiHeader.biPlanes = 1;
m_pBmpInfo->bmiHeader.biBitCount = 24;
m_pBmpInfo->bmiHeader.biCompression = BI_RGB;
m_pBmpInfo->bmiHeader.biSizeImage = 0;
m_pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
m_pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
m_pBmpInfo->bmiHeader.biClrUsed = 0;
m_pBmpInfo->bmiHeader.biClrImportant = 0;
}
//---------------------------------------------------------------------------------
/**
\brief 为黑白相机图像显示准备资源
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::__MonoPrepareForShowImg()
{
//---------------------------------------------------------------------
//----------------------初始化bitmap头---------------------------------
m_pBmpInfo = (BITMAPINFO *)m_chBmpBuf;
m_pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_pBmpInfo->bmiHeader.biWidth = (LONG)m_nImageWidth;
m_pBmpInfo->bmiHeader.biHeight = (LONG)m_nImageHeight;
m_pBmpInfo->bmiHeader.biPlanes = 1;
m_pBmpInfo->bmiHeader.biBitCount = 8; // 黑白图像为8
m_pBmpInfo->bmiHeader.biCompression = BI_RGB;
m_pBmpInfo->bmiHeader.biSizeImage = 0;
m_pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
m_pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
m_pBmpInfo->bmiHeader.biClrUsed = 0;
m_pBmpInfo->bmiHeader.biClrImportant = 0;
// 黑白图像需要初始化调色板
for (int i = 0; i < 256; i++)
{
m_pBmpInfo->bmiColors[i].rgbBlue = i;
m_pBmpInfo->bmiColors[i].rgbGreen = i;
m_pBmpInfo->bmiColors[i].rgbRed = i;
m_pBmpInfo->bmiColors[i].rgbReserved = 0;
}
//为经过翻转后的图像数据分配空间
if (m_pImageBuffer != NULL)
{
delete m_pImageBuffer;
m_pImageBuffer = NULL;
}
m_pImageBuffer = new BYTE[(size_t)(m_nImageWidth * m_nImageHeight)];
if (m_pImageBuffer == NULL)
{
throw std::runtime_error("Fail to allocate memory");
}
}
//----------------------------------------------------------------------------------
/**
\brief 判断是否兼容
\param pBmpInfo BITMAPINFO指针
\param nWidth 图像宽
\param nHeight 图像高
\return true为一样,false不一样
*/
//----------------------------------------------------------------------------------
bool CGXBitmap::__IsCompatible(BITMAPINFO *pBmpInfo, uint64_t nWidth, uint64_t nHeight)
{
if (pBmpInfo == NULL
|| pBmpInfo->bmiHeader.biHeight != nHeight
|| pBmpInfo->bmiHeader.biWidth != nWidth
)
{
return false;
}
return true;
}
//----------------------------------------------------------------------------------
/**
\brief 检查图像是否改变并更新Buffer并为图像显示准备资源
\param objCImageDataPointer 图像数据对象
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::__UpdateBitmap(CImageDataPointer& objCImageDataPointer)
{
if (!__IsCompatible(m_pBmpInfo, objCImageDataPointer->GetWidth(), objCImageDataPointer->GetHeight()))
{
m_nImageWidth = objCImageDataPointer->GetWidth();
m_nImageHeight = objCImageDataPointer->GetHeight();
if (m_bIsColor)
{
__ColorPrepareForShowImg();
}
else
{
__MonoPrepareForShowImg();
}
}
}
//---------------------------------------------------------------------------------
/**
\brief 将m_pBufferRGB中图像显示到界面
\param pBuffer 图像数据Buffer指针
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::__DrawImg(uchar* pBuffer)
{
if (m_pImage != NULL)
{
delete m_pImage;
m_pImage = NULL;
}
//数据转换
m_pImage = new QImage(pBuffer, m_nImageWidth, m_nImageHeight, QImage::Format_Indexed8);
// 不失真缩放
m_pImage->scaled(m_nImageWidth, m_nImageHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_pLabel->setScaledContents(true);
m_pLabel->setPixmap(QPixmap::fromImage(*m_pImage));
}
//----------------------------------------------------------------------------------
/**
\brief 计算宽度所占的字节数
\param nWidth 图像宽度
\param bIsColor 是否是彩色相机
\return 图像一行所占的字节数
*/
//----------------------------------------------------------------------------------
int64_t CGXBitmap::__GetStride(int64_t nWidth, bool bIsColor)
{
return bIsColor ? nWidth * 3 : nWidth;
}
//----------------------------------------------------------------------------------
/**
\brief 用于显示图像
\param objCImageDataPointer 图像数据对象
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::Show(CImageDataPointer& objCImageDataPointer)
{
GX_VALID_BIT_LIST emValidBits = GX_BIT_0_7;
uchar* pBuffer = NULL;
if (objCImageDataPointer.IsNull())
{
throw std::runtime_error("NULL pointer dereferenced");
}
//检查图像是否改变并更新Buffer
__UpdateBitmap(objCImageDataPointer);
emValidBits = GetBestValudBit(objCImageDataPointer->GetPixelFormat());
if (m_bIsColor)
{
pBuffer = (uchar*)objCImageDataPointer->ConvertToRGB24(emValidBits, GX_RAW2RGB_NEIGHBOUR, true);
__DrawImg(pBuffer);
}
else
{
if (__IsPixelFormat8(objCImageDataPointer->GetPixelFormat()))
{
pBuffer = (uchar*)objCImageDataPointer->GetBuffer();
}
else
{
pBuffer = (uchar*)objCImageDataPointer->ConvertToRaw8(emValidBits);
}
__DrawImg(pBuffer);
}
}
//----------------------------------------------------------------------------------
/**
\brief 用于图像处理后并显示图像
\param objCfg 图像处理调节参数对象
\param objCImageDataPointer 图像数据对象
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::ShowImageProcess(CImageProcessConfigPointer& objCfg, CImageDataPointer& objCImageDataPointer)
{
if ((objCfg.IsNull()) || (objCImageDataPointer.IsNull()))
{
throw std::runtime_error("NULL pointer dereferenced");
}
//检查图像是否改变并更新Buffer
__UpdateBitmap(objCImageDataPointer);
BYTE* pBuffer = (BYTE*)objCImageDataPointer->ImageProcess(objCfg);
if (m_bIsColor)
{
__DrawImg(pBuffer);
}
else
{
// 黑白相机需要翻转数据后显示
for (int i = 0; i < m_nImageHeight; i++)
{
memcpy(m_pImageBuffer + i * m_nImageWidth, pBuffer + (m_nImageHeight - i - 1) * m_nImageWidth, (size_t)m_nImageWidth);
}
__DrawImg(m_pImageBuffer);
}
}
//----------------------------------------------------------------------------------
/**
\brief 存储Bmp图像
\param objCImageDataPointer 图像数据对象
\param strFilePath 显示图像文件名
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::SaveBmp(CImageDataPointer& objCImageDataPointer, const std::string& strFilePath)
{
GX_VALID_BIT_LIST emValidBits = GX_BIT_0_7;
uchar* pBuffer = NULL;
if ((objCImageDataPointer.IsNull()) || (strFilePath == ""))
{
throw std::runtime_error("Argument is error");
}
//检查图像是否改变并更新Buffer
__UpdateBitmap(objCImageDataPointer);
emValidBits = GetBestValudBit(objCImageDataPointer->GetPixelFormat());
if (m_bIsColor)
{
pBuffer = (uchar*)objCImageDataPointer->ConvertToRGB24(emValidBits, GX_RAW2RGB_NEIGHBOUR, true);
}
else
{
if (__IsPixelFormat8(objCImageDataPointer->GetPixelFormat()))
{
pBuffer = (uchar*)objCImageDataPointer->GetBuffer();
}
else
{
pBuffer = (uchar*)objCImageDataPointer->ConvertToRaw8(emValidBits);
}
// 黑白相机需要翻转数据后显示
for (int i = 0; i < m_nImageHeight; i++)
{
memcpy(m_pImageBuffer + i * m_nImageWidth, pBuffer + (m_nImageHeight - i - 1) * m_nImageWidth, (size_t)m_nImageWidth);
}
pBuffer = m_pImageBuffer;
}
DWORD dwImageSize = (DWORD)(__GetStride(m_nImageWidth, m_bIsColor) * m_nImageHeight);
BITMAPFILEHEADER stBfh = { 0 };
DWORD dwBytesRead = 0;
stBfh.bfType = (WORD)'M' << 8 | 'B'; //定义文件类型
stBfh.bfOffBits = m_bIsColor ? sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
: sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (256 * 4); //定义文件头大小true为彩色,false为黑白
stBfh.bfSize = stBfh.bfOffBits + dwImageSize; //文件大小
DWORD dwBitmapInfoHeader = m_bIsColor ? sizeof(BITMAPINFOHEADER)
: sizeof(BITMAPINFOHEADER) + (256 * 4); //定义BitmapInfoHeader大小true为彩色,false为黑白
//创建文件
HANDLE hFile = ::CreateFile(stringToLPCWSTR(strFilePath),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
throw std::runtime_error("Handle is invalid");
}
::WriteFile(hFile, &stBfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);
::WriteFile(hFile, m_pBmpInfo, dwBitmapInfoHeader, &dwBytesRead, NULL); //黑白和彩色自适应
::WriteFile(hFile, pBuffer, dwImageSize, &dwBytesRead, NULL);
CloseHandle(hFile);
}
//----------------------------------------------------------------------------------
/**
\brief 存储Raw图像
\param objCImageDataPointer 图像数据对象
\param strFilePath 显示图像文件名
\return 无
*/
//----------------------------------------------------------------------------------
void CGXBitmap::SaveRaw(CImageDataPointer& objCImageDataPointer, const std::string& strFilePath)
{
if ((objCImageDataPointer.IsNull()) || (strFilePath == ""))
{
throw std::runtime_error("Argument is error");
}
//检查图像是否改变并更新Buffer
__UpdateBitmap(objCImageDataPointer);
DWORD dwImageSize = (DWORD)objCImageDataPointer->GetPayloadSize(); // 写入文件的长度
DWORD dwBytesRead = 0; // 文件读取的长度
BYTE* pbuffer = (BYTE*)objCImageDataPointer->GetBuffer();
if (!m_bIsColor)
{
// 黑白相机需要翻转数据后显示
for (int i = 0; i < m_nImageHeight; i++)
{
memcpy(m_pImageBuffer + i * m_nImageWidth, pbuffer + (m_nImageHeight - i - 1) * m_nImageWidth, (size_t)m_nImageWidth);
}
pbuffer = m_pImageBuffer;
}
// 创建文件
HANDLE hFile = ::CreateFile(stringToLPCWSTR(strFilePath),
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) // 创建失败则返回
{
throw std::runtime_error("Handle is invalid");
}
else // 保存Raw图像
{
::WriteFile(hFile, pbuffer, dwImageSize, &dwBytesRead, NULL);
CloseHandle(hFile);
}
}
//----------------------------------------------------------------------------------
/**
\brief 是否支持彩色
\param objCGXDevicePointer [in] 设备句柄
\param bIsColorFilter [out] 是否支持彩色
\return
*/
//----------------------------------------------------------------------------------
void CGXBitmap::__IsSupportColor(CGXDevicePointer& objCGXDevicePointer, bool &bIsColorFilter)
{
GX_STATUS emStatus = GX_STATUS_SUCCESS;
bool bIsImplemented = false;
bool bIsMono = false;
gxstring strPixelFormat = "";
strPixelFormat = objCGXDevicePointer->GetRemoteFeatureControl()->GetEnumFeature("PixelFormat")->GetValue();
strPixelFormat.substr(0, 4);
if (0 == memcmp(strPixelFormat.c_str(), "Mono", 4))
{
bIsMono = true;
}
else
{
bIsMono = false;
}
bIsImplemented = objCGXDevicePointer->GetRemoteFeatureControl()->IsImplemented("PixelColorFilter");
// 若当前为非黑白且支持PixelColorFilter则为彩色
if ((!bIsMono) && (bIsImplemented))
{
bIsColorFilter = true;
}
else
{
bIsColorFilter = false;
}
}
LPCWSTR CGXBitmap::stringToLPCWSTR(std::string orig)
{
size_t origsize = orig.length() + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t* wcstring = (wchar_t*)malloc(sizeof(wchar_t) * (orig.length() - 1));
mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
return wcstring;
}
CGXBitmap.ui不做修改
4.编写Qt .h和 .cpp文件
接下来编写最后的核心文件,具体文件以自己命名为主。
编写daheng_SingleCam_for_qt.h(我的界面是用代码生成的,没有使用拖曳的方式生成,目的是为了提供更好的代码观感)
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_daheng_SingleCam_for_qt.h"
#include <GalaxyIncludes.h>
#include <iostream>
#include "CGXBitmap.h"
#include <QPushButton>
#include <QLabel>
#include <QCloseEvent>
using namespace std;
#pragma execution_character_set("utf-8")
class daheng_SingleCam_for_qt : public QMainWindow
{
Q_OBJECT
//用户继承采集事件处理类
class CSampleCaptureEventHandler : public ICaptureEventHandler
{
public:
//---------------------------------------------------------------------------------
/**
\brief 采集回调函数
\param objImageDataPointer 图像处理参数
\param pFrame 用户参数
\return 无
*/
//----------------------------------------------------------------------------------
void DoOnImageCaptured(CImageDataPointer&objImageDataPointer, void* pUserParam)
{
try
{
daheng_SingleCam_for_qt* pSingleCamDlg = (daheng_SingleCam_for_qt*)pUserParam;
//显示图像
pSingleCamDlg->m_pBitmap->Show(objImageDataPointer);
//判断是否需要保存图像
//if (pSingleCamDlg->m_pBitmap->m_bSaveImage == true)
//{
// pSingleCamDlg->m_pBitmap->SavePicture(objImageDataPointer);
// pSingleCamDlg->m_pBitmap->m_bSaveImage = false;
//}
}
catch (CGalaxyException)
{
}
catch (std::exception)
{
}
}
};
public:
daheng_SingleCam_for_qt(QWidget *parent = Q_NULLPTR);
CGXBitmap *m_pBitmap; //图像操作类
private:
Ui::daheng_SingleCam_for_qtClass ui;
//Qt控件
QPushButton *m_pBtnOpenDevice; //打开设备按钮
QPushButton *m_pBtnCloseDevice; //关闭设备按钮
QPushButton *m_pBtnStartSnap; //开始采集按钮
QPushButton *m_pBtnStopSnap; //停止采集按钮
QLabel *m_pLabel; //状态栏显示文字
//用于界面更新的标识
bool m_bIsOpen; //打开设备标识
bool m_bIsSnap; //采集图像标识
//大恒相机API
CGXFeatureControlPointer *m_pFeatureEventHandler; //远端设备事件回调对象
CSampleCaptureEventHandler *m_pCaptureEventHandler; //采集回调对象
CGXDevicePointer m_ObjDevicePtr; //设备句柄
CGXStreamPointer m_ObjStreamPtr; //设备流
CGXFeatureControlPointer m_ObjFeatureControlPtr; //属性控制器
CGXFeatureControlPointer m_ObjStreamFeatureControlPtr; //流层控制器
//槽函数
void on_Btn_OpenDevice_clicked();
void on_Btn_CloseDevice_clicked();
void on_Btn_StartSnap_clicked();
void on_Btn_StopSnap_clicked();
//关闭窗口事件重写
void closeEvent(QCloseEvent *event);
//更新界面
void UpdateUI();
};
daheng_SingleCam_for_qt.cpp
#include "daheng_SingleCam_for_qt.h"
daheng_SingleCam_for_qt::daheng_SingleCam_for_qt(QWidget *parent)
: QMainWindow(parent)
, m_bIsOpen(false)
, m_bIsSnap(false)
{
ui.setupUi(this);
//控件初始化
m_pBtnOpenDevice = new QPushButton(this);
m_pBtnOpenDevice->setText("打开设备");
m_pBtnOpenDevice->move(0, 0);
m_pBtnCloseDevice = new QPushButton(this);
m_pBtnCloseDevice->setText("关闭设备");
m_pBtnCloseDevice->move(0, 50);
m_pBtnStartSnap = new QPushButton(this);
m_pBtnStartSnap->setText("开始采集");
m_pBtnStartSnap->move(0, 100);
m_pBtnStopSnap = new QPushButton(this);
m_pBtnStopSnap->setText("停止采集");
m_pBtnStopSnap->move(0, 150);
m_pBitmap = new CGXBitmap(this);
m_pBitmap->move(100, 0);
m_pBitmap->resize(800, 607);
m_pLabel = new QLabel(this);
m_pLabel->setText("欢迎使用大恒相机[for Qt]");
statusBar()->addWidget(m_pLabel);//将label控件添加到状态栏
//连接信号和槽函数
connect(m_pBtnOpenDevice, &QPushButton::clicked, this, &daheng_SingleCam_for_qt::on_Btn_OpenDevice_clicked);
connect(m_pBtnCloseDevice, &QPushButton::clicked, this, &daheng_SingleCam_for_qt::on_Btn_CloseDevice_clicked);
connect(m_pBtnStartSnap, &QPushButton::clicked, this, &daheng_SingleCam_for_qt::on_Btn_StartSnap_clicked);
connect(m_pBtnStopSnap, &QPushButton::clicked, this, &daheng_SingleCam_for_qt::on_Btn_StopSnap_clicked);
//大恒API库调用
try
{
//初始化设备
IGXFactory::GetInstance().Init();
m_pCaptureEventHandler = new CSampleCaptureEventHandler();
//更新界面
UpdateUI();
}
catch (CGalaxyException& e)
{
if (m_pCaptureEventHandler != NULL)
{
delete m_pCaptureEventHandler;
m_pCaptureEventHandler = NULL;
}
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
catch (std::exception& e)
{
if (m_pCaptureEventHandler != NULL)
{
delete m_pCaptureEventHandler;
m_pCaptureEventHandler = NULL;
}
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
}
//---------------------------------------------------------------------------------
/**
\brief 更新界面
\return 无
*/
//----------------------------------------------------------------------------------
void daheng_SingleCam_for_qt::UpdateUI()
{
m_pBtnOpenDevice->setEnabled(!m_bIsOpen);
m_pBtnCloseDevice->setEnabled(m_bIsOpen);
m_pBtnStartSnap->setEnabled(m_bIsOpen && !m_bIsSnap);
m_pBtnStopSnap->setEnabled(m_bIsOpen && m_bIsSnap);
}
void daheng_SingleCam_for_qt::on_Btn_OpenDevice_clicked()
{
bool bIsDeviceOpen = false; //设备是否打开标识
bool bIsStreamOpen = false; //设备流是否打开标识
try
{
//枚举设备
GxIAPICPP::gxdeviceinfo_vector vectorDeviceInfo;
IGXFactory::GetInstance().UpdateDeviceList(1000, vectorDeviceInfo);
if (vectorDeviceInfo.size() == 0)
{
m_bIsOpen = false;
bIsDeviceOpen = false;
m_pLabel->setText("无可用设备!");
return;
}
//打开第一个设备以及设备下面第一个流
m_ObjDevicePtr = IGXFactory::GetInstance().OpenDeviceBySN(vectorDeviceInfo[0].GetSN(), GX_ACCESS_EXCLUSIVE);//打开方式:独占
m_bIsOpen = true;
bIsDeviceOpen = true;
//获取远端设备属性控制器
m_ObjFeatureControlPtr = m_ObjDevicePtr->GetRemoteFeatureControl();
//为画图对象分配设备指针
m_pBitmap->addDevicePtr(m_ObjDevicePtr);
//判断设备流是否大于零,如果大于零则打开流
int nStreamCount = m_ObjDevicePtr->GetStreamCount();
if (nStreamCount)
{
m_ObjStreamPtr = m_ObjDevicePtr->OpenStream(0);
//获取流层属性控制器
m_ObjStreamFeatureControlPtr = m_ObjStreamPtr->GetFeatureControl();
bIsStreamOpen = true;
}
else
{
throw exception("未发现设备流!");
}
//提高网络相机的采集性能,设置方法如下(目前只有千兆网系列相机支持设置最优包长)
GX_DEVICE_CLASS_LIST ObjDeviceClass =
m_ObjDevicePtr->GetDeviceInfo().GetDeviceClass();
if (ObjDeviceClass == GX_DEVICE_CLASS_GEV)
{
//判断设备是否支持流通道数据包功能
if (m_ObjStreamFeatureControlPtr->IsImplemented("GevSCPSPacketSize"))
{
//获取当前网络环境的最优包长值
int nPacketSize = m_ObjStreamPtr->GetOptimalPacketSize();
//将最优包长值设置为当前设备的流通道包长值
m_ObjFeatureControlPtr->GetIntFeature(
"GevSCPSPacketSize")->SetValue(nPacketSize);
}
}
//更新界面
UpdateUI();
m_pLabel->setText(QString("打开设备成功!"));
}
catch (CGalaxyException& e)
{
//判断设备流是否已打开
if (bIsStreamOpen)
{
m_ObjStreamPtr->Close();
}
//判断设备是否已打开
if (bIsDeviceOpen)
{
m_ObjDevicePtr->Close();
}
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
catch (exception& e)
{
//判断设备流是否已打开
if (bIsStreamOpen)
{
m_ObjStreamPtr->Close();
}
//判断设备是否已打开
if (bIsDeviceOpen)
{
m_ObjDevicePtr->Close();
}
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
}
void daheng_SingleCam_for_qt::on_Btn_CloseDevice_clicked()
{
try
{
//判断是否已停止采集
if (m_bIsSnap)
{
//发送停采命令
m_ObjFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
//关闭流层采集
m_ObjStreamPtr->StopGrab();
//注销采集回调
m_ObjStreamPtr->UnregisterCaptureCallback();
}
}
catch (CGalaxyException)
{
//do noting
}
try
{
//关闭流对象
m_ObjStreamPtr->Close();
}
catch (CGalaxyException)
{
//do noting
}
try
{
//关闭设备
m_ObjDevicePtr->Close();
m_pLabel->setText(QString("关闭设备成功!"));
}
catch (CGalaxyException)
{
//do noting
}
m_bIsOpen = false;
m_bIsSnap = false;
//更新界面
UpdateUI();
}
void daheng_SingleCam_for_qt::on_Btn_StartSnap_clicked()
{
// TODO: Add your control notification handler code here
try
{
try
{
//设置Buffer处理模式
m_ObjStreamFeatureControlPtr->GetEnumFeature("StreamBufferHandlingMode")->SetValue("OldestFirst");
}
catch (...)
{
}
//注册回调函数
m_ObjStreamPtr->RegisterCaptureCallback(m_pCaptureEventHandler, this);
//开启流层通道
m_ObjStreamPtr->StartGrab();
//发送开采命令
m_ObjFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();
m_bIsSnap = true;
//更新界面
UpdateUI();
m_pLabel->setText(QString("开始采集!"));
}
catch (CGalaxyException& e)
{
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
catch (std::exception& e)
{
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
}
void daheng_SingleCam_for_qt::on_Btn_StopSnap_clicked()
{
// TODO: Add your control notification handler code here
try
{
//发送停采命令
m_ObjFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
//关闭流层通道
m_ObjStreamPtr->StopGrab();
//注销采集回调
m_ObjStreamPtr->UnregisterCaptureCallback();
m_bIsSnap = false;
//更新界面
UpdateUI();
m_pLabel->setText(QString("停止采集!"));
}
catch (CGalaxyException& e)
{
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
catch (std::exception& e)
{
m_pLabel->setText(QString::fromStdString(e.what()));
return;
}
}
void daheng_SingleCam_for_qt::closeEvent(QCloseEvent *event)
{
try
{
//判断是否停止采集
if (m_bIsSnap)
{
//发送停采命令
m_ObjFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
//关闭流层通道
m_ObjStreamPtr->StopGrab();
//注销采集回调
m_ObjStreamPtr->UnregisterCaptureCallback();
m_bIsSnap = false;
}
}
catch (CGalaxyException& e)
{
}
catch (exception& e)
{
}
try
{
//判断是否关闭设备
if (m_bIsOpen)
{
//关闭流对象
m_ObjStreamPtr->Close();
//关闭设备
m_ObjDevicePtr->Close();
m_bIsOpen = false;
}
}
catch (CGalaxyException& e)
{
}
catch (exception& e)
{
}
try
{
//释放设备资源
IGXFactory::GetInstance().Uninit();
}
catch (CGalaxyException& e)
{
}
catch (exception& e)
{
}
if (m_pCaptureEventHandler != NULL)
{
delete m_pCaptureEventHandler;
m_pCaptureEventHandler = NULL;
}
event->accept();
}
5.运行效果
因为目前我只有一个黑白相机,没办法测试彩色相机是否可行。
6.下载链接
7.双相机代码移植Qt版
可以实现两个相机的同步采集和图片保存,有兴趣的也可以下载查看使用,该项目需要自己重新配置属性。