欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Basler相机实时图像显示--Qt代码

程序员文章站 2022-07-13 14:56:55
...

Balser相机

​ 前段时间,因为项目需要,师傅让我用Qt写巴斯勒相机实时画面的显示,网上找了好多资料,愚笨的我也没有弄明白该如何写,从相机的SDK中找到了用MFC写的例子,咱也没用过MFC呀,看不懂哎,最后师傅出马,写了一下,相机图像转换的位置师傅用他之前写的图像转换类,属于公司产品,我例子中就没用这个类,转而用opencv进行转换(网上找到的方法),本文后面会附上源码。

本程序的环境:

Pylon 6.0.0 + Opencv 4.1.0 +Qt 5.12.3 + Vs 2017 Community

pylon 6.0.0 : Pylon 6.0 下载地址

vs下的头文件包含

下面只说明Balser的头文件包含,opencv 和qt的头文件包含这里忽略。

下载好之后,包含include

Basler相机实时图像显示--Qt代码

在其中填写如下路径:

XXX\Development\include
XXX\Development\Samples\C++\include 

XXX\Development\Samples\C++\include路径也可以不包含,我是用来测试sample程序的,本源码就是仿照XXX/Development\Samples\C++\GUI_MFC这个Demo来写的。

下面来包含lib:

Basler相机实时图像显示--Qt代码
在其中填写如下路径:

XXX/Development\lib\x64 #我用的是X64版本的,X86请改为Win32

Basler相机实时图像显示--Qt代码

源码讲解:

main.c
#include "BaslerCamera_RealTimeShow.h"
#include <QtWidgets/QApplication>


class PreWork
{
public:
	PreWork()
	{
		Pylon::PylonInitialize();//相机的初始化程序,把它理解为安装
	}

	~PreWork()
	{
		Pylon::PylonTerminate();//停止运行相机的执行函数,把它理解为卸载
	}
};

int main(int argc, char *argv[])
{
  PreWork p;
   //主要说明这一点,巧用构造函数和析构函数,来对相机进行安装和卸载
    
  QApplication a(argc, argv);

  BaslerCamera_RealTimeShow w;
  w.show();
  return a.exec();
}
Basler.c
#include "BaslerCamera_RealTimeShow.h"
#include <QDebug>
#include <QPainter>
#include <QRect>

BaslerCamera_RealTimeShow::BaslerCamera_RealTimeShow(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    m_camera.RegisterImageEventHandler(this, Pylon::RegistrationMode_ReplaceAll, Pylon::Ownership_ExternalOwnership);
    // Register this object as a configuration event handler, so we will be notified of camera state changes.
    // See Pylon::CConfigurationEventHandler for details
    m_camera.RegisterConfiguration(this, Pylon::RegistrationMode_ReplaceAll, Pylon::Ownership_ExternalOwnership);

    // Add the AutoPacketSizeConfiguration and let pylon delete it when not needed anymore.
    m_camera.RegisterConfiguration(new CAutoPacketSizeConfiguration(), Pylon::RegistrationMode_Append, Pylon::Cleanup_Delete);

  	m_camera.Attach(Pylon::CTlFactory::GetInstance().CreateFirstDevice(), Pylon::Cleanup_Delete);

    m_camera.Open();

    // Camera may have been disconnected.
    if (!m_camera.IsOpen() || m_camera.IsGrabbing())
    {
      return;
    }

    // Since we may switch between single and continuous shot, we must configure the camera accordingly.
    // The predefined configurations are only executed once when the camera is opened.
    // To be able to use them in our use case, we just call them explicitly to apply the configuration.
    m_continousConfiguration.OnOpened(m_camera);

    // Start grabbing until StopGrabbing() is called.
    m_camera.StartGrabbing(Pylon::GrabStrategy_OneByOne, Pylon::GrabLoop_ProvidedByInstantCamera);

    ui.centralWidget->installEventFilter(this);//安装Qt的事件过滤器

    connect(this, SIGNAL(OneImageFinishSignal()), this, SLOT(OneImageFinishSlot()));

}

void BaslerCamera_RealTimeShow::OnImagesSkipped(Pylon::CInstantCamera& camera, size_t countOfSkippedImages)
{

}
void BaslerCamera_RealTimeShow::OnImageGrabbed(Pylon::CInstantCamera& camera, const Pylon::CGrabResultPtr& grabResult)
{

  m_mutexLock.lock();

  m_ptrGrabResult = grabResult;//将捕获到的图像传递出去

  //qDebug() << __FUNCTION__;

  emit OneImageFinishSignal();

  m_mutexLock.unlock();
  
}

void BaslerCamera_RealTimeShow::OneImageFinishSlot()
{
  //qDebug() << __FUNCTION__;
  ui.centralWidget->update();
}
bool BaslerCamera_RealTimeShow::eventFilter(QObject *watched, QEvent *event)
{
  if (watched == ui.centralWidget && event->type() == QEvent::Paint)
  {
    showImage();
  }
  return false;
}
void BaslerCamera_RealTimeShow::showImage()
{	
  
  m_mutexLock.lock();

  //qDebug() << "123" << endl;

	// 新建pylon ImageFormatConverter对象.
	CImageFormatConverter formatConverter;

	Mat openCvImage;
	QPainter painter(ui.centralWidget);

	//确定输出像素格式
	formatConverter.OutputPixelFormat = PixelType_BGR8packed;
	//将抓取的缓冲数据转化成pylon image.
	formatConverter.Convert(m_bitmapImage, m_ptrGrabResult);

	// 将 pylon image转成OpenCV image.
	openCvImage = cv::Mat(m_ptrGrabResult->GetHeight(), m_ptrGrabResult->GetWidth(), CV_8UC3, (uint8_t *)m_bitmapImage.GetBuffer());

	QImage img((const unsigned char *)(openCvImage.data), openCvImage.cols, openCvImage.rows, openCvImage.cols * 3, QImage::Format_RGB888);

	QRectF target;
	target.setLeft(0);
	target.setTop(0);
	target.setSize(this->size());

	QRectF source;
	source.setLeft(0);
	source.setTop(0);
	source.setSize(img.size());

	painter.drawImage(target,img, source);

  m_mutexLock.unlock();


}

// Pylon::CConfigurationEventHandler functions
void BaslerCamera_RealTimeShow::OnAttach(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnAttached(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnDetach(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnDetached(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnDestroy(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnDestroyed(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnOpen(Pylon::CInstantCamera& camera)
{
  Pylon::String_t strFriendlyName = camera.GetDeviceInfo().GetFriendlyName();
  qDebug() << __FUNCTION__ << " - " << strFriendlyName.c_str();
}


void BaslerCamera_RealTimeShow::OnOpened(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnClose(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnClosed(Pylon::CInstantCamera& camera)
{
  Pylon::String_t strFriendlyName = camera.GetDeviceInfo().GetFriendlyName();
  qDebug() << __FUNCTION__ << " - " << strFriendlyName.c_str();
}


void BaslerCamera_RealTimeShow::OnGrabStart(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnGrabStarted(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnGrabStop(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnGrabStopped(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
  m_camera.DeregisterConfiguration(&m_continousConfiguration);
}


void BaslerCamera_RealTimeShow::OnGrabError(Pylon::CInstantCamera& camera, const char* errorMessage)
{
  qDebug() << __FUNCTION__;
}


void BaslerCamera_RealTimeShow::OnCameraDeviceRemoved(Pylon::CInstantCamera& camera)
{
  qDebug() << __FUNCTION__;
}

BaslerCamera_RealTimeShow::~BaslerCamera_RealTimeShow()
{
   Perform cleanup.
  if (m_camera.IsPylonDeviceAttached())
  {
    try
    {
      // Close camera.
      // This will also stop the grab.
      m_camera.Close();

      // Free the camera.
      // This will also stop the grab and close the camera.
      m_camera.DestroyDevice();
    }
    catch (const Pylon::GenericException& e)
    {
      qDebug() << e.what();
    }
  }
}
Balser.h
#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_BaslerCamera_RealTimeShow.h"
#include "AutoPacketSizeConfiguration.h"

//加载PYLON API.
#include <pylon/PylonIncludes.h>
#include <pylon/gige/BaslerGigECamera.h>
#include <iostream>
#include <QMutex>


// 加载OpenCV API
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/video.hpp>
#include <opencv2/opencv.hpp>

//命名空间.
using namespace Pylon;
using namespace std;
using namespace cv;

class BaslerCamera_RealTimeShow : public QMainWindow                                     
                                    , public Pylon::CImageEventHandler             // Allows you to get informed about received images and grab errors.
                                    , public Pylon::CConfigurationEventHandler     // Allows you to get informed about device removal.

{
    Q_OBJECT

signals:
  void OneImageFinishSignal();
private slots:
  void OneImageFinishSlot();

public:
    BaslerCamera_RealTimeShow(QWidget *parent = Q_NULLPTR);
    ~BaslerCamera_RealTimeShow();

private:
    Ui::BaslerCamera_RealTimeShowClass ui;

    Pylon::CInstantCamera m_camera;
    // The grab result retrieved from the camera
    Pylon::CGrabResultPtr m_ptrGrabResult;
    // The grab result as a windows DIB to be displayed on the screen
    Pylon::CPylonBitmapImage m_bitmapImage;
    Pylon::CAcquireContinuousConfiguration m_continousConfiguration;

    QMutex m_mutexLock;

protected:
	  void showImage();
    virtual bool eventFilter(QObject *watched, QEvent *event);
  
    // Pylon::CImageEventHandler functions
    virtual void OnImagesSkipped(Pylon::CInstantCamera& camera, size_t countOfSkippedImages);
    virtual void OnImageGrabbed(Pylon::CInstantCamera& camera, const Pylon::CGrabResultPtr& grabResult);

    // Pylon::CConfigurationEventHandler functions
    virtual void OnAttach(Pylon::CInstantCamera& camera);
    virtual void OnAttached(Pylon::CInstantCamera& camera);
    virtual void OnDetach(Pylon::CInstantCamera& camera);
    virtual void OnDetached(Pylon::CInstantCamera& camera);
    virtual void OnDestroy(Pylon::CInstantCamera& camera);
    virtual void OnDestroyed(Pylon::CInstantCamera& camera);
    virtual void OnOpen(Pylon::CInstantCamera& camera);
    virtual void OnOpened(Pylon::CInstantCamera& camera);
    virtual void OnClose(Pylon::CInstantCamera& camera);
    virtual void OnClosed(Pylon::CInstantCamera& camera);
    virtual void OnGrabStart(Pylon::CInstantCamera& camera);
    virtual void OnGrabStarted(Pylon::CInstantCamera& camera);
    virtual void OnGrabStop(Pylon::CInstantCamera& camera);
    virtual void OnGrabStopped(Pylon::CInstantCamera& camera);
    virtual void OnGrabError(Pylon::CInstantCamera& camera, const char* errorMessage);
    virtual void OnCameraDeviceRemoved(Pylon::CInstantCamera& camera);

};

main.c内容很简单,执行安装和卸载的函数

Balser.c在这里着重说明一下:

先说一下Balser获取实时图像的原理吧,网上也有很多,这里按照我的理解写一下。

1、Basler获取实时图像是一张一张的拍照,拍照-显示-拍照-显示…,所以我们看到的就是连续的图像。

2、Basler是事件驱动的,当拍完一张照片之后,会触发事件,然后执行的Balser提供的OnImageGrabbed函数, 这个原理可以理解为Qt的信号-槽

Balser.c的程序流程

捕获图像 —> 触发信号(事件)—> 执行OnImageGrabbed()函数,将图像保存到我们定义的类中(这里注意下m_mutexLock.lock();的使用,因为巴斯勒相机处理图像是多线程的,所以在使用变量的时候,要用线程锁保护)—>发送我们自定义的信号-因为构造函数已经连接好了信号与槽-执行OneImageFinishSlot()中的updata触发 event事件,判断该窗体时centralWidget,事件为QEvent::Paint,执行显示函数showImage()。显示函数就是把图像转换一下格式,用Painter画一下图(也用到了线程锁)

最后的源码:

​ 总结一下,本人实力有限,写的比较啰嗦,希望大家能看懂。

​ 如果大家下载源码,附上CSDN和Gitee链接,如果大家CSDN积分多,就赞助点小弟,如果没有积分,请使用Gitee链接。

最后附上下载链接:

CSDN链接地址:CSDN

Gitee链接地址:Gitee