PDA

View Full Version : MemBuffers and limits



nikkadim
September 5, 2012, 18:59:02
I would like capture images to memory.
How many MemBuffers (VC++) I can prepare for capturing? Do you have any limits?

Stefan Geissler
September 6, 2012, 10:41:46
Hello,

the only limitation is the memory, that your operating system can allocate. So you may calculate the image sizes and multiply it by the number of frames you want to capture. In a 64 bit system you can allocate much more memory than in a 32 bit system.

nikkadim
September 7, 2012, 16:51:49
If I'm going to perform simultaneous capturing for several cameras with external sync, is it necessary to run each capture in separate thread or not?

Thank you.

nikkadim
September 7, 2012, 17:51:35
Don't know why, but when I run capturing for one camera in separate thread fro 72BUC02 I got not more 5 FPS, but camera->getFPS(); shows me that I have 26.

nikkadim
September 7, 2012, 21:16:26
I have find method snapImagesAsync() (http://www.imagingcontrol.com/en_US/support/documentation/class/meth_descFrameHandlerSink_snapImagesAsync.htm), but can't find any code example with it. Could you please explain how it work, and how I can get the signal when the scheduled jobs are done?
Thank you.

Stefan Geissler
September 10, 2012, 09:39:16
If I'm going to perform simultaneous capturing for several cameras with external sync, is it necessary to run each capture in separate thread or not?
No. IC Imaging Control creates own threads for each camera, resp. Grabber object.


Don't know why, but when I run capturing for one camera in separate thread fro 72BUC02 I got not more 5 FPS, but camera->getFPS(); shows me that I have 26.
Depends on the video format, you have set. Which video format do you use?


I have find method snapImagesAsync(), but can't find any code example with it. Could you please explain how it work, and how I can get the signal when the scheduled jobs are done?
This functions works as snapImages, but it returns immediately after it was called. In your case, I wont use snapImages at all. If a camera runs triggered, you should use the GrabberListener inherited class and implement the frameReady method, which is called automatically for each incoming image. The snapMode of the sink must be set to false, so every incoming frame will be saved automatically, without calling snapImages().

So you create for each camera you want to use a Grabber object, a Sink and a Listener Object.

nikkadim
September 10, 2012, 14:37:48
This functions works as snapImages, but it returns immediately after it was called. In your case, I wont use snapImages at all. If a camera runs triggered, you should use the GrabberListener inherited class and implement the frameReady method, which is called automatically for each incoming image. The snapMode of the sink must be set to false, so every incoming frame will be saved automatically, without calling snapImages().

So you create for each camera you want to use a Grabber object, a Sink and a Listener Object.

Thank you!
I have got the Callback example from IC Imaging Control 3.2\samples\vc10\callback\, add second camera and change
sink to false (as you said). But, with pSink->setSnapMode( false ); I can't capture images at all.


#define NUM_BUFFERS 30
int main(int argc, char* argv[])
{

DShowLib::InitLibrary();

atexit( ExitLibrary );

Grabber grabber;
Grabber grabber2;

// Create the GrabberListener object.
// CListener is derived from GrabberListener.
CListener *pListener = new CListener();
CListener *pListener2 = new CListener();

/*if( !setupDeviceFromFile( grabber ) )
{
return -1;
}*/
grabber.openDev("DMx 72BUC02"); //mono 5Mpx
grabber2.openDev("DMx 22BUC03"); //mono

// Assign the number of buffers to the cListener object.
pListener->setBufferSize( NUM_BUFFERS );
pListener2->setBufferSize( NUM_BUFFERS );

// Enable the overlay bitmap to display the frame counter in the live video.
//grabber.getOverlay()->setEnable( true );

// Register the pListener object for the frame ready and
// the overlay callback event.
//grabber.addListener( pListener, GrabberListener::eFRAMEREADY| GrabberListener::eOVERLAYCALLBACK );
grabber.addListener( pListener, GrabberListener::eFRAMEREADY);
grabber2.addListener( pListener2, GrabberListener::eFRAMEREADY);


// Create a FrameTypeInfoArray data structure describing the allowed color formats.
//FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createRGBArray();
FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createStandardTypesArray();
FrameTypeInfoArray acceptedTypes2 = FrameTypeInfoArray::createStandardTypesArray();

// Create the frame handler sink
smart_ptr<FrameHandlerSink> pSink = FrameHandlerSink::create( eY800, NUM_BUFFERS );
smart_ptr<FrameHandlerSink> pSink2 = FrameHandlerSink::create( eY800, NUM_BUFFERS );

// enable snap mode (formerly tFrameGrabberMode::eSNAP).
pSink->setSnapMode( 0 );
pSink2->setSnapMode( 0 );

// Apply the sink to the grabber.
grabber.setSinkType( pSink );
grabber2.setSinkType( pSink2 );

grabber.startLive(false); // Start the grabber.
grabber2.startLive(false); // Start the grabber.

//pSink->snapImages( NUM_BUFFERS ); // Grab NUM_BUFFERS images.
//pSink2->snapImages( NUM_BUFFERS ); // Grab NUM_BUFFERS images.

grabber.stopLive(); // Stop the grabber.
grabber2.stopLive(); // Stop the grabber.

// The CListener object must be unregistered for all events
// before it may be destroyed.
grabber.removeListener( pListener );
grabber2.removeListener( pListener2 );

// Now, it must be checked whether the CListener object has been unregistered
// for all events.
while( grabber.isListenerRegistered( pListener ) )
{
Sleep( 0 ); // Wait and give pending callbacks a chance to complete.
}
while( grabber2.isListenerRegistered( pListener2 ) )
{
Sleep( 0 ); // Wait and give pending callbacks a chance to complete.
}

// Now, the application can be sure that no callback methods of pListener
// will be called anymore. It is now safe to delete pListener.
delete pListener;
delete pListener2;

return 0;
}
[/QUOTE]

also I have changed the saveImage function to separate images from different cameras
[QUOTE]
void CListener::saveImage( smart_ptr<MemBuffer> pBuffer, DWORD currFrame, Grabber& caller)
{
char filename[MAX_PATH];
long long serial;
if( currFrame < m_BufferWritten.size() )
{

sprintf( filename, "image_%s_%02i.bmp", caller.getDev().getName().c_str(), currFrame );

saveToFileBMP( *pBuffer, filename );

m_BufferWritten.at( currFrame ) = true;
}
}

nikkadim
September 10, 2012, 21:31:47
I have found some workaround, but I did not think that it is right. Correct me please.

I just put this waiting loop beetwing .startLive() and .stoplive()


while (pListener->done < NUM_BUFFERS || pListener2->done < NUM_BUFFERS) {
Sleep(0);
}

where done is updated in frameReady function:


void CListener::frameReady( Grabber& caller, smart_ptr<MemBuffer> pBuffer, DWORD currFrame)
{
std::cout << "Buffer " <<currFrame<<" " << caller.getDev().getName().c_str() <<" "<< " processed in CListener::frameReady()." << std::endl;

saveImage( pBuffer, currFrame, caller); // Do the buffer processing.
done = currFrame;

}

Stefan Geissler
September 11, 2012, 09:28:10
Hi

currFrame will be incremented for each incoming frame and therefore, it will be greater than NUM_BUFFERS after a short time. I suggest to set "done" to 1 in the frameReady and set it back to 0 again in your while loop, after you processed the images.

(Do not wonder why "php code" below, but syntax highlight works in "php" tags only :-) )


while (pListener->done == 0 && pListener2->done == 0)
{
Sleep(0); //Better is a timeout, so the application does not block, if a camera disconnects.
}
// imageprocessing
// imageprocessing goes here with the buffers saved in CListener::m_pBuffer (See below)

pListener->done = 0;
pListener2->done = 0;

pListener.m_pBuffer->Unlock();
pListener.m_pBuffer2 ->Unlock();

// Get the next images





class CListener::GrabberListener
{
public:
smart_ptr<MemBuffer> m_pBuffer;

//(...)
}
void CListener::frameReady( Grabber& caller, smart_ptr<MemBuffer> pBuffer, DWORD currFrame)
{
if( done == 0 )
{
// Save the image buffer, we
m_pBuffer = pBuffer;
// Lock the buffer, so it is not overwritten
m_pBuffer->Lock();
done = 1;
}
}


Using this, you can receive pairs of images. I am not really sure whether this is, what you want. But I think, it gives you an idea.

nikkadim
September 11, 2012, 15:23:33
Thank you Stefan!

But with this while loop I got nothing, because it does not wait until all images are grabbed.
With loop below done will never be more than NUM_BUFFERS because I stop the process


while (pListener->done < NUM_BUFFERS || pListener2->done < NUM_BUFFERS) {
Sleep(0);
}

but in this case I always can't capture the 0-frames via callback function, don't know why


...
Buffer 27 DMx 21BUC03 processed in CListener::frameReady().
Buffer 27 DMx 22BUC03 processed in CListener::frameReady().
Buffer 27 DMx 22BUC03 1 processed in CListener::frameReady().
Buffer 28 DMx 21BUC03 processed in CListener::frameReady().
Buffer 28 DMx 22BUC03 processed in CListener::frameReady().
Buffer 28 DMx 22BUC03 1 processed in CListener::frameReady().
Buffer 29 DMx 21BUC03 processed in CListener::frameReady().
Buffer 29 DMx 22BUC03 processed in CListener::frameReady().
Buffer 29 DMx 22BUC03 1 processed in CListener::frameReady().
Buffer 30 DMx 21BUC03 processed in CListener::frameReady().
Buffer 30 DMx 22BUC03 processed in CListener::frameReady().
Buffer 0 processed in main().
Buffer2 0 processed in main().

Stefan Geissler
September 12, 2012, 09:19:48
Hi

You should remove the saveimage call fromt the framerady eventhandler.

However, different approach:
If your cameras run triggered and you need a specific amount of images, you may try following:



// enable snap mode (formerly tFrameGrabberMode::eSNAP).
pSink->setSnapMode( 1 );
pSink2->setSnapMode( 1 );

pListener->done = 0;
pListener2->done = 0;

// The following lines unlock the image buffers, so you can fill the image buffers collection with new images
// The buffers will be locked in the frameReady() eventhandler.
// The code has not been tested, so there may is a syntax error. I guess, you can figure this out.
for( int i = 0; i<NUM_BUFFERS;i++)
{
pSink->getMemBufferCollection().at(i)->Unlock()
pSink2->getMemBufferCollection().at(i)->Unlock()
}

grabber.startLive(false); // Start the grabber.
grabber2.startLive(false);

pSink->snapImagesAsync( NUM_BUFFERS );
pSink2->snapImagesAsync( NUM_BUFFERS );

//Start your trigger machine now

while (pListener->done < NUM_BUFFERS || pListener2->done < NUM_BUFFERS)
{
Sleep(10);
}

//now you can access the imagebuffers collection in the pSink and pSink2

In the listener you simply count the incoming images.


void CListener::frameReady( Grabber& caller, smart_ptr<MemBuffer> pBuffer, DWORD currFrame)
{
// Lock the buffer, so it is not overwritten
pBuffer->Lock();
// count the image. "done" has be set to 0 by the code above, before we start
// a new image sequence.
done++;
}

nikkadim
September 12, 2012, 15:45:44
Good idea, thank you.

I need to correct you code with this:


for( int i = 0; i<NUM_BUFFERS;i++)
{
pSink->getMemBufferCollection()->getBuffer(i)->unlock();
pSink2->getMemBufferCollection()->getBuffer(i)->unlock();
pSink3->getMemBufferCollection()->getBuffer(i)->unlock();
}



But, my question is where I should initialize the MemBufferCollection?

I have tried this:


int main(int argc, char* argv[])
{

DShowLib::InitLibrary();

atexit( ExitLibrary );

Grabber grabber;
Grabber grabber2;
Grabber grabber3;

// Create the GrabberListener object.
// CListener is derived from GrabberListener.
CListener *pListener = new CListener();
CListener *pListener2 = new CListener();
CListener *pListener3 = new CListener();

/*if( !setupDeviceFromFile( grabber ) )
{
return -1;
}*/
grabber.openDev("DMx 21BUC03"); //mono
grabber.setFPS(30);
grabber.setExternalTrigger(0);
grabber2.openDev("DMx 22BUC03"); //mono
grabber2.setFPS(30);
grabber2.setExternalTrigger(0);
grabber3.openDev("DMx 22BUC03 1"); //mono
grabber3.setFPS(30);
grabber3.setExternalTrigger(0);


// Assign the number of buffers to the cListener object.
pListener->setBufferSize( NUM_BUFFERS );
pListener2->setBufferSize( NUM_BUFFERS );
pListener3->setBufferSize( NUM_BUFFERS );

// Enable the overlay bitmap to display the frame counter in the live video.
//grabber.getOverlay()->setEnable( true );

// Register the pListener object for the frame ready and
// the overlay callback event.
//grabber.addListener( pListener, GrabberListener::eFRAMEREADY| GrabberListener::eOVERLAYCALLBACK );
grabber.addListener( pListener, GrabberListener::eFRAMEREADY);
grabber2.addListener( pListener2, GrabberListener::eFRAMEREADY);
grabber3.addListener( pListener2, GrabberListener::eFRAMEREADY);

// Create a FrameTypeInfoArray data structure describing the allowed color formats.
//FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createRGBArray();
FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createStandardTypesArray();
FrameTypeInfoArray acceptedTypes2 = FrameTypeInfoArray::createStandardTypesArray();
FrameTypeInfoArray acceptedTypes3 = FrameTypeInfoArray::createStandardTypesArray();

// Create the frame handler sink
smart_ptr<FrameHandlerSink> pSink = FrameHandlerSink::create( eY800, NUM_BUFFERS );
smart_ptr<FrameHandlerSink> pSink2 = FrameHandlerSink::create( eY800, NUM_BUFFERS );
smart_ptr<FrameHandlerSink> pSink3 = FrameHandlerSink::create( eY800, NUM_BUFFERS );

// enable snap mode (formerly tFrameGrabberMode::eSNAP).
pSink->setSnapMode( 1 );
pSink2->setSnapMode( 1 );
pSink3->setSnapMode( 1 );

pListener->done = 1;
pListener2->done = 1;
pListener3->done = 1;

// Apply the sink to the grabber.
grabber.setSinkType( pSink );
grabber2.setSinkType( pSink2 );
grabber3.setSinkType( pSink3 );

FrameTypeInfo info;
FrameTypeInfo info2;
FrameTypeInfo info3;
pSink->getOutputFrameType( info );
pSink2->getOutputFrameType( info2 );
pSink3->getOutputFrameType( info3 );

BYTE* pBuf[NUM_BUFFERS];
BYTE* pBuf2[NUM_BUFFERS];
BYTE* pBuf3[NUM_BUFFERS];
for( int i = 0; i < NUM_BUFFERS; ++i )
{
pBuf[i] = new BYTE[info.buffersize];
pBuf2[i] = new BYTE[info2.buffersize];
pBuf3[i] = new BYTE[info3.buffersize];
}

tMemBufferCollectionPtr pCollection = MemBufferCollection::create( info, NUM_BUFFERS, pBuf );
tMemBufferCollectionPtr pCollection2 = MemBufferCollection::create( info2, NUM_BUFFERS, pBuf2 );
tMemBufferCollectionPtr pCollection3 = MemBufferCollection::create( info3, NUM_BUFFERS, pBuf3 );

pSink->setMemBufferCollection( pCollection );
pSink2->setMemBufferCollection( pCollection2 );
pSink3->setMemBufferCollection( pCollection3 );

//can't uncomment it, because got exception
/*for( int i = 0; i<NUM_BUFFERS;i++)
{
pSink->getMemBufferCollection()->getBuffer(i)->unlock();
pSink2->getMemBufferCollection()->getBuffer(i)->unlock();
pSink3->getMemBufferCollection()->getBuffer(i)->unlock();
}*/


grabber.startLive(false); // Start the grabber.
grabber2.startLive(false); // Start the grabber.
grabber3.startLive(false); // Start the grabber.


//pSink->snapImages( NUM_BUFFERS ); // Grab NUM_BUFFERS images.
//pSink2->snapImages( NUM_BUFFERS ); // Grab NUM_BUFFERS images.

pSink->snapImagesAsync( NUM_BUFFERS );
pSink2->snapImagesAsync( NUM_BUFFERS );
pSink3->snapImagesAsync( NUM_BUFFERS );

while (pListener->done < NUM_BUFFERS || pListener2->done < NUM_BUFFERS || pListener3->done < NUM_BUFFERS/){
Sleep(10);
}

printf("Size=%d\n",pSink->getMemBufferCollection()->getBufferDataSize());
//pListener->m_pBuffer->unlock();
//pListener2->m_pBuffer->unlock();

grabber.stopLive(); // Stop the grabber.
grabber2.stopLive(); // Stop the grabber.
grabber3.stopLive(); // Stop the grabber.

pCollection->save( "file*.bmp" );


// The CListener object must be unregistered for all events
// before it may be destroyed.
grabber.removeListener( pListener );
grabber2.removeListener( pListener2 );
grabber3.removeListener( pListener3 );

// Now, it must be checked whether the CListener object has been unregistered
// for all events.
while( grabber.isListenerRegistered( pListener ) )
{
Sleep( 0 ); // Wait and give pending callbacks a chance to complete.
}

// Now, the application can be sure that no callback methods of pListener
// will be called anymore. It is now safe to delete pListener.
delete pListener;
delete pListener2;
delete pListener3;

return 0;
}

Stefan Geissler
September 13, 2012, 12:42:57
Please see this:


int main(int argc, char* argv[])
{

DShowLib::InitLibrary();


Grabber grabber[3];
CListener Listener[3];
smart_ptr<FrameHandlerSink> pSink[3];
std::string CameraName[3];

CameraName[0] = "DMx 21BUC03";
CameraName[1] = "DMx 21BUC03 1"; // Make sure, they exist!
CameraName[2] = "DMx 21BUC03 2"; // Make sure, they exist!

// Initialize the grabbers and the sink.
for( int i = 0; i < 3; i++ )
{
pSink[i] = FrameHandlerSink::create( eY800, NUM_BUFFERS );
pSink[i]->setSnapMode( 1 );

grabber.addListener( &Listener[i], GrabberListener::eFRAMEREADY);
grabber[i].setSinkType( pSink[i] );

grabber[i].openDev(CameraName[i]);
grabber[i].setFPS(30);
}

for( int i = 0; i < 3; i++ )
{
grabber[i].startLive(false); // Start the grabber.
&Listener[i].done = 0;
}

for( int i = 0; i < 3; i++ )
{
pSink[i]->snapImagesAsync( NUM_BUFFERS );
}

while(pListener->done < NUM_BUFFERS || pListener2->done < NUM_BUFFERS || pListener3->done < NUM_BUFFERS)
{
Sleep(10);
}

for( int i = 0; i < 3; i++ )
{
grabber[i].stopLive(); // Stop the grabber.
grabber[i].removeListener( &Listener[i] );
}
ExitLibrary();

return 0;
}

nikkadim
September 14, 2012, 01:57:04
Thank you!
Am I right, that after that I can have access to MemBufferCollection?


pSink[0]->getMemBufferCollection()->getBuffer(0)->getPtr()

Should I initialize the MemBufferCollection? How I can delete/clear MemBufferCollection after save?

Michael Kirmse
September 19, 2012, 12:08:35
Hello nikkadim,

you do not have to initialize the MemBufferCollection and also you do not need to delete it.

nikkadim
September 20, 2012, 18:07:53
Thank you!
But I working in 64-bit mode and use large amount of memory for capturing, how I can correctly erase it after save?

Stefan Geissler
September 21, 2012, 09:16:49
The memory is freed, when the destructors are called. This is done complete automatically in IC Imaging Control.

James Donovan
September 21, 2012, 21:07:37
If I amm going to perform simultaneous capturing for several cameras with external sync, is it necessary to run each capture in separate thread or not?

Stefan Geissler
September 24, 2012, 14:49:17
James,

You do not need different threads, because IC Imaging Control does this for you internally. For each used grabber an own grabbing thread is used.