mvIMPACT Acquire SDK C++
ContinuousCapture.linux.cpp

The ContinuousCapture.linux program is a simple example for a continuous acquisition.

Note
This example will work on Linux only. Variants of this example using various window toolkits for displaying the captured image(SDL, FLTK, ...) are available on request. When a C++11 or higher capable compiler is available have a look a the ContinuousCapture.cpp example instead, which will run on any platform and uses much more sophisticated methods for capturing data!
Program location
The source file ContinuousCapture.linux.cpp can be found under:
%INSTALLDIR%\apps\ContinuousCapture\
Note
If you have installed the package without example applications, this file will not be available.
ContinuousCapture example:
  1. Opens a MATRIX VISION device.
  2. Snaps images continuously (without display).
Console Output
[0]: BF000306 (mvBlueFOX-120C, Family: mvBlueFOX, interface layout: DeviceSpecific)

Please enter the number in front of the listed device followed by [ENTER] to open it: 0
Using device number 0.
Press [ENTER] to end the application
Initialising the device. This might take some time...
Info from BF000306: FramesPerSecond: 28.655660, ErrorCount: 0, CaptureTime_s: 0.104195
Info from BF000306: FramesPerSecond: 28.655636, ErrorCount: 0, CaptureTime_s: 0.104017
Info from BF000306: FramesPerSecond: 28.655659, ErrorCount: 0, CaptureTime_s: 0.104153
Info from BF000306: FramesPerSecond: 28.655636, ErrorCount: 0, CaptureTime_s: 0.104072
Info from BF000306: FramesPerSecond: 28.655660, ErrorCount: 0, CaptureTime_s: 0.104234

This example also includes a small command line interface. The following parameters can be passed to the application from the command line:

-a<mode> to set the acquisition mode
-h<height> to set the AOI width
-p<pixelFormat> to set the pixel format
-s<serialNumber> to pre-select a certain device. If this device can be found no further user interaction is needed
-w<width> to set the AOI width
-drc<bufferCount> to specify the default request count
any other string will be interpreted as a name of a setting to load;
How it works

The continuous acquisition is similar to the single capture. The only major difference is, that this sample will continuously request images from the device. This is done without the need of a separate thread here but instead the keyboard is checked for input after every image captured. This is not the most elegant approach but the most portable and simple in this scenario.

However the general stuff (selection of a device etc.) is similar to the SingleCapture.cpp source example.

First of all the user is prompted to select the device he wants to use for this sample:

DeviceManager devMgr;
Device* pDev = getDeviceFromUserInput( devMgr );

The function getDeviceFromUserInput() is included via

#include <apps/Common/exampleHelper.h>

Then after the device has been initialised successfully image requests will constantly be sent to the drivers request queue and the application waits for the results:

// Pre-fill the capture queue with ALL buffers currently available. In case the acquisition engine is operated
// manually, buffers can only be queued when they have been queued before the acquisition engine is started as well.
// Even though there can be more than 1, for this sample we will work with the default capture queue
int requestResult = DMR_NO_ERROR;
int requestCount = 0;
if( boSingleShotMode )
{
fi.imageRequestSingle();
++requestCount;
}
else
{
while( ( requestResult = fi.imageRequestSingle() ) == DMR_NO_ERROR )
{
++requestCount;
}
}
if( requestResult != DEV_NO_FREE_REQUEST_AVAILABLE )
{
cout << "Last result: " << requestResult << "(" << ImpactAcquireException::getErrorCodeAsString( requestResult ) << "), ";
}
cout << requestCount << " buffers requested";
if( ss.requestCount.hasMaxValue() )
{
cout << ", max request count: " << ss.requestCount.getMaxValue();
}
cout << endl;
cout << "Press <<ENTER>> to end the application!!" << endl;
manuallyStartAcquisitionIfNeeded( pDev, fi );
// run thread loop
const Request* pRequest = 0;
const unsigned int timeout_ms = 8000; // USB 1.1 on an embedded system needs a large timeout for the first image
int requestNr = -1;
bool boError = false;
while( !boError )
{
// wait for results from the default capture queue
requestNr = fi.imageRequestWaitFor( timeout_ms );
if( fi.isRequestNrValid( requestNr ) )
{
pRequest = fi.getRequest( requestNr );
if( pRequest->isOK() )
{
// process data
}
else
{
cout << "*** Error: request not OK, result: " << pRequest->requestResult << endl;
boError = true;
}
// this image has been displayed thus the buffer is no longer needed...
fi.imageRequestUnlock( requestNr );
// send a new image request into the capture queue
fi.imageRequestSingle();
}
else
{
// If the error code is -2119(DEV_WAIT_FOR_REQUEST_FAILED), the documentation will provide
// additional information under TDMR_ERROR in the interface reference
cout << "imageRequestWaitFor failed (" << requestNr << ", " << ImpactAcquireException::getErrorCodeAsString( requestNr ) << ")"
<< ", timeout value too small?" << endl;
boError = true;
}
if( waitForInput( 0, STDOUT_FILENO ) != 0 )
{
cout << " == " << __FUNCTION__ << " finished by user - " << endl;
break;
}
}
@ 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:2509
@ DMR_NO_ERROR
The function call was executed successfully.
Definition: mvDriverBaseEnums.h:2356

With the request number returned by mvIMPACT::acquire::FunctionInterface::imageRequestWaitFor you can gain access the image buffer:

int requestNr = fi.imageRequestWaitFor( timeout_ms );
pRequest = fi.isRequestNrValid( requestNr ) ? fi.getRequest( requestNr ) : 0;

The image attached to the request can then be processed and/or displayed if the request does not report an error.

When the image is no longer needed you have to unlock the image buffer as otherwise the driver will refuse to use it again. This makes sure, that no image, that is still used by the user will be overwritten by the device:

pRequest->unlock();
Source code
#if !defined(linux) && !defined(__linux) && !defined(__linux__)
# error Sorry! Linux only code!
#endif // #if !defined(linux) && !defined(__linux) && !defined(__linux__)
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <apps/Common/exampleHelper.h>
#ifdef MALLOC_TRACE
# include <mcheck.h>
#endif // MALLOC_TRACE
#define PRESS_A_KEY_AND_RETURN \
cout << "Press a key..." << endl; \
getchar(); \
return 0;
using namespace std;
using namespace mvIMPACT::acquire;
static bool s_boTerminated = false;
//-----------------------------------------------------------------------------
void liveLoop( Device* pDev, const string& settingName, bool boSingleShotMode )
//-----------------------------------------------------------------------------
{
// establish access to the statistic properties
Statistics statistics( pDev );
// create an interface to the device found
FunctionInterface fi( pDev );
if( !settingName.empty() )
{
cout << "Trying to load setting " << settingName << "..." << endl;
int result = fi.loadSetting( settingName );
if( result != DMR_NO_ERROR )
{
cout << "loadSetting( \"" << settingName << "\" ); call failed: " << ImpactAcquireException::getErrorCodeAsString( result ) << endl;
}
}
// If this is color sensor, we will NOT convert the Bayer data into a RGB image because this would
// introduce additional CPU load and we might run on a tiny embedded system!
ImageProcessing ip( pDev );
if( ip.colorProcessing.isValid() )
{
ip.colorProcessing.write( cpmRaw );
}
SystemSettings ss( pDev );
int requestCount = 0;
if( boSingleShotMode )
{
fi.imageRequestSingle();
++requestCount;
}
else
{
// Send all requests to the capture queue. There can be more than 1 queue for some devices, but for this sample
// we will work with the default capture queue. If a device supports more than one capture or result
// queue, this will be stated in the manual. If nothing is mentioned about it, the device supports one
// queue only. This loop will send all requests currently available to the driver. To modify the number of requests
// use the property mvIMPACT::acquire::SystemSettings::requestCount at runtime or the property
// mvIMPACT::acquire::Device::defaultRequestCount BEFORE opening the device.
while( ( result = static_cast<TDMR_ERROR>( fi.imageRequestSingle() ) ) == DMR_NO_ERROR )
{
++requestCount;
}
}
if( ( result != DMR_NO_ERROR ) && ( result != DEV_NO_FREE_REQUEST_AVAILABLE ) )
{
cout << "'FunctionInterface.imageRequestSingle' returned with an unexpected result: " << result
}
cout << requestCount << " buffer" << ( ( requestCount > 1 ) ? "s" : "" ) << " requested";
if( ss.requestCount.hasMaxValue() )
{
cout << ", maximum request count: " << ss.requestCount.getMaxValue();
}
cout << endl;
cout << "Press <<ENTER>> to end the application!!" << endl;
manuallyStartAcquisitionIfNeeded( pDev, fi );
// run thread loop
const unsigned int timeout_ms = 10000; // USB 1.1 on an embedded system needs a large timeout for the first image
unsigned int cnt = 0;
while( !s_boTerminated )
{
// wait for results from the default capture queue
const int requestNr = fi.imageRequestWaitFor( timeout_ms );
if( fi.isRequestNrValid( requestNr ) )
{
Request* pRequest = fi.getRequest( requestNr );
if( pRequest->isOK() )
{
++cnt;
// here we can display some statistical information every 100th image
if( cnt % 10 == 0 )
{
cout << cnt << ": Info from " << pDev->serial.read()
<< ": " << statistics.framesPerSecond.name() << ": " << statistics.framesPerSecond.readS()
<< ", " << statistics.errorCount.name() << ": " << statistics.errorCount.readS()
<< ", " << statistics.captureTime_s.name() << ": " << statistics.captureTime_s.readS() << " Image count: " << cnt
<< " (dimensions: " << pRequest->imageWidth.read() << "x" << pRequest->imageHeight.read() << ", format: " << pRequest->imagePixelFormat.readS();
cout << "), line pitch: " << pRequest->imageLinePitch.read() << endl;
}
}
else
{
cout << "Error: " << pRequest->requestResult.readS() << endl;
}
// this image has been displayed thus the buffer is no longer needed...
pRequest->unlock();
if( !boSingleShotMode )
{
// send a new image request into the capture queue
fi.imageRequestSingle();
}
}
//else
//{
// Please note that slow systems or interface technologies in combination with high resolution sensors
// might need more time to transmit an image than the timeout value which has been passed to imageRequestWaitFor().
// If this is the case simply wait multiple times OR increase the timeout(not recommended as usually not necessary
// and potentially makes the capture thread less responsive) and rebuild this application.
// Once the device is configured for triggered image acquisition and the timeout elapsed before
// the device has been triggered this might happen as well.
// The return code would be -2119(DEV_WAIT_FOR_REQUEST_FAILED) in that case, the documentation will provide
// additional information under TDMR_ERROR in the interface reference.
// If waiting with an infinite timeout(-1) it will be necessary to call 'imageRequestReset' from another thread
// to force 'imageRequestWaitFor' to return when no data is coming from the device/can be captured.
// cout << "imageRequestWaitFor failed (" << requestNr << ", " << ImpactAcquireException::getErrorCodeAsString( requestNr ) << ")"
// << ", timeout value too small?" << endl;
//}
if( boSingleShotMode || ( waitForInput( 0, STDOUT_FILENO ) != 0 ) )
{
s_boTerminated = true;
}
}
if( !boSingleShotMode )
{
manuallyStopAcquisitionIfNeeded( pDev, fi );
}
// clear all queues
fi.imageRequestReset( 0, 0 );
}
//-----------------------------------------------------------------------------
int main( int argc, char* argv[] )
//-----------------------------------------------------------------------------
{
#ifdef MALLOC_TRACE
mtrace();
#endif // MALLOC_TRACE
cout << " ++ starting application...." << endl;
string settingName;
int width = -1;
int height = -1;
string pixelFormat;
string acquisitionMode;
string deviceSerial;
int defaultRequestCount = -1;
for( int i = 1; i < argc; i++ )
{
const string arg( argv[i] );
if( arg.find( "-a" ) == 0 )
{
acquisitionMode = arg.substr( 2 );
}
else if( arg.find( "-drc" ) == 0 )
{
defaultRequestCount = atoi( arg.substr( 4 ).c_str() );
}
else if( arg.find( "-h" ) == 0 )
{
height = atoi( arg.substr( 2 ).c_str() );
}
else if( arg.find( "-p" ) == 0 )
{
pixelFormat = arg.substr( 2 );
}
else if( arg.find( "-s" ) == 0 )
{
deviceSerial = arg.substr( 2 );
}
else if( arg.find( "-w" ) == 0 )
{
width = atoi( arg.substr( 2 ).c_str() );
}
else
{
// try to load this setting later on...
settingName = string( argv[1] );
}
}
if( argc <= 1 )
{
cout << "Available command line parameters:" << endl
<< endl
<< "-a<mode> to set the acquisition mode" << endl
<< "-h<height> to set the AOI width" << endl
<< "-p<pixelFormat> to set the pixel format" << endl
<< "-s<serialNumber> to pre-select a certain device. If this device can be found no further user interaction is needed" << endl
<< "-w<width> to set the AOI width" << endl
<< "-drc<bufferCount> to specify the default request count" << endl
<< "any other string will be interpreted as a name of a setting to load" << endl;
}
DeviceManager devMgr;
Device* pDev = 0;
bool bGoOn = true;
while( bGoOn )
{
if( !deviceSerial.empty() )
{
pDev = devMgr.getDeviceBySerial( deviceSerial );
if( pDev )
{
// if this device offers the 'GenICam' interface switch it on, as this will
// allow are better control over GenICam compliant devices
conditionalSetProperty( pDev->interfaceLayout, dilGenICam );
// if this device offers a user defined acquisition start/stop behaviour
// enable it as this allows finer control about the streaming behaviour
conditionalSetProperty( pDev->acquisitionStartStopBehaviour, assbUser );
}
}
if( !pDev )
{
// this will automatically set the interface layout etc. to the values from the branch above
pDev = getDeviceFromUserInput( devMgr );
}
if( pDev )
{
deviceSerial = pDev->serial.read();
cout << "Initialising device: " << pDev->serial.read() << ". This might take some time..." << endl
<< "Using interface layout '" << pDev->interfaceLayout.readS() << "'." << endl;
try
{
if( defaultRequestCount > 0 )
{
cout << "Setting default request count to " << defaultRequestCount << endl;
pDev->defaultRequestCount.write( defaultRequestCount );
}
pDev->open();
switch( pDev->interfaceLayout.read() )
{
case dilGenICam:
{
if( width > 0 )
{
ifc.width.write( width );
}
if( height > 0 )
{
ifc.height.write( height );
}
if( !pixelFormat.empty() )
{
ifc.pixelFormat.writeS( pixelFormat );
}
if( !acquisitionMode.empty() )
{
ac.acquisitionMode.writeS( acquisitionMode );
}
acquisitionMode = ac.acquisitionMode.readS();
cout << "Device set up to " << ifc.pixelFormat.readS() << " " << ifc.width.read() << "x" << ifc.height.read() << endl;
}
break;
{
CameraSettingsBase cs( pDev );
if( width > 0 )
{
cs.aoiWidth.write( width );
}
if( height > 0 )
{
cs.aoiHeight.write( height );
}
cout << "Device set up to " << cs.aoiWidth.read() << "x" << cs.aoiHeight.read() << endl;
}
break;
default:
break;
}
// start the execution of the 'live' loop.
cout << "starting live loop" << endl;
liveLoop( pDev, settingName, acquisitionMode == "SingleFrame" );
cout << "finished live loop" << endl;
pDev->close();
}
catch( const ImpactAcquireException& e )
{
// this e.g. might happen if the same device is already opened in another process...
cout << "*** " << __FUNCTION__ << " - An error occurred while opening the device " << pDev->serial.read()
<< "(error code: " << e.getErrorCode() << ", " << e.getErrorCodeAsString() << "). Press any key to end the application..." << endl;
}
}
else
{
cout << "Unable to get device!";
break;
}
if( waitForInput( 0, STDOUT_FILENO ) != 0 )
{
break;
}
}
cout << " -- ending application...." << endl;
return 0;
}
Category for the acquisition and trigger control features.
Definition: mvIMPACT_acquire_GenICam.h:2075
Category for Image Format Control features.
Definition: mvIMPACT_acquire_GenICam.h:1104
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:2351
@ assbUser
The user can control the start and stop of the data transfer from the device.
Definition: mvDriverBaseEnums.h:147
@ dilDeviceSpecific
A device specific interface shall be used(deprecated for all GenICam compliant devices).
Definition: mvDriverBaseEnums.h:1987
@ dilGenICam
A GenICamâ„¢ like interface layout shall be used.
Definition: mvDriverBaseEnums.h:2004
@ cpmRaw
No color processing will be performed.
Definition: mvDriverBaseEnums.h:1545
This namespace contains classes and functions belonging to the image acquisition module of this SDK.