Skip to main content

MdigProcess

This program shows the use of the MdigProcess() function to perform real-time processing.

Language: C++ Object

Functions used: MdigGrabContinuous, MappAlloc, MappControl, MappFree, MbufAlloc2d, MbufAllocColor, MbufClear, MbufFree, MdigAlloc, MdigFree, MdigGetHookInfo, MdigHalt, MdigInquire, MdigProcess, MdispAlloc, MdispFree, MdispSelect, MgraText, MimArith, MsysAlloc, MsysFree

Categories: Overview, General, Industries, Applications, Modules, Buffer, Display, Digitizer, Image Processing, What's New, Older

///////////////////////////////////////////////////////////////////////////////
// Aurora Imaging Library
// Filename: MdigProcess.cpp
//
// Description: This program shows the use of the MdigProcess() function and its multiple
// buffering acquisition to do robust real-time processing.
//
// The user's processing code to execute is located in a callback function
// that will be called for each frame acquired (see ProcessingFunction()).
//
// Note: The average processing time must be shorter than the grab time or some
// frames will be missed. Also, if the processing results are not displayed
// and the frame count is not drawn or printed, the CPU usage is reduced
// significantly.
//
// (C) 1992-2026 Zebra Technologies Corp. and/or its affiliates
// All Rights Reserved
///////////////////////////////////////////////////////////////////////////////

#include <AIOL.h>
using namespace Zebra::AuroraImagingObjectLibrary;

class MdigProcessExample
{
private:
static const int _bufferingSizeMax = 20;
int _processedImageCount = 0;
bool _exceptionInProcess = false;

App::Application _application;
Sys::System _system;
Dig::Digitizer _digitizer;
Disp::Display _display;
Gra::Context _graphicContext;
Buf::Image _imageDisp;
std::vector<Buf::Image> _ailGrabBufferList;

public:
MdigProcessExample()
: _application(App::AllocInitFlags::Default)
, _system(_application)
, _digitizer(_system)
, _display(_system)
, _graphicContext(_system)

, _imageDisp(_system, 1, _digitizer.SizeX(), _digitizer.SizeY(), Buf::AllocType::Unsigned8, Buf::AllocAttributes::ProcDispGrab)
{
for(int i = 0; i < _bufferingSizeMax; i++)
{
_ailGrabBufferList.emplace_back(_system, 1, _digitizer.SizeX(), _digitizer.SizeY(), Buf::AllocType::Unsigned8, Buf::AllocAttributes::ProcGrab);
_ailGrabBufferList.back().Clear(Color8::Black);
}
_imageDisp.Clear(Color8::Black);
_display.Select(_imageDisp);
}

~MdigProcessExample() = default;

int64_t ProcessingFunction(const Dig::ProcessEventArgs& Event)
{
try
{
const auto stringPosX = 20;
const auto stringPosY = 20;

Buf::Image modifiedBuffer = Event.ModifiedBuffer();

// Increment the frame counter.
_processedImageCount++;

// Print and draw the frame count (remove to reduce CPU usage).
Os::Printf(AilText("Processing frame #%d.\r"), _processedImageCount);

ailstring text = AilToString(_processedImageCount);
_graphicContext.DrawString(modifiedBuffer, stringPosX, stringPosY, text);

// Execute the processing and update the display.
Im::Arith::Not(modifiedBuffer, _imageDisp);

return 0;
}
catch(const AIOLException& exception)
{
// User-defined event/processing functions should always handle their own exceptions
Os::Printf(AilText("Encountered an exception during the hook.\n"));
Os::Printf(AilText("%s \n"), exception.Message().c_str());
Os::Printf(AilText("Press any key to exit. \n"));
_exceptionInProcess = true;
return 1;
}
}

void Run()
{
// Register Hook function
_digitizer.Process.Register(&MdigProcessExample::ProcessingFunction, *this);

// Print a message
Os::Printf(AilText("\nMULTIPLE BUFFERED PROCESSING.\n"));
Os::Printf(AilText("-----------------------------\n\n"));
Os::Printf(AilText("Press any key to start processing.\n\n"));

// Grab continuously on the display and wait for a key press.
_digitizer.GrabContinuous(_imageDisp);
Os::Getch();

// Halt continuous grab.
_digitizer.Halt();

// Start the processing. The processing function is called with every frame grabbed.
_digitizer.Process.Start(_ailGrabBufferList);

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

// Print a message and wait for a key press after a minimum number of frames.
Os::Printf(AilText("Press any key to stop.\n\n"));
while(!Os::Kbhit() && !_exceptionInProcess);

// Stop the processing.
_digitizer.Process.Stop();
Os::Getch();

// Return if we encountered an exception during processing.
if(_exceptionInProcess)
{
return;
}

// Print statistics.
auto ProcessFrameCount = _digitizer.ProcessFrameCount();
auto ProcessFrameRate = _digitizer.ProcessFrameRate();
Os::Printf(AilText("\n\n%d frames grabbed at %.1f frames/sec (%.1f ms/frame).\n"),
ProcessFrameCount, ProcessFrameRate, 1000.0 / ProcessFrameRate);
Os::Printf(AilText("Press any key to end.\n"));
Os::Getch();
}
};

int MosMain()
{
try
{
MdigProcessExample example;
example.Run();
}
catch(const AIOLException& exception)
{
Os::Printf(AilText("Encountered an exception during the example. \n"));
Os::Printf(AilText("%s \n"), exception.Message().c_str());
Os::Printf(AilText("Press any key to exit. \n"));
Os::Getch();
}
return 0;
}

Copyright © 2026 Zebra Technologies.