Qt调用工业相机之映美精相机

作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

开发环境

操作系统:Windows 10 1903 18362.778
相机型号:IMAGING SOURCE DMK 33G274
相机软件:ic_setup_3.4.0.2744,gigecam_setup_3.7.1.4512
软件版本:Qt 5.12.8, vs2017 Community
通信方式:GigE - 千兆以太网通信协议

驱动与SDK

开发包和驱动下载地址
提取码:34mt

安装驱动和开发包完成之后,可以找到以下2个目录:

  1. C:\ProgramData\Microsoft\Windows\Start Menu\Programs\IC Imaging Control 3.4
    Qt调用工业相机之映美精相机_第1张图片
  • 1 - 开发文档;
  • 2 - 示例程序源代码;
  • 其他 - 可运行的示例程序;
  1. C:\Users\60455\Documents\IC Imaging Control 3.4
    Qt调用工业相机之映美精相机_第2张图片
  • classlib - 程序开发的头文件和库文件;
  • redist - 发行包;
  • samples - 程序源代码(和刚才目录下的源代码是相同的);

映美精相机介绍

映美精相机实时显示图像比较简单,因为SDK中提供了封装好的函数可以直接调用,如下所示:
bool startLive( bool show_videowindow = true );
show_videowindow 设置为true就是启用实时视频窗口,设置为false仅用于图片抓取
我们只需要提供一个窗口的句柄就可以实时显示图像了。

这里先介绍一个叫 FrameHandlerSink 的东西,这是设计采集图像的模式,一共有两种模式:

  1. snap采图模式
    在snap模式下,到达接收器的所有帧都显示给 IFrameFilter,然后复制到 MemBufferCollection 中。之后调用 GrabberListener 的 frameReady 事件;
  2. grab采集模式
    在grab模式下,所有帧都呈现给 IFrameFilter。如果没有挂起任何快照作业,则 IFrameFilter::transform 中的目标帧为0,并且不会调用 frameReady 事件。
    当快照作业挂起时,会在 MemBuffer 中传递缓冲区,当 IFrameFilter::transform 返回true时,MemBuffer 将在 GrabberListener 中的 frameReady 事件中显示;

我们主要来看一下如何使用映美精相机来处理每一帧的数据,映美精相机处理每一帧数据有以下两种方法:

  1. 继承 DShowLib::GrabberListener 类,重新实现 frameReady 这个函数。frameReady 函数就是用来处理图像的,每当相机内存中有图片时,相机就会调用 GrabberListener 中的 frameReady 函数;
  2. 自己通过定时器定时获取图片,可以使用 getLastAcqMemBuffer() 函数获取最新的图片数据;

方法一步骤如下:

  • 添加新的侦听器对象
    m_Grabber.addListener( this, GrabberListener::eALL );

  • 设置采集模式
    m_Sink->setSnapMode( true ); // true为snap采图模式,false为grab采集模式

  • 重写 frameReady 函数
    virtual void frameReady(Grabber &caller, smart_ptr pBuffer, DWORD FrameNumber) override;

  • 调用 startLive 开启实时模式
    m_Grabber.startLive(true);

  • 调用 snapImages 抓取图片
    m_Sink->snapImages( 1, 2000 ); // 抓取一张图片,每次调用 snapImages() 之后,就会触发 Listener 中的 frameReady()

我的代码(博主使用的是方法二)

实现功能:相机图像的实时显示,并且可以在需要的时候获取当前帧数据,用于分析或者保存

首先需要在pro中配置头文件和库文件

CONFIG += debug_and_release

INCLUDEPATH += $$PWD/classlib/include/

windows {
    CONFIG(debug, debug|release) {
        CONFIG += console
        contains(DEFINES, WIN64) {
            LIBS += -L$$PWD/classlib/x64/debug/ -lTIS_UDSHL11d_x64
        } else {
            LIBS += -L$$PWD/classlib/win32/debug/ -lTIS_UDSHL11d_x64
        }
    } else {
        contains(DEFINES, WIN64) {
            LIBS += -L$$PWD/classlib/x64/release/ -lTIS_UDSHL11d_x64
        } else {
            LIBS += -L$$PWD/classlib/win32/release/ -lTIS_UDSHL11d_x64
        }
    }
}

自定义相机基类 Camera

#ifndef CAMERA_H
#define CAMERA_H

#include 
#include 
#include 
#include 

#include 

class Camera : public QObject
{
    Q_OBJECT

public:
    enum CameraType {
        Basler = 1,                     // 巴斯勒相机
        IC_Imaging,                     // 映美精相机
        MV,                             // 海康威视相机
        Virtual                         // 虚拟相机
    };

    explicit Camera(CameraType type = Basler) : m_type(type) {}

    virtual void initCamera() = 0;      // 初始化相机
    virtual void destroyCamera() = 0;   // 销毁相机
    virtual void openCamera() = 0;      // 打开相机
    virtual void closeCamera() = 0;     // 关闭相机
    virtual void startWork() = 0;       // 开始工作
    virtual void stopWork() = 0;        // 停止工作
    virtual cv::Mat takeAPic() = 0;     // 获取当前图像

    void start() { m_timer.start(); }
    void stop() { m_timer.stop(); }
    void setInterval(int time) { m_timer.setInterval(time); }
    CameraType getCameraType() { return m_type; }

signals:
    void updateImage(QImage image);

protected:
    CameraType m_type;
    QMutex m_mutex;
    QTimer m_timer;
};

#endif // CAMERA_H

自定义 BICCameraControl 相机控制类

#ifndef BICCAMERACONTROL_H
#define BICCAMERACONTROL_H

#include "../camera.h"
#include 
#include "Grabber.h"
using namespace _DSHOWLIB_NAMESPACE;

#define NUM_BUFFERS 10

class BICCameraControl : public Camera
{
    Q_OBJECT
public:
    explicit BICCameraControl(Camera::CameraType type = Camera::CameraType::IC_Imaging);

    virtual void initCamera() override;
    virtual void destroyCamera() override;

    virtual void openCamera() override;
    virtual void closeCamera() override;

    virtual void startWork() override;
    virtual void stopWork() override;

    virtual cv::Mat takeAPic() override;

    void showDialog();
    double getExposure();

public slots:
    void updateFrame();

protected:
    DShowLib::Grabber m_Grabber;
    DShowLib::FrameHandlerSink::tFHSPtr m_Sink;
};

#endif // BICCAMERACONTROL_H
#include "biccameracontrol.h"
#include "globalfun.h"

BICCameraControl::BICCameraControl(Camera::CameraType type) : Camera(type)
{
    try {
        DShowLib::InitLibrary();
        atexit(DShowLib::ExitLibrary);
    } catch (DShowLib::Error &e) {
        qDebug() << "InitLibrary erroer: " + QString::fromStdString(e.toString());
    }

    m_timer.setInterval(GlobalValue::cam_itl);
    connect(&m_timer, &QTimer::timeout, this, &BICCameraControl::updateFrame);
}

void BICCameraControl::initCamera()
{
    try {
        m_Sink = DShowLib::FrameHandlerSink::create( FrameTypeInfoArray::createRGBArray(), NUM_BUFFERS );
        m_Sink->setSnapMode( true );

        // Apply the sink to the grabber.
        m_Grabber.setSinkType( m_Sink );
    } catch (DShowLib::Error &e) {
        qDebug() << "initCamera erroer: " + QString::fromStdString(e.toString());
    }
}

void BICCameraControl::destroyCamera()
{
    try {
        stopWork();
        closeCamera();
    } catch (DShowLib::Error &e) {
        qDebug() << "destroyCamera erroer: " + QString::fromStdString(e.toString());
    }
}

void BICCameraControl::openCamera()
{
    // Check if a device is open.
    if ( m_Grabber.isDevOpen() ) {
        return;
    }

    if (m_Grabber.getAvailableVideoCaptureDevices()->size() == 0) {
        return;
    }

    try {
        Grabber::tVidCapDevListPtr pVidCapDevList = m_Grabber.getAvailableVideoCaptureDevices();
        if( pVidCapDevList == 0 || pVidCapDevList->empty() )
        {
            qDebug() << "No device available !";
            return;
        }

        __int64 num;
        pVidCapDevList->at(0).getSerialNumber(num);

        // Open camera from serialNumber.
        m_Grabber.openDev(num);

        m_Grabber.setVideoFormat(dstringa(GlobalValue::cam_fmt.toLatin1().data()));
        m_Grabber.setFPS(GlobalValue::cam_fps);

    } catch (DShowLib::Error &e) {
        qDebug() << "openCamera erroer: " + QString::fromStdString(e.toString());
    }
}

void BICCameraControl::closeCamera()
{
    // Check if a device is open.
    if ( !m_Grabber.isDevOpen() ) {
        return;
    }

    try {
        // Closes the currently active video capture device.
        m_Grabber.closeDev();
    } catch (DShowLib::Error &e) {
        qDebug() << "closeCamera erroer: " + QString::fromStdString(e.toString());
    }
}

void BICCameraControl::startWork()
{
    // Check if live mode is on.
    if ( m_Grabber.isLive() ) {
        return;
    }

    // Check if there is a valid device.
    if ( !m_Grabber.isDevValid() ) {
        return;
    }

    try {
        // Start the live video. Set true to enable the live video window, false to grab only.
        m_Grabber.startLive(false);
        m_timer.start();
    } catch (DShowLib::Error &e) {
        qDebug() << "startWork erroer: " + QString::fromStdString(e.toString());
    }
}

void BICCameraControl::stopWork()
{
    // Check if live mode is on.
    if ( !m_Grabber.isLive() ) {
        return;
    }

    try {
        // Stop live mode.
        m_Grabber.stopLive();
        m_timer.stop();
    } catch (DShowLib::Error &e) {
        qDebug() << "stopWork erroer: " + QString::fromStdString(e.toString());
    }
}

cv::Mat BICCameraControl::takeAPic()
{
    // Check if live mode is on.
    if ( !m_Grabber.isLive() ) {
        return cv::Mat();
    }

    QMutexLocker locker(&m_mutex);

    try {
        m_Sink->snapImages( 1, 1000 );
        smart_ptr pBuffer = m_Sink->getLastAcqMemBuffer();

        QImage image(static_cast< uchar* >( pBuffer->getPtr() ),
                     int( pBuffer->getSize().cx ),
                     int( pBuffer->getSize().cy ),
                     QImage::Format_RGB32);

        QImage retImage = image.mirrored(false, true);
        cv::Mat mat = GlobalFun::convertQImageToMat(retImage);
        return mat.clone();
    } catch (DShowLib::Error &e) {
        qDebug() << "takeAPic erroer: " + QString::fromStdString(e.toString());
        return cv::Mat();
    }
}

void BICCameraControl::showDialog()
{
    if ( m_Grabber.isDevOpen() && m_Grabber.isLive() ) {
        m_Grabber.stopLive();
        m_timer.stop();

        std::thread th([=](){ m_Grabber.showDevicePage(); });
        th.join();

        GlobalValue::cam_fps = m_Grabber.getFPS();
        GlobalValue::cam_fmt = QString::fromStdString(m_Grabber.getVideoFormat().toString());
        qDebug() << "FPS: " + QString::number(GlobalValue::cam_fps);
        qDebug() << "Format: " + GlobalValue::cam_fmt;

        m_Grabber.startLive(false);
        m_timer.start();

        m_Grabber.showVCDPropertyPage();

        GlobalValue::cam_exp = getExposure() * 1000;
        qDebug() << "Exposure: " + QString::number(GlobalValue::cam_exp);
    }
}

double BICCameraControl::getExposure() {
    tIVCDPropertyItemsPtr pItems = m_Grabber.getAvailableVCDProperties();
    if( pItems != 0 )
    {
        tIVCDPropertyItemPtr pExposureItem = pItems->findItem( VCDID_Exposure );
        tIVCDPropertyElementPtr pExposureValueElement = pExposureItem->findElement( VCDElement_Value );
        tIVCDAbsoluteValuePropertyPtr m_pExposureAbsoluteValue;

        if( pExposureValueElement != 0 )
        {
            pExposureValueElement->getInterfacePtr( m_pExposureAbsoluteValue );
        }

        if( m_pExposureAbsoluteValue != 0 )
        {
            return m_pExposureAbsoluteValue->getValue();
        }
    }

    return 0.033;
}

void BICCameraControl::updateFrame()
{
    QMutexLocker locker(&m_mutex);

    try {
        m_Sink->snapImages( 1, 1000 );
        smart_ptr pBuffer = m_Sink->getLastAcqMemBuffer();

        QImage image(static_cast< uchar* >( pBuffer->getPtr() ),
                     int( pBuffer->getSize().cx ),
                     int( pBuffer->getSize().cy ),
                     QImage::Format_RGB32);

        emit updateImage(image.mirrored(false, true));
    } catch (DShowLib::Error &e) {
        qDebug() << "updateFrame erroer: " + QString::fromStdString(e.toString());
    }
}

其他请参考

  • Qt调用工业相机之巴斯勒相机
  • Qt调用工业相机之海康威视相机

你可能感兴趣的:(Qt)