#ifdef _MSC_VER
# if _MSC_VER < 1300
# pragma warning( disable : 4786 )
# endif
#endif
#include <iostream>
#include <apps/Common/exampleHelper.h>
#include <cassert>
#include <iomanip>
#include <limits>
#include <common/crt/mvstdio.h>
#if defined(linux) || defined(__linux) || defined(__linux__)
# include <sys/time.h>
# include <unistd.h>
#else
# include <windows.h>
# undef min
# undef max
# include <process.h>
#endif
using namespace std;
static bool s_boTerminated = false;
static void checkedMethodCall( Device* pDev, Method& method );
static double getMinimalExposureTime( void );
static int64_type getOverallSequenceLength( void );
#if defined(linux) || defined(__linux) || defined(__linux__)
class CTime
{
struct timespec m_tsStart;
struct timespec m_tsEnd;
clockid_t m_ClockId;
long diffTime( void )
{
clock_gettime( m_ClockId, &m_tsEnd );
static struct timespec tsDiff;
tsDiff.tv_sec = m_tsEnd.tv_sec - m_tsStart.tv_sec ;
tsDiff.tv_nsec = m_tsEnd.tv_nsec - m_tsStart.tv_nsec ;
if( tsDiff.tv_nsec < 0 )
{
tsDiff.tv_nsec += 1000000000 ;
tsDiff.tv_sec -= 1;
}
return tsDiff.tv_sec * 1000 + tsDiff.tv_nsec / 1000000;
}
public:
explicit CTime() : m_tsStart(), m_tsEnd(), m_ClockId( CLOCK_REALTIME )
{
#ifdef USE_MONOTONIC_CLOCK
struct timespec ts;
m_ClockId = ( clock_gettime( CLOCK_MONOTONIC, &ts ) == 0 ) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
#endif
start();
}
void start( void )
{
clock_gettime( m_ClockId, &m_tsStart );
}
double elapsed( void )
{
return static_cast<double>( diffTime() / 1000. );
}
double restart( void )
{
double result = elapsed();
m_tsStart = m_tsEnd;
return result;
}
};
#else
class CTime
{
LARGE_INTEGER frequency_;
LARGE_INTEGER start_;
LARGE_INTEGER end_;
public:
explicit CTime()
{
QueryPerformanceFrequency( &frequency_ );
QueryPerformanceCounter( &start_ );
}
void start( void )
{
QueryPerformanceCounter( &( start_ ) );
}
double elapsed( void )
{
QueryPerformanceCounter( &end_ );
return static_cast<double>( end_.QuadPart - start_.QuadPart ) / frequency_.QuadPart;
}
double restart( void )
{
QueryPerformanceCounter( &end_ );
double result = static_cast<double>( end_.QuadPart - start_.QuadPart ) / frequency_.QuadPart;
start_ = end_;
return result;
}
};
#endif
struct SequencerSetParameter
{
const int64_type setNr_;
const int64_type sequencerSetNext_;
const double exposureTime_us_;
const int64_type frameCount_;
const int64_type horizontalBinningOrDecimation_;
const int64_type verticalBinningOrDecimation_;
double expectedFrameRate_;
explicit SequencerSetParameter( const int64_type setNr, const int64_type sequencerSetNext, const double exposureTime_us, const int64_type frameCount, const int64_type horizontalBinningOrDecimation, const int64_type verticalBinningOrDecimation ) :
setNr_( setNr ), sequencerSetNext_( sequencerSetNext ), exposureTime_us_( exposureTime_us ), frameCount_( frameCount ), horizontalBinningOrDecimation_( horizontalBinningOrDecimation ), verticalBinningOrDecimation_( verticalBinningOrDecimation ), expectedFrameRate_( 0.0 )
{
}
};
struct ThreadParameter
{
Device* pDev;
FunctionInterface fi;
Statistics statistics;
GenICam::AcquisitionControl ac;
GenICam::ImageFormatControl ifc;
GenICam::ChunkDataControl cdc;
GenICam::CounterAndTimerControl ctc;
GenICam::SequencerControl sc;
#if defined(linux) || defined(__linux) || defined(__linux__)
explicit ThreadParameter( Device* p ) : pDev( p ), fi( pDev ), statistics( pDev ), ac( pDev ), ifc( pDev ), cdc( pDev ), ctc( pDev ), sc( pDev )
{
}
#else
ImageDisplayWindow displayWindow;
explicit ThreadParameter( Device* p, const string& windowTitle ) : pDev( p ), fi( pDev ), statistics( pDev ), ac( pDev ), ifc( pDev ), cdc( pDev ), ctc( pDev ), sc( pDev ), displayWindow( windowTitle )
{
}
#endif
};
static SequencerSetParameter s_SequencerData[] =
{
#define USE_EXTENDED_SEQUENCER
#ifdef USE_EXTENDED_SEQUENCER
SequencerSetParameter( 0, 1, 1000., 5, 2, 2 ),
SequencerSetParameter( 1, 2, 2000., 16, 2, 2 ),
SequencerSetParameter( 2, 3, 2000., 8, 1, 1 ),
SequencerSetParameter( 3, 4, 10000., 16, 1, 1 ),
SequencerSetParameter( 4, 5, 5000., 5, 1, 1 ),
SequencerSetParameter( 5, 6, 2000., 5, 2, 2 ),
SequencerSetParameter( 6, 7, 1000., 16, 2, 2 ),
SequencerSetParameter( 7, 8, 5000., 8, 1, 1 ),
SequencerSetParameter( 8, 9, 10000., 16, 1, 1 ),
SequencerSetParameter( 9, 0, 15000., 5, 1, 1 )
#else
SequencerSetParameter( 0, 1, 1000., 5, 1, 1 ),
SequencerSetParameter( 1, 2, 15000., 40, 1, 1 ),
SequencerSetParameter( 2, 3, 2000., 20, 1, 1 ),
SequencerSetParameter( 3, 4, 10000., 40, 1, 1 ),
SequencerSetParameter( 4, 0, 5000., 5, 1, 1 )
#endif
};
void configureDevice( Device* pDev )
{
try
{
GenICam::UserSetControl usc( pDev );
conditionalSetEnumPropertyByString( usc.userSetSelector, "Default" );
{
cout << "An error occurred while restoring the factory default for device " << pDev->serial.read()
}
GenICam::AcquisitionControl acqc( pDev );
conditionalSetEnumPropertyByString( acqc.exposureMode, "Timed" );
conditionalSetEnumPropertyByString( acqc.exposureAuto, "Off" );
GenICam::AnalogControl ac( pDev );
if( ac.gainSelector.isValid() )
{
vector<string> validGainSelectorValues;
ac.gainSelector.getTranslationDictStrings( validGainSelectorValues );
const vector<string>::size_type cnt = validGainSelectorValues.size();
for( vector<string>::size_type i = 0; i < cnt; i++ )
{
conditionalSetEnumPropertyByString( ac.gainSelector, validGainSelectorValues[i] );
conditionalSetEnumPropertyByString( ac.gainAuto, "Off" );
}
}
else
{
conditionalSetEnumPropertyByString( ac.gainAuto, "Off" );
}
GenICam::ChunkDataControl cdc( pDev );
cdc.chunkModeActive.write(
bTrue );
GenICam::CounterAndTimerControl ctc( pDev );
ctc.counterSelector.writeS( "Counter1" );
ctc.counterEventSource.writeS( "ExposureEnd" );
ctc.counterTriggerSource.writeS( "Counter1End" );
ctc.timerSelector.writeS( "Timer1" );
ctc.timerDuration.write( getMinimalExposureTime() );
ctc.timerTriggerSource.writeS( "Timer1End" );
acqc.triggerSelector.writeS( "FrameStart" );
acqc.triggerMode.writeS( "On" );
acqc.triggerSource.writeS( "Timer1End" );
conditionalSetEnumPropertyByString( acqc.mvAcquisitionFrameRateLimitMode, "mvDeviceLinkThroughput" );
conditionalSetEnumPropertyByString( acqc.mvAcquisitionFrameRateEnable, "Off" );
SystemSettings ss( pDev );
ss.requestCount.write( static_cast<int>( getOverallSequenceLength() ) );
ImageProcessing ip( pDev );
ip.colorProcessing.write(
cpmRaw );
if( ip.tapSortEnable.isValid() )
{
ip.tapSortEnable.write(
bFalse );
}
}
catch( const ImpactAcquireException& e )
{
cout << "An error occurred while configuring the device " << pDev->serial.read()
<< "(error code: " << e.getErrorCodeAsString() << ")." << endl
<< "Press [ENTER] to end the application..." << endl;
cin.get();
exit( 1 );
}
}
void configureSequencerSet( ThreadParameter* pThreadParameter, const SequencerSetParameter& ssp )
{
pThreadParameter->sc.sequencerSetSelector.write( ssp.setNr_ );
pThreadParameter->ac.exposureTime.write( ssp.exposureTime_us_ );
if( pThreadParameter->ifc.binningHorizontal.isValid() )
{
pThreadParameter->ifc.binningHorizontal.write( ssp.horizontalBinningOrDecimation_ );
}
else if( pThreadParameter->ifc.decimationHorizontal.isValid() )
{
pThreadParameter->ifc.decimationHorizontal.write( ssp.horizontalBinningOrDecimation_ );
}
if( pThreadParameter->ifc.binningVertical.isValid() )
{
pThreadParameter->ifc.binningVertical.write( ssp.verticalBinningOrDecimation_ );
}
else if( pThreadParameter->ifc.decimationVertical.isValid() )
{
pThreadParameter->ifc.decimationVertical.write( ssp.verticalBinningOrDecimation_ );
}
pThreadParameter->ifc.height.write( pThreadParameter->ifc.heightMax.read() );
pThreadParameter->ctc.counterDuration.write( ssp.frameCount_ );
pThreadParameter->sc.sequencerPathSelector.write( 0LL );
pThreadParameter->sc.sequencerTriggerSource.writeS( "Counter1End" );
pThreadParameter->sc.sequencerSetNext.write( ssp.sequencerSetNext_ );
checkedMethodCall( pThreadParameter->pDev, pThreadParameter->sc.sequencerSetSave );
}
void configureSequencer( ThreadParameter* pThreadParameter )
{
try
{
pThreadParameter->sc.sequencerMode.writeS( "Off" );
pThreadParameter->sc.sequencerConfigurationMode.writeS( "On" );
pThreadParameter->sc.sequencerFeatureSelector.writeS( "ExposureTime" );
pThreadParameter->sc.sequencerFeatureEnable.write(
bTrue );
pThreadParameter->sc.sequencerFeatureSelector.writeS( "CounterDuration" );
pThreadParameter->sc.sequencerFeatureEnable.write(
bTrue );
const size_t cnt = sizeof( s_SequencerData ) / sizeof( s_SequencerData[0] );
for( size_t i = 0; i < cnt; i++ )
{
configureSequencerSet( pThreadParameter, s_SequencerData[i] );
s_SequencerData[i].expectedFrameRate_ = pThreadParameter->ac.mvResultingFrameRate.read();
}
pThreadParameter->sc.sequencerSetStart.write( 0 );
pThreadParameter->sc.sequencerConfigurationMode.writeS( "Off" );
pThreadParameter->sc.sequencerMode.writeS( "On" );
}
catch( const ImpactAcquireException& e )
{
cout << "An error occurred while setting up the sequencer for device " << pThreadParameter->pDev->serial.read()
<< "(error code: " << e.getErrorCodeAsString() << ")." << endl;
s_boTerminated = true;
}
}
size_t getExpectedSequencerSet( int64_type frameNr )
{
const size_t cnt = sizeof( s_SequencerData ) / sizeof( s_SequencerData[0] );
int64_type framesUpToHere = 0LL;
for( size_t i = 0; i < cnt; i++ )
{
framesUpToHere += s_SequencerData[i].frameCount_;
if( frameNr < framesUpToHere )
{
return i;
}
}
return 0xFFFFFFFF;
}
double getMinimalExposureTime( void )
{
const size_t cnt = sizeof( s_SequencerData ) / sizeof( s_SequencerData[0] );
double minExposureTime_us = numeric_limits<double>::max();
for( size_t i = 0; i < cnt; i++ )
{
if( minExposureTime_us > s_SequencerData[i].exposureTime_us_ )
{
minExposureTime_us = s_SequencerData[i].exposureTime_us_;
}
}
assert( minExposureTime_us != numeric_limits<double>::max() );
return minExposureTime_us;
}
int64_type getOverallSequenceLength( void )
{
const size_t cnt = sizeof( s_SequencerData ) / sizeof( s_SequencerData[0] );
int64_type overallFrameCount = 0LL;
for( size_t i = 0; i < cnt; i++ )
{
overallFrameCount += s_SequencerData[i].frameCount_;
}
return overallFrameCount;
}
double getPureAcquisitionTimeOfCapturedFrames( const int64_type framesCaptured )
{
const size_t cnt = sizeof( s_SequencerData ) / sizeof( s_SequencerData[0] );
int64_type framesProcessed = 0;
double pureAcquisitionTime_us = 0.0;
for( size_t i = 0; i < cnt; i++ )
{
const int64_type framesToConsider = ( ( framesProcessed + s_SequencerData[i].frameCount_ ) > framesCaptured ) ? framesCaptured - framesProcessed : s_SequencerData[i].frameCount_;
if( ( s_SequencerData[i].expectedFrameRate_ > 0.0 ) &&
( ( 1.0 / s_SequencerData[i].expectedFrameRate_ * 1000000. ) > s_SequencerData[i].exposureTime_us_ ) )
{
pureAcquisitionTime_us += ( 1.0 / s_SequencerData[i].expectedFrameRate_ * 1000000. ) * framesToConsider;
}
else
{
pureAcquisitionTime_us += s_SequencerData[i].exposureTime_us_ * framesToConsider;
}
framesProcessed += framesToConsider;
if( framesProcessed >= framesCaptured )
{
break;
}
}
return pureAcquisitionTime_us / 1000000.;
}
void storeRawFrame( Request* pRequest )
{
const void* pData = pRequest->imageData.read();
if( pData )
{
ostringstream fileName;
fileName << "image" << setw( 6 ) << setfill( '0' ) << pRequest->infoFrameID.read() << "_"
<< "Set=" << pRequest->chunkSequencerSetActive.read() << "_"
<< "Exposure=" << static_cast<unsigned int>( pRequest->chunkExposureTime.read() ) << "."
<< pRequest->imageWidth.read() << "x" << pRequest->imageHeight.read()
<< "." << pRequest->imagePixelFormat.readS();
if( pRequest->imageBayerMosaicParity.read() !=
bmpUndefined )
{
fileName << "(BayerPattern=" << pRequest->imageBayerMosaicParity.readS() << ")";
}
fileName << ".raw";
FILE* pFile = mv_fopen_s( fileName.str().c_str(), "wb" );
if( pFile )
{
if( fwrite( pData, pRequest->imageSize.read(), 1, pFile ) != 1 )
{
cout << "Failed to write file '" << fileName.str() << "'." << endl;
}
else
{
cout << "Successfully written file '" << fileName.str() << "'." << endl;
}
fclose( pFile );
}
}
}
void checkedMethodCall( Device* pDev, Method& method )
{
{
cout << "An error was returned while calling function '" << method.displayName() << "' on device " << pDev->serial.read()
}
}
unsigned int DMR_CALL liveThread( void* pData )
{
ThreadParameter* pThreadParameter = reinterpret_cast<ThreadParameter*>( pData );
CTime timer;
const int64_type orgWidth = pThreadParameter->ifc.width.read();
const int64_type orgHeight = pThreadParameter->ifc.height.read();
cout << "OrgWidth = " << orgWidth << " OrgHeight = " << orgHeight << endl;
configureDevice( pThreadParameter->pDev );
cout << "Setting up the device took " << timer.restart() << " seconds." << endl;
configureSequencer( pThreadParameter );
cout << "Setting up the sequencer took " << timer.restart() << " seconds." << endl;
{
cout << "'FunctionInterface.imageRequestSingle' returned with an unexpected result: " << result
}
cout << "Queuing capture buffers took " << timer.restart() << " seconds." << endl;
manuallyStartAcquisitionIfNeeded( pThreadParameter->pDev, pThreadParameter->fi );
cout << "Starting the acquisition took " << timer.restart() << " seconds." << endl;
const int framesToCapture = pThreadParameter->fi.requestCount();
int64_type framesCaptured = 0;
bool isFirstValidImage = true;
vector<string> information;
const unsigned int timeout_ms = 2500;
while( !s_boTerminated && ( framesCaptured < framesToCapture ) )
{
ostringstream oss;
int requestNr = pThreadParameter->fi.imageRequestWaitFor( timeout_ms );
if( pThreadParameter->fi.isRequestNrValid( requestNr ) )
{
const Request* pRequest = pThreadParameter->fi.getRequest( requestNr );
if( pRequest->isOK() )
{
if( isFirstValidImage == true )
{
oss << "The first frame arrived after " << timer.elapsed() << " seconds using the following format: "
<< pRequest->imageWidth.read() << "x" << pRequest->imageHeight.read() << ", " << pRequest->imagePixelFormat.readS()
<< endl;
isFirstValidImage = false;
}
oss << "Image captured: "
<< "TimeStamp: " << setw( 16 ) << pRequest->infoTimeStamp_us.read() << ", "
<< "ChunkExposureTime: " << setw( 10 ) << static_cast<int>( pRequest->chunkExposureTime.read() ) << ", "
<< "ChunkSequencerSetActive: " << pRequest->chunkSequencerSetActive.read() << ", "
<< "ChunkWidth: " << pRequest->chunkWidth.read() << ", "
<< "ChunkHeight: " << pRequest->chunkHeight.read() << ", "
<< "FrameID: " << setw( 16 ) << pRequest->infoFrameID.read() << ".";
const size_t expectedSet = getExpectedSequencerSet( framesCaptured );
if( expectedSet < ( sizeof( s_SequencerData ) / sizeof( s_SequencerData[0] ) ) )
{
if( expectedSet != static_cast<size_t>( pRequest->chunkSequencerSetActive.read() ) )
{
oss << " ERROR! Expected set " << expectedSet << ", reported set " << pRequest->chunkSequencerSetActive.read();
}
const double reportedExposureTime = pRequest->chunkExposureTime.read();
if( ( s_SequencerData[expectedSet].exposureTime_us_ * 0.95 > reportedExposureTime ) ||
( s_SequencerData[expectedSet].exposureTime_us_ * 1.05 < reportedExposureTime ) )
{
oss << " ERROR! Expected exposure time " << s_SequencerData[expectedSet].exposureTime_us_ << ", reported exposure time " << static_cast<int>( reportedExposureTime );
}
const int64_type reportedWidth = pRequest->chunkWidth.read();
const int64_type expectedWidth = orgWidth / s_SequencerData[expectedSet].horizontalBinningOrDecimation_;
if( ( expectedWidth != reportedWidth ) &&
( ( ( expectedWidth / 32 ) * 32 ) != reportedWidth ) )
{
oss << " ERROR! Expected width " << expectedWidth << ", reported width " << static_cast<int>( reportedWidth );
}
const int64_type reportedHeight = pRequest->chunkHeight.read();
if( ( s_SequencerData[expectedSet].verticalBinningOrDecimation_ * reportedHeight != orgHeight ) )
{
oss << " ERROR! Expected height " << orgHeight / s_SequencerData[expectedSet].verticalBinningOrDecimation_ << ", reported height " << static_cast<int>( reportedHeight );
}
}
else
{
oss << "Internal error! Failed to locate matching sequencer set!";
}
oss << endl;
#if !defined(linux) && !defined(__linux) && !defined(__linux__)
pThreadParameter->displayWindow.GetImageDisplay().SetImage( pRequest );
pThreadParameter->displayWindow.GetImageDisplay().Update();
#endif
}
else
{
oss << "Error: " << pRequest->requestResult.readS() << endl;
}
++framesCaptured;
}
else
{
s_boTerminated = true;
}
information.push_back( oss.str() );
#if defined(linux) || defined(__linux) || defined(__linux__)
s_boTerminated = waitForInput( 0, STDOUT_FILENO ) == 0 ? false : true;
#endif
}
const double captureTime = timer.elapsed();
const vector<string>::size_type informationCount = information.size();
for( vector<string>::size_type i = 0; i < informationCount; i++ )
{
cout << information[i];
}
cout << "Capturing the sequence took " << captureTime << " seconds while the pure acquisition time of all frames would have been " << getPureAcquisitionTimeOfCapturedFrames( framesCaptured ) << " seconds." << endl;
timer.restart();
manuallyStopAcquisitionIfNeeded( pThreadParameter->pDev, pThreadParameter->fi );
cout << "Stopping the acquisition took " << timer.restart() << " seconds." << endl;
#if !defined(linux) && !defined(__linux) && !defined(__linux__)
pThreadParameter->displayWindow.GetImageDisplay().RemoveImage();
#endif
cout << endl << "If the " << framesCaptured << " frames shall be stored to disc press 'y' [ENTER] now: ";
string store;
cin >> store;
if( store == "y" )
{
cout << "Storing...." << endl;
for( unsigned int i = 0; i < framesCaptured; i++ )
{
storeRawFrame( pThreadParameter->fi.getRequest( i ) );
}
cout << endl << "All files have been stored in RAW format. They can e.g. be watched by dragging them onto the display area of wxPropView!" << endl;
}
for( unsigned int i = 0; i < framesCaptured; i++ )
{
result =
static_cast<TDMR_ERROR>( pThreadParameter->fi.imageRequestUnlock( i ) );
{
}
}
pThreadParameter->fi.imageRequestReset( 0, 0 );
return 0;
}
bool isDeviceSupportedBySample( const Device* const pDev )
{
if( !pDev->interfaceLayout.isValid() &&
!pDev->acquisitionStartStopBehaviour.isValid() )
{
return false;
}
vector<TDeviceInterfaceLayout> availableInterfaceLayouts;
pDev->interfaceLayout.getTranslationDictValues( availableInterfaceLayouts );
return find( availableInterfaceLayouts.begin(), availableInterfaceLayouts.end(),
dilGenICam ) != availableInterfaceLayouts.end();
}
int main( void )
{
DeviceManager devMgr;
Device* pDev = getDeviceFromUserInput( devMgr, isDeviceSupportedBySample );
if( !pDev )
{
cout << "Could not obtain a valid pointer to a device. Unable to continue!";
cout << "Press [ENTER] to end the application" << endl;
cin.get();
return 1;
}
try
{
cout << "Initialising the device. This might take some time..." << endl << endl;
pDev->open();
}
catch( const ImpactAcquireException& e )
{
cout << "An error occurred while opening the device " << pDev->serial.read()
<< "(error code: " << e.getErrorCodeAsString() << ")." << endl
<< "Press [ENTER] to end the application..." << endl;
cin.get();
return 1;
}
#if defined(linux) || defined(__linux) || defined(__linux__)
ThreadParameter threadParam( pDev );
liveThread( &threadParam );
#else
unsigned int dwThreadID;
string windowTitle( "mvIMPACT_acquire sequencer sample, Device " + pDev->serial.read() );
ThreadParameter threadParam( pDev, windowTitle );
HANDLE hThread = ( HANDLE )_beginthreadex( 0, 0, liveThread, ( LPVOID )( &threadParam ), 0, &dwThreadID );
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
#endif
return 0;
}
std::string getErrorCodeAsString(void) const
Returns a string representation of the error associated with the exception.
Definition: mvIMPACT_acquire.h:280
TDMR_ERROR
Errors reported by the device manager.
Definition: mvDriverBaseEnums.h:2265
@ DEV_NO_FREE_REQUEST_AVAILABLE
The user requested a new image, but no free mvIMPACT::acquire::Request object is available to process...
Definition: mvDriverBaseEnums.h:2425
@ DMR_NO_ERROR
The function call was executed successfully.
Definition: mvDriverBaseEnums.h:2270
@ bFalse
Off, false or logical low.
Definition: mvDriverBaseEnums.h:556
@ bTrue
On, true or logical high.
Definition: mvDriverBaseEnums.h:558
@ dilGenICam
A GenICamâ„¢ like interface layout shall be used.
Definition: mvDriverBaseEnums.h:1918
@ cpmRaw
No color processing will be performed.
Definition: mvDriverBaseEnums.h:1527
@ bmpUndefined
It is not known whether the buffer or image contains raw Bayer data or the buffer or image does NOT c...
Definition: TBayerMosaicParity.h:31
This namespace contains classes and functions that can be used to display images.
This namespace contains classes and functions belonging to the image acquisition module of this SDK.
Definition: mvImageBuffer.h:42