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
    在這裏插入圖片描述
  • 1 - 開發文檔;
  • 2 - 示例程序源代碼;
  • 其他 - 可運行的示例程序;
  1. C:\Users\60455\Documents\IC Imaging Control 3.4
    在這裏插入圖片描述
  • classlib - 程序開發的頭文件和庫文件;
  • redist - 發行包;
  • samples - 程序源代碼(和剛纔目錄下的源代碼是相同的);

相機原理介紹

映美精相機實時顯示圖像比較簡單,因爲SDK中提供了封裝好的函數可以直接調用,如下所示:
bool startLive( bool show_videowindow = true );
show_videowindow 設置爲true就是啓用實時視頻窗口,設置爲false僅用於圖片抓取
我們只需要提供一個窗口的句柄就可以實時顯示圖像了。

我們主要來看一下如何使用映美精相機來處理每一幀的數據。
當我們需要處理每一幀數據時,我們就要繼承 DShowLib::GrabberListener 類,重新實現 frameReady 這個函數。frameReady 函數就是用來處理圖像的,每當相機內存中有圖片時,相機就會調用 GrabberListener 中的 frameReady 函數。

這裏還要介紹一個叫 FrameHandlerSink 的東西,這是設計採集圖像的模式,一共有兩種模式:

  1. snap採圖模式
    在snap模式下,到達接收器的所有幀都顯示給 IFrameFilter,然後複製到 MemBufferCollection 中。之後調用 GrabberListener 的 frameReady 事件。

  2. grab採集模式
    在grab模式下,所有幀都呈現給 IFrameFilter。如果沒有掛起任何快照作業,則 IFrameFilter::transform 中的目標幀爲0,並且不會調用 frameReady 事件。
    當快照作業掛起時,會在 MemBuffer 中傳遞緩衝區,當 IFrameFilter::transform 返回true時,MemBuffer 將在 GrabberListener 中的 frameReady 事件中顯示。

步驟如下:

  • 添加新的偵聽器對象
    m_Grabber.addListener( this, GrabberListener::eALL );

  • 設置採集模式
    m_Sink->setSnapMode( true ); // true爲snap採圖模式,false爲grab採集模式

  • 重寫 overlayCallback 和 frameReady 函數
    virtual void overlayCallback(Grabber &caller, smart_ptr<OverlayBitmap> pBitmap, const tsMediaSampleDesc &desc) override;
    virtual void frameReady(Grabber &caller, smart_ptr<MemBuffer> pBuffer, DWORD FrameNumber) override;

  • 調用 startLive 開啓實時模式
    m_Grabber.startLive(true);

  • 調用 snapImages 抓取圖片
    m_Sink->snapImages( 1, 2000 ); // 抓取一張圖片,每次調用 snapImages() 之後,就會觸發 Listener 中的 frameReady()

我的代碼

這裏需要說明一下,博主自定義的相機控制類 BICCameraControl 使用了多繼承的方式,這個方法不是很好。我們在開發項目中還是要倡導多用組合,少用繼承,博主在這裏偷懶了。

實現功能:相機圖像的實時顯示,並且可以在某一時刻拍照保存圖片到本地

首先需要在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
        }
    }
}

自定義 BICCameraControl 相機控制類

#ifndef BICCAMERACONTROL_H
#define BICCAMERACONTROL_H

#include <QObject>
#include <tisudshl.h>
#include "Grabber.h"
using namespace _DSHOWLIB_NAMESPACE;

#define NUM_BUFFERS 10

class BICCameraControl : public QObject, public DShowLib::GrabberListener
{
    Q_OBJECT
public:
    explicit BICCameraControl(QObject *parent = nullptr);

    void initCamera();                              // 初始化相機
    void destroyCamera();                           // 銷燬相機

    void setHWND(HWND hwnd);                        // 設置窗口句柄
    void setWindowSize(long width, long height);    // 設置窗口大小

    void openCamera();                              // 打開相機
    void closeCamera();                             // 關閉相機

    void startWork();                               // 開始工作
    void stopWork();                                // 停止工作

    // Overwrite the GrabberListener methods we need.
    virtual void overlayCallback(Grabber &caller, smart_ptr<OverlayBitmap> pBitmap, const tsMediaSampleDesc &desc) override;
    virtual void frameReady(Grabber &caller, smart_ptr<MemBuffer> pBuffer, DWORD FrameNumber) override;

    void takeAPicture();                            // 拍照

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

private:
    HWND m_hwnd;
    long m_width;
    long m_height;
};

#endif // BICCAMERACONTROL_H
#include "biccameracontrol.h"
#include <QMessageBox>
#include <QDebug>

BICCameraControl::BICCameraControl(QObject *parent) : QObject(parent)
{
    DShowLib::InitLibrary();
    atexit(DShowLib::ExitLibrary);
}

void BICCameraControl::initCamera()
{
    // Enable the overlay bitmap to display the frame counter in the live video.
    m_Grabber.setOverlayBitmapPathPosition( ePP_DEVICE );
    m_Grabber.getOverlay( ePP_DEVICE )->setEnable( true );

    // Register the pListener object event.
    m_Grabber.addListener( this, GrabberListener::eALL );

    m_Sink = DShowLib::FrameHandlerSink::create( FrameTypeInfoArray::createRGBArray(), NUM_BUFFERS );
    m_Sink->setSnapMode( true );

    // Apply the sink to the grabber.
    m_Grabber.setSinkType( m_Sink );
}

void BICCameraControl::setHWND(HWND hwnd)
{
    m_hwnd = hwnd;
}

void BICCameraControl::setWindowSize(long width, long height)
{
    m_width = width;
    m_height = height;
}

void BICCameraControl::openCamera()
{
    // Show the device page.
    m_Grabber.showDevicePage();

    // Check if there is a valid device.
    if ( m_Grabber.isDevValid() ) {
        qDebug() << QString::fromStdString(m_Grabber.getDev().toString());

        // Set the window that should display the live video.
        m_Grabber.setHWND(m_hwnd);

        // Enables or disables the default window size lock of the video window.
        m_Grabber.setDefaultWindowPosition(false);
        // Sets the size of the video window.
        m_Grabber.setWindowSize(m_width, m_height);
    }
}

void BICCameraControl::closeCamera()
{
    // Closes the currently active video capture device.
    m_Grabber.closeDev();
}

void BICCameraControl::startWork()
{
    if ( m_Grabber.isLive() ) {
        QMessageBox::warning(NULL, "Warning", "Grabber already in live-mode !", QMessageBox::Ok);
        return;
    }

    // Check if there is a valid device.
    if ( m_Grabber.isDevValid() ) {
        // Start the live video.
        // Set true to enable the live video window, false to grab only.
        m_Grabber.startLive(true);

        if ( m_Grabber.getLastError().isError() )
        {
            QMessageBox::warning(NULL, "Warning", QString::fromStdWString(m_Grabber.getLastError().toStringW()), QMessageBox::Ok);
        }
    }
}

void BICCameraControl::stopWork()
{
    if ( !m_Grabber.isLive() ) {
        QMessageBox::warning(NULL, "Warning", "Grabber already in unlive-mode !", QMessageBox::Ok);
        return;
    }

    m_Grabber.stopLive();

    if ( m_Grabber.getLastError().isError() )
    {
        QMessageBox::warning(NULL, "Warning", QString::fromStdWString(m_Grabber.getLastError().toStringW()), QMessageBox::Ok);
    }
}

void BICCameraControl::overlayCallback(Grabber& caller, smart_ptr<OverlayBitmap> pBitmap, const tsMediaSampleDesc& MediaSampleDesc)
{
    UNREFERENCED_PARAMETER(caller);
    char szText[25];
    if( pBitmap->getEnable() == true ) // Draw only, if the overlay bitmap is enabled.
    {
        sprintf_s( szText, "%04d ", MediaSampleDesc.FrameNumber );
        pBitmap->drawText( RGB(255,0,0), 0, 0, szText );
    }
}

// frameReady() 方法用於處理圖像
void BICCameraControl::frameReady(Grabber& caller, smart_ptr<MemBuffer> pBuffer, DWORD currFrame)
{
    UNREFERENCED_PARAMETER(caller);
    qDebug() << "Buffer " << currFrame << " processed in CListener::frameReady().";

    char filename[MAX_PATH];
    sprintf_s( filename, "image%02i.bmp", currFrame );
    saveToFileBMP( *pBuffer, filename );
}

void BICCameraControl::takeAPicture()
{
    if ( !m_Grabber.isLive() ) {
        QMessageBox::warning(NULL, "Warning", "Grabber already in unlive-mode !", QMessageBox::Ok);
        return;
    }

    m_Sink->snapImages( 1, 2000 );	// 抓取一張圖片,每次調用 snapImages() 之後,就會觸發 Listener 中的 frameReady()
}

使用比較簡單,直接調用就行

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "biccameracontrol.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_openBtn_clicked();

    void on_closeBtn_clicked();

    void on_startBtn_clicked();

    void on_endBtn_clicked();

    void on_picBtn_clicked();

private:
    Ui::MainWindow *ui;
    BICCameraControl *m_BICCameraControl;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_BICCameraControl = new BICCameraControl(this);
    m_BICCameraControl->initCamera();

    //QT中獲取label控件的窗口句柄
    m_BICCameraControl->setHWND((HWND)ui->label->winId());
    m_BICCameraControl->setWindowSize(ui->label->width(), ui->label->height());
};

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_openBtn_clicked()
{
    m_BICCameraControl->openCamera();
}

void MainWindow::on_closeBtn_clicked()
{
    m_BICCameraControl->closeCamera();
}

void MainWindow::on_startBtn_clicked()
{
   m_BICCameraControl->startWork();
}

void MainWindow::on_endBtn_clicked()
{
    m_BICCameraControl->stopWork();
}

void MainWindow::on_picBtn_clicked()
{
    m_BICCameraControl->takeAPicture();
}

其他請參考 Qt調用工業相機之巴斯勒相機

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章