Friday, January 29, 2010

Using Euresys Multicam Library

There are several different frame grabbers and industrial cameras available in my Lab for experiment. One of them is from Euresys (sorry, this is not an advertisement) and there are several other brands. However most of the time I'm dealing with this card either with analog cameras (standard analog interface) or digital cameras (with cameralink interface).

I found that this library is very convenient to use. The disadvantage is that like other available SDK's, I found that the guide of the SDK is not quite human readable. So I was trying hard to understand how to use this, and happens to be after a lot of attempts (try, fail, ask support, fail, try again, etc.) I can understand some this library.

Therefore I want to write how to use this library in this blog. So if I have to use it again in the future, I can read it from this blog and so can you :). If there's some part that is not correct, please give a feedback to me. Thanks.

The process of using this library is divided into three parts:
1. Initialization, includes the initialization of the card(s), camera(s) and the callback function.
2. Image acquisition.
3. Stop image acquisition and memory cleanup.

Let's start from the first part, initialization. Depending on your coding platform, you can write your own code. I'm using C++ on a Borland C++ Builder compiler, if you're using Visual C++ then you might need to adjust this code to your coding platform. I use the sample code provided from Euresys.

  • Board and camera initialization
1. Initialization of driver


2. Setting error message configuration

// Activate message box error handling
McSetParamInt(MC_CONFIGURATION, MC_ErrorHandling, MC_ErrorHandling_MSGBOX);
McSetParamStr(MC_CONFIGURATION, MC_ErrorLog, "error.log");

3. Setting board topology (check your board)

McSetParamInt(MC_BOARD + 1, MC_BoardTopology, MC_BoardTopology_MONO);

4. Creating a channel

McCreate(MC_CHANNEL, &m_Channel);
McSetParamInt(m_Channel, MC_DriverIndex, 1);

  • Creating a connection to a camera

1. Choose the channel for the camera (depends on the port).

McSetParamStr(m_Channel, MC_Connector, "M");

2. Select the cam file, check your camera

McSetParamStr(m_Channel, MC_CamFile, "VCC-G22V31CL_P120SC");

3. Set the exposure time

McSetParamInt(m_Channel, MC_Expose_us, 10000);

4. Set the color format

McSetParamInt(m_Channel, MC_ColorFormat, MC_ColorFormat_Y8);

5. Set the acquisition mode

McSetParamInt(m_Channel, MC_AcquisitionMode, MC_AcquisitionMode_HFR);

  • Setting the trigger mode

1. Choose the way the first acquisition is triggered

McSetParamInt(m_Channel, MC_TrigMode, MC_TrigMode_IMMEDIATE);

2. Choose the triggering mode for subsequent acquisitions

McSetParamInt(m_Channel, MC_NextTrigMode, MC_NextTrigMode_REPEAT);

3. Choose the number of images to acquire

McSetParamInt(m_Channel, MC_SeqLength_Fr, MC_INDETERMINATE);

  • Setting up the frame parameters

1. Retrieve image dimensions

McGetParamInt(m_Channel, MC_ImageSizeX, &m_SizeX);
McGetParamInt(m_Channel, MC_ImageSizeY, &m_SizeY);
McGetParamInt(m_Channel, MC_BufferPitch, &m_BufferPitch);

2. The memory allocation for the images is automatically done by Multicam when activating the channel. We only set the number of surfaces to be created by MultiCam.

McSetParamInt(m_Channel, MC_SurfaceCount, EURESYS_SURFACE_COUNT);

  • Enabling Multicam Signals

1. Enable MultiCam signals

McSetParamInt(m_Channel, MC_SignalEnable + MC_SIG_SURFACE_PROCESSING, MC_SignalEnable_ON);
McSetParamInt(m_Channel, MC_SignalEnable + MC_SIG_ACQUISITION_FAILURE, MC_SignalEnable_ON);

2. Register the callback function

McRegisterCallback(m_Channel, GlobalCallback, this);

  • Preparing bitmap info

1. Build bitmap info Y8

m_pBitmapInfo = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
m_pBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_pBitmapInfo->bmiHeader.biPlanes = 1;
m_pBitmapInfo->bmiHeader.biBitCount = 8;
m_pBitmapInfo->bmiHeader.biCompression = BI_RGB;
m_pBitmapInfo->bmiHeader.biSizeImage = 0;
m_pBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
m_pBitmapInfo->bmiHeader.biYPelsPerMeter = 0;
m_pBitmapInfo->bmiHeader.biClrUsed = 0;
m_pBitmapInfo->bmiHeader.biClrImportant = 0;

for (int i = 0 ; i <>
m_pBitmapInfo->bmiColors[i].rgbBlue = (BYTE)i;
m_pBitmapInfo->bmiColors[i].rgbGreen = (BYTE)i;
m_pBitmapInfo->bmiColors[i].rgbRed = (BYTE)i;
m_pBitmapInfo->bmiColors[i].rgbReserved = 0;

m_pBitmapInfo->bmiHeader.biWidth = m_BufferPitch / (m_pBitmapInfo->bmiHeader.biBitCount/8) ;
m_pBitmapInfo->bmiHeader.biHeight = -(int)m_SizeY ;

  • Declaring the callback function

void WINAPI GlobalCallback(PMCSIGNALINFO SigInfo)
if (SigInfo && SigInfo->Context)
TForm1* pTForm1 = (TForm1*) SigInfo->Context ;

  • Callback function

void TForm1::Callback(PMCSIGNALINFO SigInfo)
// Update "current" surface address pointer
McGetParamInt(SigInfo->SignalInfo, MC_SurfaceAddr, (PINT32) &m_pCurrent);

// Insert the eVision code here.

// Post screen refresh message
RECT recpict;
recpict.left = 0; = 0;
recpict.right = m_SizeX-1;
recpict.bottom = m_SizeY-1;
InvalidateRect(Handle, &recpict, false);
else if (SigInfo->Signal == MC_SIG_ACQUISITION_FAILURE)
StatusBar1->SimpleText = m_StatusBarText.sprintf("Frame Rate: %.2f, Channel State: IDLE", 0);
MessageBox(NULL, "Acquisition Failure !", "PicoloVideoTrigger", MB_OK);

  • Start and Stop Grabbing

1. Start an acquisition sequence by activating the channel

McSetParamInt(m_Channel, MC_ChannelState, MC_ChannelState_ACTIVE);

2. Stop an acquisition sequence by deactivating the channel

McSetParamInt(m_Channel, MC_ChannelState, MC_ChannelState_IDLE);

  • Deactivating Channel and Cleaning Up

1. Set the channel to IDLE before deleting it.

McSetParamInt(m_Channel, MC_ChannelState, MC_ChannelState_IDLE);

2. Delete the channel


3. Terminate driver


4. Delete bitmap info

if (m_pBitmapInfo) delete m_pBitmapInfo;

That's all, I will post the details in the next article because it's too long to be posted here.

Labels: , ,