1

I'm new to programming with Matrox (MIL) and C++. I've been wanting to use a camera to its limit (120 Hz frame rate). I'm currently using MIL through Microsoft Visual Studio to program the camera. How my program works currently is using MdigProcess to acquire and save each image using a separate function. However, this slows down the camera to roughly 10Hz since it calls the function every time the to save the image in a buffer when it is ready. If I don't save the images, then the camera works fine. But I won't have any data :/

I am thinking of having the images (100 images for now) in the buffers first once, then save them. Is there a way to do that? Here is my attempt:

#include <mil.h>
#include <stdlib.h>
/* Number of images in the buffering grab queue.
Generally, increasing this number gives a better real-time grab.
*/
#define BUFFERING_SIZE_MAX 5

/* User's processing function prototype. */
MIL_INT MFTYPE ProcessingFunction(MIL_INT HookType, MIL_ID HookId, void* 
HookDataPtr);

/* User's processing function hook data structure. */
typedef struct
{
MIL_ID  MilDigitizer;
MIL_ID  MilImageDisp;
MIL_INT ProcessedImageCount;
} HookDataStruct;


/* Main function. */
/* ---------------*/

int MosMain(void)
{
MIL_ID MilApplication;
MIL_ID MilSystem;
MIL_ID MilDigitizer;
MIL_ID MilDisplay;   /* Display identifier. */
MIL_ID MilImageDisp; /* Display Image buffer identifier. */
MIL_ID MilGrabBufferList[BUFFERING_SIZE_MAX] = { 0 };
MIL_INT MilGrabBufferListSize;
MIL_INT ProcessFrameCount = 0, ProcessFrameMissed = 0, ProcessFrameCorrupted = 0;
MIL_DOUBLE ProcessFrameRate = 0;
MIL_DOUBLE     FrameRate; // Initializes the FrameRate variable as double
HookDataStruct UserHookData;

MappAlloc(M_NULL, M_DEFAULT, &MilApplication); /* This initializes the MIL library. M_NULL means no cluster manager will be used. M_DEFAULT means reported error message will be displayed. */
MsysAlloc(M_SYSTEM_RAPIXOCL, M_DEFAULT, M_DEFAULT, &MilSystem); /* This allocates a MIL system*/
MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_DEFAULT, &MilDisplay); /* M_WINDOWED means it will display at a separate window*/
MdigAlloc(MilSystem, M_DEV0, MIL_TEXT("C:\\Users\\fluids-student\\Documents\\JAI 5000 PMCL.dcf"), M_DEFAULT, &MilDigitizer);
/* Allocate a monochrome display buffer. */
MbufAlloc2d(MilSystem, 2560, 2048, 8 + M_UNSIGNED, M_IMAGE + M_DISP + M_GRAB + M_PROC, &MilImageDisp);
MbufClear(MilImageDisp, M_BLACK);

/* Display the image buffer. */
MdispSelect(MilDisplay, MilImageDisp);

/* This inquires the frame rate */
MdigInquire(MilDigitizer, M_SELECTED_FRAME_RATE, &FrameRate);
MosPrintf(MIL_TEXT("The frame rate is @ %0.2f fps.\n"), FrameRate);

/* Print a message. */
MosPrintf(MIL_TEXT("\nMULTIPLE BUFFERED PROCESSING.\n"));
MosPrintf(MIL_TEXT("-----------------------------\n\n"));
MosPrintf(MIL_TEXT("Press <Enter> to start acquisition.\n\n"));

/* Grab continuously on the display and wait for a key press. */
MdigGrabContinuous(MilDigitizer, MilImageDisp);
MosGetch();

/* Halt continuous grab. */
MdigHalt(MilDigitizer);

/* Allocate the grab buffers and clear them. */
MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE);
for (MilGrabBufferListSize = 0; MilGrabBufferListSize < BUFFERING_SIZE_MAX;
    MilGrabBufferListSize++)
{
    MbufAlloc2d(MilSystem,
        MdigInquire(MilDigitizer, M_SIZE_X, M_NULL),
        MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL),
        8L + M_UNSIGNED,
        M_IMAGE + M_GRAB + M_PROC,
        &MilGrabBufferList[MilGrabBufferListSize]);
    if (MilGrabBufferList[MilGrabBufferListSize])
        MbufClear(MilGrabBufferList[MilGrabBufferListSize], 0xFF);
    else
        break;
}
MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE);

/* Initialize the user's processing function data structure. */
UserHookData.MilDigitizer = MilDigitizer;
UserHookData.MilImageDisp = MilImageDisp;
UserHookData.ProcessedImageCount = 0;

/* Start the processing. The processing function is called with every frame grabbed. */
MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize,
    M_SEQUENCE + M_COUNT(100), M_DEFAULT, ProcessingFunction, &UserHookData);

/* Here the main() is free to perform other tasks while the processing is executing. */
/* --------------------------------------------------------------------------------- */

/* Stop the processing. */
MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize,
    M_STOP, M_DEFAULT, ProcessingFunction, &UserHookData);

/* Print statistics. */
MdigInquire(MilDigitizer, M_PROCESS_FRAME_COUNT, &ProcessFrameCount);
MdigInquire(MilDigitizer, M_PROCESS_FRAME_RATE, &ProcessFrameRate);
MdigInquire(MilDigitizer, M_PROCESS_FRAME_MISSED, &ProcessFrameMissed);
MdigInquire(MilDigitizer, M_PROCESS_FRAME_CORRUPTED, &ProcessFrameCorrupted);
MosPrintf(MIL_TEXT("\n\n%d frames grabbed at %.1f frames/sec (%.1f ms/frame).\n"),
    (int)ProcessFrameCount, ProcessFrameRate, 1000.0 / ProcessFrameRate);
MosPrintf(MIL_TEXT("%ld frames missed.\n"), ProcessFrameMissed);
MosPrintf(MIL_TEXT("%ld frames corrupted.\n"), ProcessFrameCorrupted);
MosPrintf(MIL_TEXT("Press <Enter> to end.\n\n"));
MosPrintf(MIL_TEXT("BufferListSize = %d\n"), MilGrabBufferListSize);
MosGetch();

/* Free the grab buffers. */
while (MilGrabBufferListSize > 0)
    MbufFree(MilGrabBufferList[--MilGrabBufferListSize]);

/* Free display buffer. */
MbufFree(MilImageDisp);

/* Release defaults. */
MdigFree(MilDigitizer);
MdispFree(MilDisplay);
MsysFree(MilSystem);
MappFree(MilApplication);

return 0;
}

/* User's processing function called every time a grab buffer is ready. */
/* -------------------------------------------------------------------- */

/* Local defines. */
#define STRING_LENGTH_MAX  20
#define STRING_POS_X       20
#define STRING_POS_Y       20

MIL_INT MFTYPE ProcessingFunction(MIL_INT HookType, MIL_ID HookId, void* HookDataPtr)
{
HookDataStruct* UserHookDataPtr = (HookDataStruct*)HookDataPtr;
MIL_ID ModifiedBufferId;
MIL_TEXT_CHAR Text[STRING_LENGTH_MAX] = { MIL_TEXT('\0'), };
MIL_TEXT_CHAR junkoutput[STRING_LENGTH_MAX] = { MIL_TEXT('\0'), };

/* Retrieve the MIL_ID of the grabbed buffer. */
MdigGetHookInfo(HookId, M_MODIFIED_BUFFER + M_BUFFER_ID, &ModifiedBufferId);

/* Increment the frame counter. */
UserHookDataPtr->ProcessedImageCount++;

/* Print and draw the frame count (remove to reduce CPU usage). */
MosPrintf(MIL_TEXT("Acquiring frame #%d.\r"), (int)UserHookDataPtr->ProcessedImageCount);
MosSprintf(Text, STRING_LENGTH_MAX, MIL_TEXT("%d"),
    (int)UserHookDataPtr->ProcessedImageCount);
/* Execute the processing and update the display. */
MbufCopy(ModifiedBufferId, UserHookDataPtr->MilImageDisp);  // Remove comment to see the image acquisition. Will slow down the frame rate/ acquisition time
/* Create file name base on the index of the frame that is being processed */
MosSprintf(Text, STRING_LENGTH_MAX, MIL_TEXT("Image%03li.png"), UserHookDataPtr->ProcessedImageCount); // 0-adds zeroes to the naming, 3- three places, l-long integer, i-signed decimal integer
/* Save image to disk */
 MbufSave(Text, UserHookDataPtr->MilImageDisp);

return 0;
}

Thanks for all the help I can get!

Paulo Yu
  • 11
  • 1
  • do you have enough memory to hold 100 images, how big is each one? – pm100 Feb 04 '22 at 01:30
  • Hello, thanks for the response. I believe so. Each image I was able to save 2560x2048 at 5 megapixels before. I have a 16BG ram if I remember correctly. My goal is to acquire at least 500 images at 120Hz frame rate. – Paulo Yu Feb 04 '22 at 01:59
  • the other thing to do is compute and store only deltas, like you are doing video (pframe iframe) – pm100 Feb 04 '22 at 02:14
  • Do you find a solution? I'm trying to adquire and save 100 images (5000x4000) from 3 cameras using 24Hz frame rate and with a frame burst operations... I'm facing memory problems because as you said, MdigProcess uses an external ProcessingFunction and wants all buffers previously allocated... 64Gb on RAM is not enought in my case. I'm losing frames. Is any other way to not allocate all this large size buffers or not use the external ProcessingFunction? – Flippi96 Feb 08 '23 at 14:13

0 Answers0