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
在其中填寫如下路徑:
XXX\Development\include
XXX\Development\Samples\C++\include
XXX\Development\Samples\C++\include路徑也可以不包含,我是用來測試sample程序的,本源碼就是仿照XXX/Development\Samples\C++\GUI_MFC這個Demo來寫的。
下面來包含lib:
在其中填寫如下路徑:
XXX/Development\lib\x64 #我用的是X64版本的,X86請改爲Win32
源碼講解:
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