First of all a device handle must be obtained. In this sample the user is prompted to select the device he wants to use. The following function will display a list of every recognized device an will ask the user to select one of them:
Afterwards the user can set the length of the sequence that shall be buffered in main memory:
Now the display window is initialized and the acquisition is started. From now on the application will constantly display a live image until the user stops the acquisition
During the thread execution the images will be stored in the queue until the user defined queue size is reached. Then each time a new images is added the queue the oldest one will be removed:
The user can stop the acquisition by pressing any key. Afterwards he can replay the captured sequence as many times as he wants by pressing "y"
. From now on the actual hardware device is no longer needed. To stop replaying the captured images the user can press any other key:
Now the sequence can be saved as an AVI file before ending the application by pressing "y"
:
#include <conio.h>
#include <deque>
#include <iostream>
#include <apps/Common/aviwrapper.h>
#include <apps/Common/exampleHelper.h>
#include <mvDisplay/Include/mvIMPACT_acquire_display.h>
#include <mvIMPACT_CPP/mvIMPACT_acquire_helper.h>
using namespace std;
using ImageQueue = deque<ImageBufferDesc>;
class ThreadParameter
{
unsigned int requestsCaptured_;
ImageQueue& imageQueue_;
ImageQueue::size_type maxQueueSize_;
int frameRate_;
public:
explicit ThreadParameter(
Device* p, ImageQueue& q, ImageQueue::size_type maxSize,
int fr )
: pDev_( p ), requestsCaptured_( 0 ), statistics_( p ), displayWindow_(
"mvIMPACT_acquire sample, Device " + p->
serial.
read() ), imageQueue_( q ), maxQueueSize_( maxSize ), frameRate_( fr ) {}
ThreadParameter( const ThreadParameter& src ) = delete;
ThreadParameter& operator=( const ThreadParameter& rhs ) = delete;
void incRequestsCaptured( void )
{
++requestsCaptured_;
}
unsigned int getRequestsCaptured( void ) const
{
return requestsCaptured_;
}
{
return statistics_;
}
int getFrameRate( void ) const
{
return frameRate_;
}
void setFrameRate( int fr )
{
frameRate_ = fr;
}
Device* getDevice(
void )
const
{
return pDev_;
}
{
return displayWindow_;
}
ImageQueue& getImageQueue( void ) const
{
return imageQueue_;
}
ImageQueue::size_type getMaxQueueSize( void ) const
{
return maxQueueSize_;
}
};
{
int upperHalfOfLines = p->
iHeight / 2;
char* pLowerLine =
static_cast<char*
>( p->
vpData ) + ( ( p->
iHeight - 1 ) * pitch );
char* pUpperLine =
static_cast<char*
>( p->
vpData );
unique_ptr<char[]> pTmpLine( new char[pitch] );
for( int y = 0; y < upperHalfOfLines; y++ )
{
memcpy( pTmpLine.get(), pUpperLine, pitch );
memcpy( pUpperLine, pLowerLine, pitch );
memcpy( pLowerLine, pTmpLine.get(), pitch );
pUpperLine += pitch;
pLowerLine -= pitch;
}
}
void setupBlueFOXFrameRate(
Device* pDev,
int& frameRate_Hz )
{
cout << "To use the HRTC to configure the mvBlueFOX to capture with a defined frequency press 'y'." << endl;
if( _getch() != 'y' )
{
return;
}
cout << "Enter the desired capture frame rate in Hz: ";
cin >> frameRate_Hz;
cout << "Trying to capture at " << frameRate_Hz << " frames per second. Please make sure the device can deliver this frame rate" << endl
<< "as otherwise the resulting AVI stream will be replayed with an incorrect speed" << endl;
int frametime_us = static_cast<int>( 1000000.0 * ( 1.0 / static_cast<double>( frameRate_Hz ) ) );
const int TRIGGER_PULSE_WIDTH_us = {100};
if( frametime_us < 2 * TRIGGER_PULSE_WIDTH_us )
{
cout << "frame rate too high (" << frameRate_Hz << "). Using 10 Hz." << endl;
frametime_us = 100000;
}
if( bfs.expose_us.read() > frametime_us / 2 )
{
ostringstream oss;
oss << "Reducing frame-time from " << bfs.expose_us.read() << " us to " << frametime_us / 2 << " us." << endl
<< "Higher values are possible but require a more sophisticated HRTC program" << endl;
bfs.expose_us.write( frametime_us / 2 );
}
bfs.triggerSource.write( ctsRTCtrl );
bfs.triggerMode.write( ctmOnRisingEdge );
if( bfIOs.RTCtrProgramCount() == 0 )
{
cout <<
"This device (" << pDev->
product.
read() <<
") doesn't support HRTC" << endl;
return;
}
if( !pRTCtrlprogram )
{
cout << "Error! No valid program. Short of memory?" << endl;
return;
}
int progStep = {0};
pRTCtrlStep->
clocks_us.
write( frametime_us - TRIGGER_PULSE_WIDTH_us );
pRTCtrlStep = pRTCtrlprogram->
programStep( progStep++ );
pRTCtrlStep = pRTCtrlprogram->
programStep( progStep++ );
pRTCtrlStep = pRTCtrlprogram->
programStep( progStep++ );
pRTCtrlStep = pRTCtrlprogram->
programStep( progStep++ );
}
void myThreadCallback( shared_ptr<Request> pRequest, ThreadParameter& threadParameter )
{
threadParameter.incRequestsCaptured();
if( threadParameter.getRequestsCaptured() % 100 == 0 )
{
const Statistics& s = threadParameter.getStatistics();
cout << "Info from " << threadParameter.getDevice()->serial.read()
}
if( pRequest->isOK() )
{
threadParameter.getDisplayWindow().GetImageDisplay().SetImage( pRequest );
threadParameter.getDisplayWindow().GetImageDisplay().Update();
threadParameter.getImageQueue().push_back( pRequest->getImageBufferDesc().clone() );
if( threadParameter.getImageQueue().size() > threadParameter.getMaxQueueSize() )
{
threadParameter.getImageQueue().pop_front();
}
}
else
{
cout << "Error: " << pRequest->requestResult.readS() << endl;
}
}
int main( void )
{
Device* pDev = getDeviceFromUserInput( devMgr );
if( pDev == nullptr )
{
cout << "Could not obtain a valid pointer to a device. Unable to continue! Press any key to end the program." << endl;
return _getch();
}
cout << "Initialising the device. This might take some time..." << endl
<< endl
<< "PLEASE NOTE THAT THIS EXAMPLE APPLICATION MAKES USE OF A VERY OLD, OUTDATED WINDOWS ONLY API WHICH IS NOT RECOMMENDED FOR NEW PROJECTS!" << endl
<< "There are various other, more portable ways to encode/store a video stream there day. Please consider using the FFmpeg library (see" << endl
<< "'ContinuousCaptureFFmpeg' in the C++ manual) or something similar instead!" << endl;
try
{
}
{
cout <<
"An error occurred while opening the device " << pDev->
serial.
read()
return 1;
}
int captureFrameRate = {0};
{
setupBlueFOXFrameRate( pDev, captureFrameRate );
}
ImageQueue::size_type maxQueueSize = {0};
cout << "Enter the length of the sequence to buffer (please note that this might be limited by your systems memory): ";
cin >> maxQueueSize;
vector<pair<string, TImageDestinationPixelFormat> > vAvailableDestinationFormats;
id.pixelFormat.getTranslationDict( vAvailableDestinationFormats );
cout << "Available destination formats: " << endl;
for( const auto& format : vAvailableDestinationFormats )
{
cout << "[" << format.first << "]: " << format.second << endl;
}
cout << endl << endl;
cout << "If AVI files shall be written please note, that most AVI compression handlers" << endl
<< "accept RGB888Packed formats only. Apart from that planar formats are not supported" << endl
<< "by this sample in order to keep things simple." << endl << endl
<< "Destination format (as integer): ";
int destinationPixelFormat = {0};
cin >> destinationPixelFormat;
try
{
}
{
cout <<
"Failed to set destination pixel format(" << e.
getErrorCodeAsString() <<
"), using default" << endl;
id.pixelFormat.write( idpfRGB888Packed );
}
cout << "Using " << id.pixelFormat.readS() << "." << endl;
cout << "Press [ENTER] to stop the acquisition thread" << endl;
ImageQueue imageQueue;
ThreadParameter threadParam( pDev, imageQueue, maxQueueSize, captureFrameRate );
requestProvider.acquisitionStart( myThreadCallback, std::ref( threadParam ) );
if( _getch() == EOF )
{
cout << "Calling '_getch()' did return EOF...\n";
}
const double fr = threadParam.getStatistics().framesPerSecond.read();
threadParam.setFrameRate( static_cast<int>( fr ) );
if( ( fr - static_cast<double>( static_cast<int>( fr ) ) ) >= 0.5 )
{
threadParam.setFrameRate( threadParam.getFrameRate() + 1 );
}
requestProvider.acquisitionStop();
if( imageQueue.empty() )
{
cout << "No images have been captured thus no playback or storage can be performed"
<< "Press any key to end the application" << endl;
if( _getch() == EOF )
{
cout << "Calling '_getch()' did return EOF...\n";
}
return 1;
}
const ImageQueue::size_type qSize = imageQueue.size();
bool boRun = true;
while( boRun )
{
cout << "Press 'y' to replay the captured sequence of " << qSize << " images from memory or any other key to end the replay loop." << endl;
char c = static_cast<char>( _getch() );
if( c != 'y' )
{
boRun = false;
continue;
}
const DWORD frameDelay = ( threadParam.getFrameRate() > 0 ) ? 1000 / threadParam.getFrameRate() : 40;
ImageDisplay& display = threadParam.getDisplayWindow().GetImageDisplay();
cout << "Replaying the last " << qSize << " captured images with " << 1000 / frameDelay << " Hz..." << endl;
for( const auto& imageBufferDescriptor : imageQueue )
{
display.
SetImage( imageBufferDescriptor.getBuffer() );
this_thread::sleep_for( chrono::milliseconds( frameDelay ) );
}
}
cout << endl;
cout << "If you want to save the captured sequence press 'y' or any other key to end the application: ";
if( _getch() != 'y' )
{
return 0;
}
cout << endl << "Please enter the file name for the resulting AVI stream(use proper file extensions like *.avi as otherwise creating the stream may fail): ";
string fileName;
cin >> fileName;
unique_ptr<AVIWrapper> pAVIWrapper;
boRun = true;
while( boRun )
{
try
{
pAVIWrapper = unique_ptr<AVIWrapper>( new AVIWrapper() );
pAVIWrapper->OpenAVIFile( fileName.c_str(), OF_WRITE | OF_CREATE | OF_SHARE_DENY_WRITE );
cout << "Please select a compression handler from the dialog box (which might be hidden behind this window)" << endl << endl;
const ImageBuffer* pIB = imageQueue.front().getBuffer();
pAVIWrapper->CreateAVIStreamFromDIBs( pIB->
iWidth, pIB->
iHeight, pIB->
iBytesPerPixel * 8, threadParam.getFrameRate(), 8000,
"myStream" );
boRun = false;
}
catch( const AVIException& e )
{
cout << "Error while creating AVI stream(" << string( e.what() ) << ")." << endl
<< "Please note, that not every codec will accept every pixel format, thus this error might" << endl
<< "appear without changing the destination pixel format within the driver. However the" << endl
<< "format selected in this sample (RGB888Packed) works for the greatest number of codecs" << endl
<< "Unable to continue. Press 'q' to end the application or any other key to select a different" << endl
<< "compression handler." << endl;
if( _getch() == 'q' )
{
return 1;
}
}
}
for( ImageQueue::size_type x = 0; x < qSize; x++ )
{
cout << "Storing image " << x << " in stream " << fileName << ".\r";
inplaceHorizontalMirror( pIB );
pAVIWrapper->SaveDataToAVIStream(
reinterpret_cast<unsigned char*
>( pIB->
vpData ), pIB->
iSize );
}
return 0;
}
mvBlueFOX related camera settings(Device specific interface layout only).
Definition mvIMPACT_acquire.h:20035
std::string name(void) const
Returns the name of the component referenced by this object.
Definition mvIMPACT_acquire.h:1206
Grants access to devices that can be operated by this software interface.
Definition mvIMPACT_acquire.h:7171
This class and its functions represent an actual device detected by this interface in the current sys...
Definition mvIMPACT_acquire.h:6118
PropertyS product
A string property (read-only) containing the product name of this device.
Definition mvIMPACT_acquire.h:6537
PropertyS serial
A string property (read-only) containing the serial number of this device.
Definition mvIMPACT_acquire.h:6551
void open(void)
Opens a device.
Definition mvIMPACT_acquire.h:6420
PropertyS family
A string property (read-only) containing the family name of this device.
Definition mvIMPACT_acquire.h:6526
const EnumPropertyI & write(ZYX value, int index=0) const
Writes one value to the property.
Definition mvIMPACT_acquire.h:4426
A class to handle the digital inputs and outputs for mvBlueFOX USB cameras(Device specific interface ...
Definition mvIMPACT_acquire.h:16787
Properties to define the format of resulting images.
Definition mvIMPACT_acquire.h:12376
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
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
A class to represent one step of a real time control(RTCtr) program (Device specific interface layout...
Definition mvIMPACT_acquire.h:15681
PropertyI address
An integer property, which defines the absolute jump address within this mvIMPACT::acquire::RTCtrProg...
Definition mvIMPACT_acquire.h:15706
PropertyIRTProgOpCodes opCode
An enumerated integer property defining the general purpose of this mvIMPACT::acquire::RTCtrProgramSt...
Definition mvIMPACT_acquire.h:15743
PropertyI clocks_us
An integer property, which defines the waiting time mvIMPACT::acquire::RTCtrProgram.
Definition mvIMPACT_acquire.h:15716
A class to represent real time control programs(Device specific interface layout only).
Definition mvIMPACT_acquire.h:16026
PropertyIRTCtrlModes mode
An enumerated integer property defining the current state this program is into.
Definition mvIMPACT_acquire.h:16187
RTCtrProgramStep * programStep(unsigned int nr) const
Returns a pointer to a program instruction of the program.
Definition mvIMPACT_acquire.h:16169
void setProgramSize(int newSize)
A function to define the number of instructions this program should consist of.
Definition mvIMPACT_acquire.h:16145
Contains basic statistical information.
Definition mvIMPACT_acquire.h:14509
PropertyF framesPerSecond
A float property (read-only) containing the current number of frames captured per second.
Definition mvIMPACT_acquire.h:14586
PropertyF captureTime_s
A float property (read-only) containing the overall time an image request spent in the device drivers...
Definition mvIMPACT_acquire.h:14560
PropertyI errorCount
An integer property (read-only) containing the overall count of image requests which returned with an...
Definition mvIMPACT_acquire.h:14568
A class that can be used to display images in a window.
Definition mvIMPACT_acquire_display.h:606
A class that can be used for displaying images within existing windows or GUI elements that can provi...
Definition mvIMPACT_acquire_display.h:176
void SetImage(const void *pData, int width, int height, int bitsPerPixel, int pitch)
Sets the next image to display.
Definition mvIMPACT_acquire_display.h:316
void Update(void) const
Immediately redraws the current image.
Definition mvIMPACT_acquire_display.h:405
A helper class that can be used to implement a simple continuous acquisition from a device.
Definition mvIMPACT_acquire_helper.h:432
int iHeight
The height of the image in pixel or lines.
Definition mvImageBuffer.h:98
int iWidth
The width of the image in pixel.
Definition mvImageBuffer.h:100
int iLinePitch
The offset (in bytes) to the next line of this channel.
Definition mvImageBuffer.h:70
void * vpData
The starting address of the image.
Definition mvImageBuffer.h:157
ChannelData * pChannels
A pointer to an array of channel specific image data.
Definition mvImageBuffer.h:166
int iBytesPerPixel
The number of bytes per pixel.
Definition mvImageBuffer.h:96
int iSize
The size (in bytes) of the whole image.
Definition mvImageBuffer.h:112
Fully describes a captured image.
Definition mvImageBuffer.h:94
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 mvCommonDataTypes.h:34