Radiation-resistantCamera/Vimba_6_0/VimbaCPP/Examples/VimbaViewer/Source/FrameObserver.h
2025-04-30 09:26:04 +08:00

354 lines
13 KiB
C++

/*=============================================================================
Copyright (C) 2012 Allied Vision Technologies. All Rights Reserved.
Redistribution of this file, in original or modified form, without
prior written consent of Allied Vision Technologies is prohibited.
-------------------------------------------------------------------------------
File: FrameObserver.h
Description: Frame callback.
-------------------------------------------------------------------------------
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE,
NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/
#ifndef FRAMEOBSERVER_H
#define FRAMEOBSERVER_H
#include <QObject>
#include <QImage>
#include <QVector>
#include <QTime>
#include <QThread>
#include <QStringList>
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
#include "Helper.h"
#include "Histogram/HistogramThread.h"
#include <VimbaCPP/Include/IFrameObserver.h>
#include <VimbaCPP/Include/Frame.h>
#include <VimbaCPP/Include/Camera.h>
#include "VmbImageTransformHelper.hpp"
/* Number of frames in use to count the first FPS since start*/
const unsigned int MAX_FRAMES_TO_COUNT = 50;
using AVT::VmbAPI::CameraPtr;
using AVT::VmbAPI::FramePtr;
#ifdef _WIN32
/*high resolution timer for windows*/
class PrecisionTimer
{
const LARGE_INTEGER m_Frequency;
LARGE_INTEGER m_Time;
static LARGE_INTEGER getFrq()
{
LARGE_INTEGER tmp;
QueryPerformanceFrequency( & tmp );
return tmp;
}
public:
PrecisionTimer()
: m_Frequency( getFrq() )
{
}
LARGE_INTEGER Frequency() const { return m_Frequency; }
LARGE_INTEGER Ticks() const
{
LARGE_INTEGER tmp;
QueryPerformanceCounter( &tmp );
return tmp;
}
void start()
{
QueryPerformanceCounter( &m_Time );
}
double elapsed() const
{
LARGE_INTEGER tmpTime;
QueryPerformanceCounter( &tmpTime );
tmpTime.QuadPart -= m_Time.QuadPart;
return (tmpTime.QuadPart*1000.0)/ m_Frequency.QuadPart;
}
};
typedef PrecisionTimer timer_type;
#else
typedef QTime timer_type;
#endif
/*class to calculate frames per second*/
class FPSCounter
{
double m_CurrentFPS;
timer_type m_Timer;
bool m_IsRunning;
VmbInt64_t m_LastFrameID;
bool m_Valid;
public:
double CurrentFPS() const { return m_CurrentFPS; }
FPSCounter( )
: m_IsRunning( false )
, m_LastFrameID( 0 )
, m_Valid( false )
{
}
void count( VmbInt64_t id )
{
if( ! m_IsRunning )
{
m_LastFrameID = id;
m_IsRunning = true;
m_Valid = false;
m_Timer.start();
return;
}
double time_ms = m_Timer.elapsed();
VmbInt64_t delta_id = id - m_LastFrameID;
if( (time_ms > 1000 && delta_id != 0) )
{
m_CurrentFPS = (delta_id*1000) / time_ms;
m_LastFrameID = id;
m_Valid = true;
m_Timer.start();
}
}
bool isValid() const {return m_Valid;}
void stop()
{
m_CurrentFPS = 0.0;
m_LastFrameID = 0;
m_Valid = false;
m_IsRunning = false;
}
bool isRunning() const { return m_IsRunning; }
};
template <typename T>
class ValueWithState
{
T m_Value;
bool m_isValid;
public:
ValueWithState()
: m_Value( T())
, m_isValid( false )
{
}
ValueWithState( const ValueWithState<T> & o)
: m_Value( o() )
, m_isValid( o.isValid() )
{}
void Invalidate()
{
m_isValid = false;
m_Value = T();
}
bool isValid() const { return m_isValid; }
const T& operator()() const { return m_Value; }
T& operator()() { return m_Value; }
void operator()( const T&o)
{
m_Value = o;
m_isValid = true;
}
};
class ImageProcessingThread : public QThread
{
Q_OBJECT
public:
protected:
struct FrameData
{
private:
bool m_TransferFullBitDepthImage;
tFrameInfo m_FrameInfo;
public:
FrameData()
{}
FrameData( const tFrameInfo &info, bool FullBitDepthImage)
: m_TransferFullBitDepthImage( FullBitDepthImage )
, m_FrameInfo( info )
{}
tFrameInfo FrameInfo() const { return m_FrameInfo; }
bool TransformFullBitDepth() const { return m_TransferFullBitDepthImage; }
bool ColorInterpolation() const { return m_FrameInfo.UseColorInterpolation(); }
QSharedPointer<unsigned char> GetFrameData() const { return m_FrameInfo.DataPtr(); }
VmbPixelFormatType PixelFormat() const { return m_FrameInfo.PixelFormat(); }
VmbUint32_t Width() const { return m_FrameInfo.Width();}
VmbUint32_t Height() const { return m_FrameInfo.Height(); }
VmbUint32_t Size() const { return m_FrameInfo.Size(); }
};
private:
ConsumerQueue<FrameData> m_FrameQueue;
bool m_Stopping;
size_t m_DroppedFrames;
VmbUint64_t m_FrameCount;
FPSCounter m_FPSCounter;
timer_type m_Timer;
bool m_LimitFrameRate;
ValueWithState<double> m_LastTime;
public:
ImageProcessingThread( size_t MaxFrames = 3)
: m_FrameQueue( MaxFrames )
, m_Stopping( false )
, m_DroppedFrames( 0 )
, m_FrameCount ( 0 )
, m_LimitFrameRate( false )
{
m_Timer.start();
}
const FPSCounter & getFPSCounter() const { return m_FPSCounter;}
~ImageProcessingThread()
{
StopProcessing();
}
void StopProcessing()
{
if( ! m_Stopping)
{
m_LastTime.Invalidate();
m_Stopping = true;
m_FrameQueue.StopProcessing();
wait();
}
}
void StartProcessing()
{
m_Stopping = false;
m_FrameQueue.StartProcessing();
start();
}
size_t DroppedFrames() const { return m_DroppedFrames; }
void setThreadFrame ( const tFrameInfo &FrameInfo, bool FullBitDepthImage )
{
FrameData tmpFrameData( FrameInfo,FullBitDepthImage);
m_FrameQueue.Enqueue( tmpFrameData );
}
void LimitFrameRate( bool v ) { m_LimitFrameRate= v; }
private:
protected:
virtual void run();
private:
signals:
void frameReadyFromThread ( QImage image, const QString &sFormat, const QString &sHeight, const QString &sWidth );
void frameReadyFromThreadFullBitDepth ( tFrameInfo mFullImageInfo );
};
class FrameObserver : public QObject, public AVT::VmbAPI::IFrameObserver
{
Q_OBJECT
public:
protected:
private:
typedef QSharedPointer<unsigned char> FrameDataPtr;
FPSCounter m_FPSCamera;
FPSCounter m_FPSReceived;
CameraPtr m_pCam; // camera to wait for frames on
QSharedPointer<HistogramThread> m_pHistogramThread; // histogram calculation thread
unsigned int m_nFrames;
unsigned int m_nFramesCounter; // nr frames received
QSharedPointer<ImageProcessingThread> m_pImageProcessingThread; // Image processing thread
bool m_bIsReset;
bool m_EmitFrame;
/* Saving Raw Data */
unsigned int m_nRawImagesToSave;
unsigned int m_nRawImagesCounter;
QString m_sPathDestination;
QString m_sRawImagesName;
/* Histogram */
bool m_bIsHistogramEnabled;
bool m_bColorInterpolation;
bool m_IsStopping;
QMutex m_StoppingLock;
bool m_bTransferFullBitDepthImage;
public:
void Stopping()
{
m_pImageProcessingThread->StopProcessing();
m_FPSCamera.stop();
m_FPSReceived.stop();
QMutexLocker guard( &m_StoppingLock );
m_IsStopping = true;
}
void Starting()
{
QMutexLocker guard( &m_StoppingLock );
m_IsStopping = false;
m_pImageProcessingThread->StartProcessing();
}
FrameObserver ( CameraPtr pCam );
~FrameObserver ();
virtual void FrameReceived ( const FramePtr frame );
void resetFrameCounter ( bool bIsRestart );
void setDisplayInterval ( unsigned int nInterval );
void saveRawData ( unsigned int nNumberOfRawImagesToSave, const QString &sPath, const QString &sFileName);
void enableHistogram ( bool bIsHistogramEnabled );
void setColorInterpolation ( bool bState);
bool getColorInterpolation ( void );
void enableFullBitDepthTransfer ( bool bIsFullBitDepthEnabled );
void setEmitFrame ( bool bEmitFrame );
protected:
private:
bool setFrame ( const FramePtr &frame );
private slots:
void getFrameFromThread ( QImage image, const QString &sFormat, const QString &sHeight, const QString &sWidth );
void getFullBitDepthFrameFromThread ( tFrameInfo mFullImageInfo );
void getHistogramDataFromThread ( const QVector<QVector <quint32> > &histData, const QString &sHistogramTitle,
const double &nMaxHeight_YAxis, const double &nMaxWidth_XAxis, const QVector <QStringList> &statistics );
signals:
void frameReadyFromObserver ( QImage image, const QString &sFormat, const QString &sHeight, const QString &sWidth );
void frameReadyFromObserverFullBitDepth ( tFrameInfo mFullImageInfo );
void setCurrentFPS ( const QString &sFPS );
void setFrameCounter ( const unsigned int &nFrame );
void histogramDataFromObserver ( const QVector<QVector <quint32> > &histData, const QString &sHistogramTitle,
const double &nMaxHeight_YAxis, const double &nMaxWidth_XAxis, const QVector <QStringList> &statistics );
};
#endif