使用Qt联合Opencv进行大恒USB3.0工业相机二次开发

目录

前言

1. 进行.pro文件的修改

2. 进行数据部分代码编写

3. 创建大恒相机设备类

4. 效果测试


前言

在一个项目中,需要使用大亨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. 效果测试

以上就是主要的核心代码部分,我进行了界面的相关设计以及调试部分代码编写,测试效果如下图:

 332e47f76a7548668b730ce3ba4e0001.png

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值