/*============================================================================= Copyright (C) 2012 - 2016 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.cpp 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. =============================================================================*/ #include "FrameObserver.h" #include "VmbImageTransformHelper.hpp" #include #include #include #include FrameObserver::FrameObserver ( CameraPtr pCam ) : IFrameObserver ( pCam ) , m_nFramesCounter ( 0 ) , m_nRawImagesToSave ( 0 ) , m_nRawImagesCounter ( 0 ) , m_bIsReset ( false ) , m_EmitFrame ( true ) , m_nFrames ( MAX_FRAMES_TO_COUNT ) , m_bIsHistogramEnabled ( false ) , m_bColorInterpolation ( true ) , m_IsStopping ( false ) , m_bTransferFullBitDepthImage ( false ) , m_pCam ( pCam ) { m_pImageProcessingThread = QSharedPointer(new ImageProcessingThread()); m_pHistogramThread = QSharedPointer(new HistogramThread()); connect ( m_pImageProcessingThread.data(), SIGNAL ( frameReadyFromThread (QImage, const QString &, const QString &, const QString &) ), this, SLOT ( getFrameFromThread (QImage, const QString &, const QString &, const QString &) ) ); connect ( m_pImageProcessingThread.data(), SIGNAL ( frameReadyFromThreadFullBitDepth ( tFrameInfo) ), this, SLOT ( getFullBitDepthFrameFromThread ( tFrameInfo) ) ); // We need to register QVector because it is not known to Qt's meta-object system qRegisterMetaType< QVector > >("QVector >"); qRegisterMetaType< QVector >("QVector "); // register tFrameInfo type to use with frameReadyFromObserver signal qRegisterMetaType< tFrameInfo >("tFrameInfo"); connect ( m_pHistogramThread.data(), SIGNAL ( histogramDataFromThread ( const QVector > &, const QString &, const double &, const double &, const QVector & )), this, SLOT ( getHistogramDataFromThread ( const QVector > &, const QString &, const double &, const double &, const QVector& )) ); } FrameObserver::~FrameObserver ( void ) { if( NULL != m_pImageProcessingThread || m_pImageProcessingThread->isRunning() ) { m_pImageProcessingThread->quit(); } } void FrameObserver::FrameReceived ( const AVT::VmbAPI::FramePtr frame ) { QMutexLocker guard ( &m_StoppingLock ); if( m_IsStopping ) { return; } VmbFrameStatusType statusType = VmbFrameStatusInvalid; if( VmbErrorSuccess == frame->GetReceiveStatus(statusType) ) { /* ignore any incompletely frame */ if( VmbFrameStatusComplete != statusType ) { m_pCam->QueueFrame(frame); return; } m_nFramesCounter++; emit setFrameCounter ( m_nFramesCounter ); m_FPSReceived.count( m_nFramesCounter ); VmbUint64_t camera_frame_id; frame->GetFrameID( camera_frame_id ); m_FPSCamera.count( camera_frame_id ); static const char token[] = {'-','\\','|','/'}; QString fps(token[ m_nFramesCounter%4] ); if( m_FPSReceived.isValid() ) { fps = QString("Rcv:") + QString::number( static_cast(m_FPSReceived.CurrentFPS()*100)/100.0 ); if( m_FPSCamera.isValid() ) { fps += " Cam:" + QString::number(static_cast(m_FPSCamera.CurrentFPS()*100)/100.0 ); } if( m_pImageProcessingThread->getFPSCounter().isValid() ) { fps += " Dis:" + QString::number(static_cast(m_pImageProcessingThread->getFPSCounter().CurrentFPS()*100)/100.0 ); } } emit setCurrentFPS( fps ); if( m_EmitFrame ) { setFrame( frame ); } } m_pCam->QueueFrame(frame); } void FrameObserver::enableHistogram ( bool bIsHistogramEnabled ) { m_bIsHistogramEnabled = bIsHistogramEnabled; } void FrameObserver::setColorInterpolation (bool bState ) { m_bColorInterpolation = bState; } bool FrameObserver::getColorInterpolation ( void ) { return m_bColorInterpolation; } void FrameObserver::enableFullBitDepthTransfer(bool bIsFullBitDepthEnabled) { m_bTransferFullBitDepthImage = bIsFullBitDepthEnabled; } void FrameObserver::setEmitFrame( bool bEmitFrame ) { m_EmitFrame = bEmitFrame; } void FrameObserver::setDisplayInterval ( unsigned int nInterval ) { m_pImageProcessingThread->LimitFrameRate( nInterval != 0 ); } void FrameObserver::resetFrameCounter ( bool bIsRestart ) { if( bIsRestart ) { m_nFramesCounter = 0; } m_nFrames = MAX_FRAMES_TO_COUNT; m_bIsReset = true; emit setCurrentFPS ( "-" ); } bool FrameObserver::setFrame (const AVT::VmbAPI::FramePtr &frame ) { try { tFrameInfo tmpInfo( frame, m_bColorInterpolation ); m_pImageProcessingThread->setThreadFrame( tmpInfo, m_bTransferFullBitDepthImage); if(m_bIsHistogramEnabled) { m_pHistogramThread->setThreadFrame ( tmpInfo ); m_pHistogramThread->start(); } /* saving Raw Data */ if( m_nRawImagesToSave > 0) { m_nRawImagesCounter++; QString s = m_sPathDestination; s.append("\\"); s.append(m_sRawImagesName).append(QString::number(m_nRawImagesCounter)).append(".bin"); m_nRawImagesToSave--; QFile rawFile(s); rawFile.open(QIODevice::WriteOnly); QDataStream out(&rawFile); out.writeRawData((const char*)tmpInfo.Data(), tmpInfo.Size() ); rawFile.close(); } } catch (...) { return false; } return true; } void FrameObserver::saveRawData ( unsigned int nNumberOfRawImagesToSave, const QString& sPath, const QString &sFileName ) { m_nRawImagesCounter = 0; m_nRawImagesToSave = nNumberOfRawImagesToSave; m_sPathDestination = sPath; m_sRawImagesName = sFileName; } void FrameObserver::getFrameFromThread ( QImage image, const QString &sFormat, const QString &sHeight, const QString &sWidth ) { emit frameReadyFromObserver (image, sFormat, sHeight, sWidth); } void FrameObserver::getFullBitDepthFrameFromThread ( tFrameInfo mFullImageInfo ) { if ( true == m_bTransferFullBitDepthImage ) { emit frameReadyFromObserverFullBitDepth ( mFullImageInfo ); } } void FrameObserver::getHistogramDataFromThread ( const QVector > &histData, const QString &sHistogramTitle, const double &nMaxHeight_YAxis, const double &nMaxWidth_XAxis ,const QVector &statistics) { emit histogramDataFromObserver ( histData, sHistogramTitle, nMaxHeight_YAxis, nMaxWidth_XAxis, statistics ); } void ImageProcessingThread::run() { FrameData tmpFrameData; while( !m_Stopping && m_FrameQueue.WaitData( tmpFrameData) ) { if( m_LimitFrameRate ) { double currentTime = m_Timer.elapsed(); if ( m_LastTime.isValid() ) { const double frameLimit = 33.0; // limit about time for 33 fps const double deltaTime = currentTime - m_LastTime(); if( frameLimit > deltaTime) { continue; } const double newTime =currentTime + (frameLimit - deltaTime); m_LastTime(newTime); } else { m_LastTime( currentTime); } } m_FrameCount++; m_FPSCounter.count( m_FrameCount ); QImage convertedImage( tmpFrameData.Width(), tmpFrameData.Height(), QImage::Format_RGB32 ); if(! convertedImage.isNull()) { if (NULL != tmpFrameData.GetFrameData()) // unlikely { VmbError_t error; VmbPixelFormatType outputPixelFormat; if(tmpFrameData.ColorInterpolation()) { outputPixelFormat = tmpFrameData.PixelFormat(); } else { try { outputPixelFormat = AVT::GetCompatibleMonoPixelFormatForRaw(tmpFrameData.PixelFormat() ) ; } catch(...)// lands here if GetCompatibleMonoPixelFromatForRaw throws { outputPixelFormat =tmpFrameData.PixelFormat() ; } } error = AVT::VmbImageTransform( convertedImage, tmpFrameData.GetFrameData().data(), tmpFrameData.Width(), tmpFrameData.Height(), outputPixelFormat ); QString sFormat = Helper::convertFormatToString( outputPixelFormat ); if( VmbErrorSuccess != error ) { sFormat = "Convert Error: " + QString::number(error,16); if( VmbErrorBadParameter == error ) if (((tmpFrameData.Width()%4!=0) || (tmpFrameData.Height()%2!=0))) { sFormat.append(" (height or width not supported!)"); } else { sFormat.append(" (PixelFormat not supported!)"); } convertedImage = QImage(); } { if( !m_Stopping ) { emit frameReadyFromThread (convertedImage, sFormat, QString::number (tmpFrameData.Height() ), QString::number (tmpFrameData.Width() )); } } } } // send the full bit depth image if requested if ( true == tmpFrameData.TransformFullBitDepth() ) { emit frameReadyFromThreadFullBitDepth ( tmpFrameData.FrameInfo() ); } } }