Impact 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 Balluff device.
  2. Snaps images continuously (without display).
Console Output
[0]: BF000306 (mvBlueFOX-202C, 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;
}
}

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
//
// @description: Example applications for Impact Acquire
// @copyright: Copyright (C) 2005 - 2023 Balluff GmbH
// @authors: APIs and drivers development team at Balluff GmbH
// @initial date: 2005-10-11
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,i
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#if !defined(linux) && !defined(__linux) && !defined(__linux__) && !defined(__APPLE__)
# error Sorry! Code for Unix flavoured operating systems only!
#endif // #if !defined(linux) && !defined(__linux) && !defined(__linux__) && !defined(__APPLE__)
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <apps/Common/exampleHelper.h>
#include <mvIMPACT_CPP/mvIMPACT_acquire.h>
#include <mvIMPACT_CPP/mvIMPACT_acquire_GenICam.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 );
{
ip.colorProcessing.write( cpmRaw );
}
SystemSettings ss( pDev );
TDMR_ERROR result = DMR_NO_ERROR;
int requestCount = 0;
if( boSingleShotMode )
{
++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 (note that some devices will
// only allow to modify this parameter while NOT streaming data!) 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";
{
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
}
}
//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;
}
A base class for camera related settings(Device specific interface layout only).
Definition mvIMPACT_acquire.h:18786
std::string name(void) const
Returns the name of the component referenced by this object.
Definition mvIMPACT_acquire.h:1206
bool isValid(void) const
Checks if the internal component referenced by this object is still valid.
Definition mvIMPACT_acquire.h:1721
Grants access to devices that can be operated by this software interface.
Definition mvIMPACT_acquire.h:7159
Device * getDeviceBySerial(const std::string &serial="", unsigned int devNr=0, char wildcard=' *') const
Tries to locate a device via the serial number.
Definition mvIMPACT_acquire.h:7512
This class and its functions represent an actual device detected by this interface in the current sys...
Definition mvIMPACT_acquire.h:6118
PropertyS serial
A string property (read-only) containing the serial number of this device.
Definition mvIMPACT_acquire.h:6550
void close(void)
Closes an opened device.
Definition mvIMPACT_acquire.h:6271
void open(void)
Opens a device.
Definition mvIMPACT_acquire.h:6419
PropertyI defaultRequestCount
An integer property that defines the number of mvIMPACT::acquire::Request objects to be created when ...
Definition mvIMPACT_acquire.h:6671
PropertyIDeviceInterfaceLayout interfaceLayout
An enumerated integer property which can be used to define which interface layout shall be used when ...
Definition mvIMPACT_acquire.h:6643
PropertyIAcquisitionStartStopBehaviour acquisitionStartStopBehaviour
An enumerated integer property defining the start/stop behaviour during acquisition of this driver in...
Definition mvIMPACT_acquire.h:6788
ZYX read(int index=0) const
Reads a value from a property.
Definition mvIMPACT_acquire.h:4300
ZYX getMaxValue(void) const
Reads the maximum value from a property.
Definition mvIMPACT_acquire.h:4325
const EnumPropertyI & write(ZYX value, int index=0) const
Writes one value to the property.
Definition mvIMPACT_acquire.h:4426
The function interface to devices supported by this interface.
Definition mvIMPACT_acquire.h:10746
int imageRequestWaitFor(int timeout_ms, int queueNr=0) const
Waits for a request object to become ready.
Definition mvIMPACT_acquire.h:11604
int loadSetting(const std::string &name, TStorageFlag storageFlags=sfNative, TScope scope=sGlobal) const
Loads a previously stored setting.
Definition mvIMPACT_acquire.h:11824
int imageRequestSingle(ImageRequestControl *pImageRequestControl=0, int *pRequestUsed=0) const
Sends an image request to the mvIMPACT::acquire::Device driver.
Definition mvIMPACT_acquire.h:11491
bool isRequestNrValid(int nr) const
Check if nr specifies a valid mvIMPACT::acquire::Request.
Definition mvIMPACT_acquire.h:11751
int imageRequestReset(int requestCtrlNr, int mode) const
Deletes all requests currently queued for the specified mvIMPACT::acquire::ImageRequestControl.
Definition mvIMPACT_acquire.h:11438
Request * getRequest(int nr) const
Returns a pointer to the desired mvIMPACT::acquire::Request.
Definition mvIMPACT_acquire.h:11177
Category for the acquisition and trigger control features.
Definition mvIMPACT_acquire_GenICam.h:2108
Category for Image Format Control features.
Definition mvIMPACT_acquire_GenICam.h:1132
Base class for image processing related properties.
Definition mvIMPACT_acquire.h:13193
PropertyIColorProcessingMode colorProcessing
An enumerated integer property defining what kind of color processing shall be applied to the raw ima...
Definition mvIMPACT_acquire.h:13606
A base class for exceptions generated by Impact Acquire.
Definition mvIMPACT_acquire.h:256
std::string getErrorCodeAsString(void) const
Returns a string representation of the error associated with the exception.
Definition mvIMPACT_acquire.h:288
int getErrorCode(void) const
Returns a unique numerical representation for this error.
Definition mvIMPACT_acquire.h:275
std::string read(int index=0) const
Reads a value from a property.
Definition mvIMPACT_acquire.h:5323
std::string readS(int index=0, const std::string &format="") const
Reads data from this property as a string.
Definition mvIMPACT_acquire.h:3340
bool hasMaxValue(void) const
Checks if a maximum value is defined for this property.
Definition mvIMPACT_acquire.h:3305
Contains information about a captured buffer.
Definition mvIMPACT_acquire.h:8628
PropertyI imageHeight
An integer property (read-only) containing the height of the image in pixels.
Definition mvIMPACT_acquire.h:10319
bool isOK(void) const
Convenience function to check if a request has been processed successfully.
Definition mvIMPACT_acquire.h:9462
PropertyIRequestResult requestResult
An enumerated integer property (read-only) defining the result of this request.
Definition mvIMPACT_acquire.h:9768
PropertyI imageWidth
An integer property (read-only) containing the width of the image in pixels.
Definition mvIMPACT_acquire.h:10308
PropertyIImageBufferPixelFormat imagePixelFormat
An enumerated integer property (read-only) containing the pixel format of this image.
Definition mvIMPACT_acquire.h:10120
int unlock(void)
Unlocks the request for the driver again.
Definition mvIMPACT_acquire.h:9602
PropertyI imageLinePitch
An integer property (read-only) containing the offset (in bytes) to the next line of each channel bel...
Definition mvIMPACT_acquire.h:10250
Contains basic statistical information.
Definition mvIMPACT_acquire.h:14497
PropertyF framesPerSecond
A float property (read-only) containing the current number of frames captured per second.
Definition mvIMPACT_acquire.h:14564
PropertyF captureTime_s
A float property (read-only) containing the overall time an image request spent in the device drivers...
Definition mvIMPACT_acquire.h:14548
PropertyI errorCount
An integer property (read-only) containing the overall count of image requests which returned with an...
Definition mvIMPACT_acquire.h:14556
A base class for accessing settings that control the overall behaviour of a device driver.
Definition mvIMPACT_acquire.h:14706
PropertyI requestCount
An integer property defining the number of requests allocated by the driver.
Definition mvIMPACT_acquire.h:14759
TDMR_ERROR
Errors reported by the device manager.
Definition mvDriverBaseEnums.h:2601
@ dilDeviceSpecific
A device specific interface shall be used(deprecated for all GenICamâ„¢ compliant devices).
Definition mvDriverBaseEnums.h:2133
@ dilGenICam
A GenICamâ„¢ like interface layout shall be used.
Definition mvDriverBaseEnums.h:2150
This namespace contains classes and functions belonging to the image acquisition module of this SDK.
Definition mvCommonDataTypes.h:34