Skip to main content

MdigAutoFocus

This program performs an autofocus operation using the MdigFocus() function. Since the way to move a motorized camera lens is device-specific, we will not include real lens movement control and image grab but will simulate the lens focus with a smooth operation.

Language: C#

Functions used: MappAlloc, MappFree, MbufAlloc2d, MbufClear, MbufCopy, MbufFree, MbufInquire, MbufRestore, MdigFocus, MdispAlloc, MdispControl, MdispFree, MdispInquire, MdispSelect, MgraLine, MimConvolve, MsysAlloc, MsysFree

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

///////////////////////////////////////////////////////////////////////////////
// Aurora Imaging Library
// Filename: MdigAutoFocus.cs
//
// Description: This program performs an autofocus operation using the
// MdigFocus() function. Since the way to move a motorized
// camera lens is device-specific, we will not include real
// lens movement control and image grab but will simulate
// the lens focus with a smooth operation.
//
// Note: Under AIL-Lite, the out of focus lens simulation is not supported.
//
// (C) 1992-2026 Zebra Technologies Corp. and/or its affiliates
// All Rights Reserved
///////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

using Zebra.AuroraImagingLibrary;

namespace MDigAutoFocus
{
class Program
{
// Source image file specification.
private const string IMAGE_FILE = AIL.M_IMAGE_PATH + "BaboonMono.mim";

// Lens mechanical characteristics.
private const int FOCUS_MAX_NB_POSITIONS = 100;
private const int FOCUS_MIN_POSITION = 0;
private const int FOCUS_MAX_POSITION = (FOCUS_MAX_NB_POSITIONS - 1);
private const int FOCUS_START_POSITION = 10;

// Autofocus search properties.
private const int FOCUS_MAX_POSITION_VARIATION = AIL.M_DEFAULT;
private const int FOCUS_MODE = AIL.M_SMART_SCAN;
private const int FOCUS_SENSITIVITY = 1;

// User Data object definition.
public class DigHookUserData
{
public AIL_ID SourceImage;
public AIL_ID FocusImage;
public AIL_ID Display;
public int Iteration;
};

static void Main(string[] args)
{
AIL_ID AilApplication = AIL.M_NULL; // Application identifier.
AIL_ID AilSystem = AIL.M_NULL; // System identifier.
AIL_ID AilDisplay = AIL.M_NULL; // Display identifier.
AIL_ID AilSource = AIL.M_NULL; // Source image.
AIL_ID AilCameraFocus = AIL.M_NULL; // Focus simulated image.
AIL_INT FocusPos = 0; // Best focus position.

DigHookUserData UserData = new DigHookUserData(); // User data passed to the hook.

// Allocate defaults.
AIL.MappAllocDefault(AIL.M_DEFAULT, ref AilApplication, ref AilSystem, ref AilDisplay, AIL.M_NULL, AIL.M_NULL);

// Load the source image.
AIL.MbufRestore(IMAGE_FILE, AilSystem, ref AilSource);
AIL.MbufRestore(IMAGE_FILE, AilSystem, ref AilCameraFocus);
AIL.MbufClear(AilCameraFocus, 0);

// Select image on the display.
AIL.MdispSelect(AilDisplay, AilCameraFocus);

// Simulate the first image grab.
SimulateGrabFromCamera(AilSource, AilCameraFocus, FOCUS_START_POSITION, AilDisplay);

// Initialize user data needed within the hook function.
UserData.SourceImage = AilSource;
UserData.FocusImage = AilCameraFocus;
UserData.Iteration = 0;
UserData.Display = AilDisplay;

// Pause to show the original image.
Console.Write("\nAUTOFOCUS:\n");
Console.Write("----------\n\n");
Console.Write("Automatic focusing operation will be done on this image.\n");
Console.Write("Press any key to continue.\n\n");
Console.ReadKey(true);
Console.Write("Autofocusing...\n\n");

// Perform Autofocus.
// Since lens movement is hardware specific, no digitizer is used here.
// We simulate the lens movement with by smoothing the image data in
// the hook function instead.

// get a handle to the DigHookUserData object in the managed heap, we will use this
// handle to get the object back in the callback function
GCHandle hUserData = GCHandle.Alloc(UserData);

// We give the handle to the DigHookUserData object by casting it to a IntPtr,
// later in the hook handler we will receive our IntPtr back and cast it again
// to a GCHandle to get a handle to our object
AIL.MdigFocus(AIL.M_NULL,
AilCameraFocus,
AIL.M_DEFAULT,
MoveLensHookFunction,
GCHandle.ToIntPtr(hUserData),
FOCUS_MIN_POSITION,
FOCUS_START_POSITION,
FOCUS_MAX_POSITION,
FOCUS_MAX_POSITION_VARIATION,
FOCUS_MODE + FOCUS_SENSITIVITY,
ref FocusPos);

// Free the GCHandle when no longer used
hUserData.Free();

// Print the best focus position and number of iterations.
Console.Write("The best focus position is {0}.\n", FocusPos);
Console.Write("The best focus position found in {0} iterations.\n\n", UserData.Iteration);
Console.Write("Press any key to end.\n");
Console.ReadKey(true);

// Free all allocations.
AIL.MbufFree(AilSource);
AIL.MbufFree(AilCameraFocus);
AIL.MappFreeDefault(AilApplication, AilSystem, AilDisplay, AIL.M_NULL, AIL.M_NULL);
}

//*******************************************************************************
// Autofocus hook function responsible to move the lens.

static AIL_INT MoveLensHookFunction(AIL_INT HookType, AIL_INT Position, IntPtr UserDataHookPtr)
{
// this is how to check if the user data is null, the IntPtr class
// contains a member, Zero, which exists solely for this purpose
if (!IntPtr.Zero.Equals(UserDataHookPtr))
{
// get the handle to the DigHookUserData object back from the IntPtr
GCHandle hUserData = GCHandle.FromIntPtr(UserDataHookPtr);

// get a reference to the DigHookUserData object
DigHookUserData UserData = hUserData.Target as DigHookUserData;

// Here, the lens position must be changed according to the Position parameter.
// In that case, we simulate the lens position change followed by a grab.
if (HookType == AIL.M_CHANGE || HookType == AIL.M_ON_FOCUS)
{
SimulateGrabFromCamera(UserData.SourceImage, UserData.FocusImage, (int)Position, UserData.Display);
UserData.Iteration++;
}
}

return 0;
}

//**********************************************************************************
// Utility function to simulate a grab from a camera at different lens position
// by smoothing the original image. It should be replaced with a true camera grab.
//
// Note that this lens simulation will not work under AIL-lite because it uses
// MimConvolve().

// Lens simulation characteristics.
private const double FOCUS_BEST_POSITION = (FOCUS_MAX_NB_POSITIONS / 2);

static void SimulateGrabFromCamera(AIL_ID SourceImage, AIL_ID FocusImage, AIL_INT Iteration, AIL_ID AnnotationDisplay)
{
int NbSmoothNeeded = 0; // Number of smooths needed.

AIL_INT BufType = 0; // Buffer type.
AIL_INT BufSizeX = 0; // Buffer size X.
AIL_INT BufSizeY = 0; // Buffer size Y.
int Smooth = 0; // Smooth index.
AIL_ID TempBuffer = AIL.M_NULL; // Temporary buffer.
AIL_ID SourceOwnerSystem = AIL.M_NULL; // Owner system of the source buffer.

// Compute number of smooths needed to simulate focus.
NbSmoothNeeded = (int)Math.Abs(Iteration - FOCUS_BEST_POSITION);

// Buffer inquires.
BufType = AIL.MbufInquire(FocusImage, AIL.M_TYPE, AIL.M_NULL);
BufSizeX = AIL.MbufInquire(FocusImage, AIL.M_SIZE_X, AIL.M_NULL);
BufSizeY = AIL.MbufInquire(FocusImage, AIL.M_SIZE_Y, AIL.M_NULL);

if (NbSmoothNeeded == 0)
{
// Directly copy image source to destination.
AIL.MbufCopy(SourceImage, FocusImage);
}
else if (NbSmoothNeeded == 1)
{
// Directly convolve image from source to destination.
AIL.MimConvolve(SourceImage, FocusImage, AIL.M_SMOOTH);
}
else
{
SourceOwnerSystem = (AIL_ID)AIL.MbufInquire(SourceImage, AIL.M_OWNER_SYSTEM, AIL.M_NULL);

// Allocate temporary buffer.
AIL.MbufAlloc2d(SourceOwnerSystem, BufSizeX, BufSizeY, BufType, AIL.M_IMAGE + AIL.M_PROC, ref TempBuffer);

// Perform first smooth.
AIL.MimConvolve(SourceImage, TempBuffer, AIL.M_SMOOTH);

// Perform smooths.
for (Smooth = 1; Smooth < NbSmoothNeeded - 1; Smooth++)
{
AIL.MimConvolve(TempBuffer, TempBuffer, AIL.M_SMOOTH);
}

// Perform last smooth.
AIL.MimConvolve(TempBuffer, FocusImage, AIL.M_SMOOTH);

// Free temporary buffer.
AIL.MbufFree(TempBuffer);
}

// Draw position cursor.
DrawCursor(AnnotationDisplay, Iteration);
}

//***************************************************************
// Draw position of the focus lens.

// Cursor specifications.

private static double CURSOR_POSITION(AIL_INT BufSizeY) { return ((BufSizeY * 7) / 8); }
private const int CURSOR_SIZE = 14;
private static readonly int CURSOR_COLOR = AIL.M_COLOR_GREEN;

static void DrawCursor(AIL_ID AnnotationDisplay, AIL_INT Position)
{
AIL_ID AnnotationImage = AIL.M_NULL;
AIL_INT BufSizeX = 0;
AIL_INT BufSizeY = 0;
AIL_INT n = 0;

// Prepare for overlay annotations.
AIL.MdispControl(AnnotationDisplay, AIL.M_OVERLAY, AIL.M_ENABLE);
AIL.MdispControl(AnnotationDisplay, AIL.M_OVERLAY_CLEAR, AIL.M_DEFAULT);
AIL.MdispInquire(AnnotationDisplay, AIL.M_OVERLAY_ID, ref AnnotationImage);
AIL.MbufInquire(AnnotationImage, AIL.M_SIZE_X, ref BufSizeX);
AIL.MbufInquire(AnnotationImage, AIL.M_SIZE_Y, ref BufSizeY);
AIL.MgraControl(AIL.M_DEFAULT, AIL.M_COLOR, CURSOR_COLOR);

// Write annotations.
n = (BufSizeX / FOCUS_MAX_NB_POSITIONS);
AIL.MgraLine(AIL.M_DEFAULT, AnnotationImage, 0, CURSOR_POSITION(BufSizeY) + CURSOR_SIZE, BufSizeX - 1, CURSOR_POSITION(BufSizeY) + CURSOR_SIZE);
AIL.MgraLine(AIL.M_DEFAULT, AnnotationImage, Position * n, CURSOR_POSITION(BufSizeY) + CURSOR_SIZE, Position * n - CURSOR_SIZE, CURSOR_POSITION(BufSizeY));
AIL.MgraLine(AIL.M_DEFAULT, AnnotationImage, Position * n, CURSOR_POSITION(BufSizeY) + CURSOR_SIZE, Position * n + CURSOR_SIZE, CURSOR_POSITION(BufSizeY));
AIL.MgraLine(AIL.M_DEFAULT, AnnotationImage, Position * n - CURSOR_SIZE, CURSOR_POSITION(BufSizeY), Position * n + CURSOR_SIZE, CURSOR_POSITION(BufSizeY));
}
}
}

Copyright © 2026 Zebra Technologies.