目录
前言
在一个项目中,需要使用大亨USB3.0工业相机进行二次开发,进行开发相关记录。
相机型号:MER2-230-168U3M/C
开发IDE:Qt Creator 4.8.0
图像算法库:opencv4.5.1
使用cv::Mat作为后期开发的图像处理,使用QPixmap进行图像的显示。
1. 进行.pro文件的修改
#配置大恒相机
LIBS += -L$$PWD/Dependence/Equip/Daheng/lib/x64/ -lGxIAPICPPEx
INCLUDEPATH += $$PWD/Dependence/Equip/Daheng/inc
DEPENDPATH += $$PWD/Dependence/Equip/Daheng/inc
#配置Opencv
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/Dependence/Tool/opencv4.5.1/vc15/lib/ -lopencv_world451
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/Dependence/Tool/opencv4.5.1/vc15/lib/ -lopencv_world451d
else:unix: LIBS += -L$$PWD/Dependence/Tool/opencv4.5.1/vc15/lib/ -lopencv_world451
INCLUDEPATH += $$PWD/Dependence/Tool/opencv4.5.1/include
DEPENDPATH += $$PWD/Dependence/Tool/opencv4.5.1/include/opencv2
2. 进行数据部分代码编写
封装CImage数据类型变量,其中包括QImage、QPixmap、Mat类型数据,也实现了QImage与Mat类型转换、QImage与QPixmap类型转换。在界面部分使用QPixmap进行显示。
创建数据元素类型IBaseDataElement,用于后期的数据管理。
其中头文件代码如下:
#ifndef IMAGEDATAELEMENT_H
#define IMAGEDATAELEMENT_H
#include "IBaseDataElement.h"
#include <QImage>
#include <QPixmap>
#include <opencv2/opencv.hpp>
class CImage;
class ImageDataElement : public IBaseDataElement
{
public:
ImageDataElement(Value &vRef,QStandardItem* pDataManagerItem);
~ImageDataElement();
CImage* m_Image;
CImage* GetCurrent();
bool PushData(void* Data);
};
class CImage
{
public:
QImage m_qImage;
QPixmap m_qPixmap;
cv::Mat m_mImage;
QImage cvMatToQImage(const cv::Mat& mat);
cv::Mat QImageTocvMat(const QImage &image);
QPixmap QImageToQPixmap(const QImage& image);
};
#endif // IMAGEDATAELEMENT_H
cpp文件部分代码代码如下:
cv::Mat CImage::QImageTocvMat(const QImage &image)
{
cv::Mat mat;
switch(image.format())
{
case QImage::Format_Grayscale8: //灰度图,每个像素点1个字节(8位)
case QImage::Format_Indexed8: //Mat构造:行数,列数,存储结构,数据,step每行多少字节
mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
break;
case QImage::Format_ARGB32:
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
break;
case QImage::Format_RGB888: //RR,GG,BB字节顺序存储
mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
//opencv需要转为BGR的字节顺序
break;
}
return mat;
}
QPixmap CImage::QImageToQPixmap(const QImage& image)
{
return QPixmap::fromImage(image);
}
QImage CImage::cvMatToQImage(const cv::Mat& mat)
{
switch (mat.type()) {
case CV_8UC1:{
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
image.setColorCount(256);
for(int i = 0; i < 256; i++){
image.setColor(i, qRgb(i, i, i));
}
uchar *pSrc = mat.data;
for(int row = 0; row < mat.rows; row ++){
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return image;
}
case CV_8UC3:{
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
break;
case CV_8UC4:{
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
break;
default:
break;
}
return QImage();
}
3. 创建大恒相机设备类
需要include大恒相机的库文件
CGXDevicePointer objDevicePtr为当前设备指针
ICaptureEventHandler* m_pCaptureEventHandler为捕获对象指针
CGXStreamPointer objStreamPtr;为流控制指针
CImageProcessConfigPointer objImageProcessConfigPtr;为图像配置指针
在初始化部分,我进行判断获取到的相机SN码与配置文件的SN码内容是否一致(注:配置文件相关代码未提供)。
大恒相机类头文件部分代码内容:
#ifndef DAHENGCAMERA_USB3_0_H
#define DAHENGCAMERA_USB3_0_H
#include "Dependence/Equip/Daheng/inc/GalaxyIncludes.h"
#include <string>
namespace Ui {
class DahengCamera_USB3_0;
}
class CSampleCaptureEventHandler;
class DahengCamera_USB3_0 : public IBaseCamera
{
Q_OBJECT
public:
explicit DahengCamera_USB3_0(Value &v_Parameter,QStandardItem* pEquipmentManagerItem,QWidget* pParent);
~DahengCamera_USB3_0();
CGXDevicePointer objDevicePtr;//当前设备指针
ICaptureEventHandler* m_pCaptureEventHandler;//捕获对象指针
CGXStreamPointer objStreamPtr;//流控制指针
CImageProcessConfigPointer objImageProcessConfigPtr;//图像配置指针
virtual bool Init();
virtual void UnInit();
void CollectContinuousStart();//连续采集开始
void CollectContinuousStop();//连续采集结束
};
大恒相机类源文件部分代码内容:
bool DahengCamera_USB3_0::Init()
{
IGXFactory::GetInstance().Init();
GxIAPICPP::gxdeviceinfo_vector vectorDeviceInfo;
IGXFactory::GetInstance().UpdateDeviceList(1000, vectorDeviceInfo);
if (vectorDeviceInfo.size()> 0)
{
for(int i=0;i<(int)vectorDeviceInfo.size();i++)
{
CLogShow::Instance()->Add(vectorDeviceInfo[i].GetVendorName().c_str());
CLogShow::Instance()->Add(vectorDeviceInfo[i].GetSN().c_str());
CLogShow::Instance()->Add(vectorDeviceInfo[i].GetModelName().c_str());
//打开链表中的第i个设备
std::string strSN = vectorDeviceInfo[i].GetSN().c_str();
if(strSN==m_strSN)
{
GxIAPICPP::gxstring strSN = vectorDeviceInfo[i].GetSN();
objDevicePtr = IGXFactory::GetInstance().OpenDeviceBySN(strSN, GX_ACCESS_EXCLUSIVE);
objImageProcessConfigPtr = objDevicePtr->CreateImageProcessConfig();
CLogShow::Instance()->Add("Camera_Init_True");
m_bInitFlag = true;
return true;
}
}
CLogShow::Instance()->Add("Camera_Init_False");
m_bInitFlag = false;
return false;
}
else
{
CLogShow::Instance()->Add("Camera_Init_False");
m_bInitFlag = false;
return false;
}
return true;
}
void DahengCamera_USB3_0::UnInit()
{
if(!IsInit())
return;
//关闭设备之后不允许再调用 IDevice 以及设备的 IFeatureControl、IStream 的所有接口
m_bInitFlag = false;
objDevicePtr->Close();
IGXFactory::GetInstance().Uninit();
CLogShow::Instance()->Add("Camera_UnInit");
}
void DahengCamera_USB3_0::CollectContinuousStart()
{
objStreamPtr = objDevicePtr->OpenStream(0);
//注册采集回调函数,注意第一个参数是用户私有参数,用户可以传入任何 object 对象,也可以是 null
//用户私有参数在回调函数内部还原使用,如果不使用私有参数,可以传入 null
m_pCaptureEventHandler = new CSampleCaptureEventHandler(m_iDataElementIndex,objImageProcessConfigPtr);
objStreamPtr->RegisterCaptureCallback(m_pCaptureEventHandler,NULL);
//开启流通道采集
objStreamPtr->StartGrab();
//给设备发送开采命令
CGXFeatureControlPointer objFeatureControlPtr =
objDevicePtr->GetRemoteFeatureControl();
objFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();
//回调采集过程,参见回调函数
m_bCollectFlag = true;//设置采集标志为true
}
void DahengCamera_USB3_0::CollectContinuousStop()
{
CGXFeatureControlPointer objFeatureControlPtr = objDevicePtr->GetRemoteFeatureControl();
//停采、注销采集回调函数
objFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
objStreamPtr->StopGrab();
objStreamPtr->UnregisterCaptureCallback();
delete m_pCaptureEventHandler;
m_pCaptureEventHandler = NULL;
//关闭流通道
objStreamPtr->Close();
m_bCollectFlag = false;
}
此外,连续采集需要继承ICaptureEventHandler并且重写回调函数DoOnImageCaptured。以下是实现的代码。这里一开始将pRaw8Buffer 转换成QImage类型后进行QPixmap类型显示,发现显示的图像结果是镜像的,故将pRaw8Buffer转换成Mat类型后没有这样的问题,这里标记一下待以后查看原因。
头文件:
class CSampleCaptureEventHandler : public ICaptureEventHandler
{
public:
CSampleCaptureEventHandler(int iDataElementIndex,CImageProcessConfigPointer& objImageProcessConfigPtr);
ImageDataElement* m_pELement;
CImageProcessConfigPointer m_objImageProcessConfigPtr;
void DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam);
};
源文件代码:
CSampleCaptureEventHandler::CSampleCaptureEventHandler(int iDataElementIndex,CImageProcessConfigPointer& objImageProcessConfigPtr)
{
m_pELement = static_cast<ImageDataElement*>(DataManager::Instance()->m_vDataList[iDataElementIndex]);
m_objImageProcessConfigPtr = objImageProcessConfigPtr;
}
void CSampleCaptureEventHandler::DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam)
{
if (objImageDataPointer->GetStatus() == GX_FRAME_STATUS_SUCCESS)
{
//图像获取为完整帧,可以读取图像宽、高、数据格式等
//uint64_t nWidth = objImageDataPointer->GetWidth();
//uint64_t nHeight = objImageDataPointer->GetHeight();
//GX_PIXEL_FORMAT_ENTRY emPixelFormat = objImageDataPointer->GetPixelFormat();
void* pRaw8Buffer = NULL;
objImageDataPointer->ImageProcess(m_objImageProcessConfigPtr);
pRaw8Buffer = objImageDataPointer->ConvertToRaw8(GX_BIT_0_7);
m_pELement->Lock();
m_pELement->m_Image->m_mImage = cv::Mat((int)objImageDataPointer->GetHeight(),(int)objImageDataPointer->GetWidth(),CV_8UC1,pRaw8Buffer,objImageDataPointer->GetWidth());
m_pELement->m_Image->m_qImage = m_pELement->m_Image->cvMatToQImage(m_pELement->m_Image->m_mImage);
m_pELement->m_Image->m_qPixmap = m_pELement->m_Image->QImageToQPixmap(m_pELement->m_Image->m_qImage);
m_pELement->UnLock();
}
}
4. 效果测试
以上就是主要的核心代码部分,我进行了界面的相关设计以及调试部分代码编写,测试效果如下图: