afengine_web_logo

AFEngine C++ library

v3.0.1

Table of contents

Overview

AFEngine C++ library provides auto focus function for different software lens controllers. AFEngine class doesn’t control lens directly. It just get lens state and gives what should lens controller do for reaching optimal focus position. The library provides various auto focus features: push focus, continuous auto focus (after changing zoom), auto focus timeout, autofocus sensitivity trigger, auto focus ROI change and auto focus ROI detection. The focus factor is computed with a noise-robust band-pass (difference-of-box) edge-energy measure, so it stays reliable on noisy (e.g. thermal) video without any separate noise filtering. The library has a simple interface for embedding in different software lens controllers. To ensure autofocus operation, the user must transfer each new video frame to the library, as well as transfer the current zoom and focus positions. The library depends on Frame library (provides description of video frame class, source code included, Apache 2.0 license). The library uses C++17 standard. The test application uses OpenCV library (for user interface, video file reading and video recording, linked, Apache 2.0 license).

Versions

Table 1 - Library versions.

Version Release date What’s new
1.0.0 02.11.2023 First version.
1.1.0 25.04.2024 - Code structure updated.
- Documentation updated.
1.1.1 23.04.2024 - Submodules updated.
- Documentation updated.
1.2.1 29.07.2024 - CMake updated.
- Description updated.
- Data structures updated.
2.0.0 23.08.2024 - Add calibration procedure.
2.0.1 16.09.2024 - Fix calibration procedure.
- Add AF stuck avoidance.
2.1.0 12.03.2025 - Add noise reduction.
- Add zero focus factor value (30).
2.1.1 14.05.2025 - Zero focus factor set to (10).
- Fix continues mode Interruption.
2.1.2 28.03.2026 - Denoiser submodule updated.
3.0.0 24.06.2026 - Focus factor replaced with noise-robust band-pass (difference-of-box) measure.
- Denoiser / noise reduction removed.
- FF_DECREASE_THRESHOLD parameter removed (now a fixed internal constant applied to the focus-factor signal).
- Autofocus peak detection made fully adaptive (no fixed drop threshold).
- FOCUS_POSITION_ACCURACY default set to 0.5% of the full range.
- CAF refocus timeout fixed: the period is now measured from autofocus finish and no longer adds a fixed re-settle delay, so it matches CAF_REFOCUS_TIMEOUT_SEC.
- Test application reworked to drive the full AFEngine (AFEngineTest); the ROI is now selected with the mouse (left-button drag to draw and set it) instead of the WASD/QE keys, it shows the AFEngine per-frame compute time, and it can record the displayed video (with the ROI overlay) to afengine_<date>_<time>.mp4 with the R key.
- Bug fixes (findRoi ROI position, ROI bounds, getParam not-found return value).
3.0.1 13.07.2026 - Restored the FF_DECREASE_THRESHOLD parameter and the relative-drop autofocus stop criterion.

Library files

The library is supplied only by source code. The user is given a set of files in the form of a CMake project (repository). The repository structure is shown below:

CMakeLists.txt ------------ Main CMake file of the library.
3rdparty ------------------ Folder with third-party libraries.
    CMakeLists.txt -------- CMake file to includes third-party libraries.
    Frame ----------------- Folder with Frame library source code.
src ----------------------- Folder with source code of the library.
    CMakeLists.txt -------- CMake file of the library.
    AFEngine.cpp ---------- C++ implementation file.
    AFEngine.h ------------ Header file which includes AFEngine class declaration.
    AFEngineVersion.h ----- Header file which includes version of the library.
    AFEngineVersion.h.in -- CMake service file to generate version file.
    FocusDetector.h ------- Header file of focus detector implementation.
    FocusDetector.cpp ----- C++ implementation file of focus detector.
test ---------------------- Folder with the test application.
    CMakeLists.txt -------- CMake file of the test application.
    main.cpp -------------- Source code of the AFEngineTest application.

Focus factor calculation

The focus factor (parameter FOCUS_FACTOR) is the value the library maximizes to reach optimal focus. It is calculated for the auto focus ROI of the most recently added video frame. AFEngine uses a band-pass edge-energy measure, implemented as the difference of two box blurs (a fast box-blur approximation of a Difference-of-Gaussians). For every pixel of the ROI two local averages of the grayscale image are computed - a small one (inner box) and a large one (outer box) - and the focus factor is the mean squared difference between them over the ROI:

d(x, y)      = avg_inner(x, y) - avg_outer(x, y)        // band-pass response
focus factor = FF_ZERO + ( 1 / N ) * Σ d(x, y)^2        // N = number of ROI pixels

where FF_ZERO is a small constant offset (so the value is always > 0). The inner box size is 7×7 pixels and the outer box size is 15×15 pixels by default. The measure works because the difference of two blurs keeps only a band of spatial frequencies:

Frequency band Removed / kept by Effect
High frequencies (sensor noise) removed by the inner box noise no longer inflates the focus factor (important for thermal video)
Low frequencies (overall brightness, soft bright blobs, illumination gradients) removed by the outer box the focus factor does not depend on brightness / contrast
Mid frequencies (real sharp edges) kept in the difference maximal exactly when the image is in focus

As a result the focus factor is robust to noise and invariant to brightness / contrast changes, so it does not need any separate noise-reduction filtering and does not get fooled by bright but blurry frames.

Properties:

  • Noise robustness - built into the measure (the inner box suppresses high-frequency noise).
  • Brightness / contrast invariance - the outer box removes the low-frequency component.
  • Performance - O(N) per frame: the two box averages are obtained from a separable sliding window (incremental per-column sums plus a horizontal running sum) using small int32 buffers with sequential, cache-friendly access. No floating-point square roots, no external filtering.
  • Value range - relative units that depend on the ROI content; always > 0. Only the relative maximum matters for selecting the best-focus frame and for the continuous auto focus logic, not the absolute value.

Automatic ROI position check. The band-pass needs a border of real pixels (equal to the outer-box radius, 7 pixels) around every ROI pixel. If the user places the auto focus ROI closer than that to a frame edge, the region actually used for the calculation is automatically reduced (clamped to stay at least the border distance away from each edge) instead of sampling out-of-frame pixels - this keeps the focus factor correct near the frame borders. The auto-ROI detection (ROI_MODE == 1) likewise never places the detected ROI closer than the border distance to a frame edge. The auto-ROI detection of the “optimal” ROI position (ROI_MODE == 1) uses a separate gradient (Sobel) energy measure to locate the most textured region of the frame; the band-pass measure above is then used to track focus for the selected ROI.

Autofocus search and adaptive peak detection. The autofocus moves the lens and tracks the running peak focus factor. Deciding when it has passed the peak (and may reverse direction / stop) is done with no fixed threshold - two adaptive criteria are used instead, so the search reverses quickly on both clean low-contrast and noisy video without per-lens or per-scene tuning:

  1. Is it a real peak? (an absolute gate). The library continuously estimates the defocused floor as the median focus factor seen during the pass (the search spends most of its time defocused, so the median sits on the floor and ignores the few large samples around the real peak). A defocused frame has no real edges, so the floor above the flat-image baseline (FF_ZERO) is essentially the noise/grain energy of the video. A candidate is accepted as a real peak only when its prominence (running maximum minus the median floor) exceeds a small multiple of that noise floor. This gate scales with the video’s own noise, so it rejects noise and small content bumps - large on noisy video, small on clean video.

  2. Have we fallen far enough past it? (a proportional trigger). Once the gate is passed, the search reverses when the focus factor has fallen back down by a fixed fraction of that peak’s own prominence. Because the trigger scales with each peak’s height, the search reverses soon after the peak for a shallow low-contrast peak just as it does for a sharp high-contrast one - it does not have to sweep most of the focus range waiting for a fixed absolute drop.

Separating “real peak?” (absolute, noise-scaled) from “fallen enough?” (relative to the peak’s height) is what makes the search both robust to noise and fast on low-contrast scenes. Once the peak is bracketed, its position is refined to sub-step accuracy by parabolic interpolation of the three samples around the maximum. If a scene’s peak is too shallow to clear the noise gate at all, the search safely falls back to sweeping to the travel limit and taking the global maximum.

AFEngine class description

AFEngine class declaration

AFEngine class declared in AFEngine.h file. Class declaration:

namespace cr
{
namespace af
{
/// Auto Focus Engine class.
class AFEngine 
{
public:

    /// Get engine version.
    static std::string getVersion();

    /// Add video frame for processing.
    bool addVideoFrame(cr::video::Frame& frame);
    
    /// Update data to get AF State Machine value.
    int updateData(int zoomPos, int focusPos, int& reqPos);

    /// Set the AFEngine param.
    bool setParam(AFParam id, float value);

    /// Get the AFEngine param.
    float getParam(AFParam id);

    /// Execute command.
    bool executeCommand(AFCommand id);
};
}
}

getVersion method

The getVersion() static method returns string of current version of AFEngine class. Method declaration:

static std::string getVersion();

Method can be used without AFEngine class instance:

cout << "AFEngine class version: " << AFEngine::getVersion() << endl;

Console output:

AFEngine class version: 3.0.0

addVideoFrame method

The addVideoFrame(…) method adds video frame to library for focus factor calculation. To ensure autofocus operation, the user must transfer each new video frame to the library, as well as transfer the current zoom and focus positions. The library calculates the focus factor for each frame of the video. The focus factor calculation is performed in the region of interest set in the parameters (AFParam enum).

bool addVideoFrame(cr::video::Frame& frame);
Parameter Value
frame Frame class object. The library support RAW pixel formats: BGR24, RGB24, GRAY, NV12, NV21, YU12, YV12, UYVY, YUYV and YUV24. Minimum width / height of video frame is 32. Maximum width / height of video frame is 8192.

Returns: TRUE if frame has been added or FALSE if not.

updateData method

The updateData(…) method intended to set current lens state (zoom and focus position) and gives what should lens controller do for reaching optimal focus position. The library controls auto focus mode (off, push, continuous). The principle of the library is as follows: every time the zoom or focus position changes, the user must call the updateData(…) method. In this case, the method will return the code of the action that must be performed by the lens controller to implement the autofocus function. It is up to the lens controller whether the same command is sent multiple times.

int updateData(int zoomPos, int focusPos, int& reqPos);
Parameter Value
zoomPos Current zoom position from controller. Should use zoom position value: 0 (full wide) - 65535 (full tele). Lens controller must convert native lens zoom position range to [0:65535].
focusPos Current focus position from controller. Should use focus position value: 0 (full near) - 65535 (full far). Lens controller must convert native lens focus position range to [0:65535].
reqPos Reference to required focus position. The lens controller should move lens to this position.

Returns: Action ID should be done in Lens controller.

Return value Description
0 Nothing to do
1 Go to focus FAR. The movement speed must be decided by lens controller to provide necessary auto focus accuracy. Fast movement can lead to not accurate auto focus.
2 Go to “start” focus position as fast as possible. Necessary focus position is reqPos. “Start” focus position is the position of auto focus start.
3 Go to focus NEAR. The movement speed must be decided by lens controller to provide necessary auto focus accuracy. Fast movement can lead to not accurate auto focus.

setParam method

The setParam(…) method sets AFEngine parameters value. Method declaration:

bool setParam(AFParam id, float value);
Parameter Description
id AFEngine parameter ID according to AFParam enum.
value AFEngine parameter value.

Returns: TRUE if the parameter was set or FALSE if not.

getParam method

The getParam(…) method designed to obtain AFEngine parameter value. Method declaration:

float getParam(AFParam id);
Parameter Description
id AFEngine parameter ID according to AFParam enum.

Returns: parameter value or -1 if the parameter doesn’t exist.

executeCommand method

The executeCommand(…) method designed to execute AFEngine action command.

bool executeCommand(AFCommand id);
Parameter Description
id AFEngine action command ID according to AFCommand enum.

Returns: TRUE if the command executed or FALSE.

Data structures

AFCommand enum

The AFCommand enum declared in AFEngine.h file:

enum class AFCommand
{
    /// Start auto focus.  
    START,
    /// Stop auto focus.  
    STOP,
    /// Calibrate auto focus engine.
    CALIBRATE
};

Table 2 - AFEngine action commands description.

Command Description
START Start autofocus. Push focus.
STOP Stop autofocus.
CALIBRATE Calibrate auto focus engine. Measure time delay between lens position and corresponding frame and set TIME_ADJUSTMENT parameter of the AFParam enum. Typically the video from the camera comes later than the zoom or focus position from the lens controller. That is, there is a delay between the data and the focus or zoom position and the corresponding video frame. This delay affects the accuracy of autofocus (the longer the delay, the less accurate the autofocus). To reduce the effect of time delay between the zoom and focus positions and the video frame, AFEngine has a built-in calibration algorithm that is triggered by user command. Calibration is usually performed once for a particular camera and lens. To perform a calibration, the user must point the camera at a contrasting object, adjust the focus so that the object is contrasting in the video and run the calibration. AFEngine will then perform a series of actions to calculate the TIME_ADJUSTMENT parameter of the AFParam enum.

AFParam enum

AFParam enum declared in AFEngine.h file:

enum class AFParam
{
    /// Auto focus mode
    /// 0 - Off 1 - PUSH AF, 2 - CAF
    /// (write/read)
    MODE,
    /// Auto focus ROI top-left corner horizontal position in pixels.
    /// Auto focus ROI is rectangle.
    /// (write/read)
    ROI_X0,
    /// Auto focus ROI top-left corner vertical position in pixels.
    /// Auto focus ROI is rectangle.
    /// (write/read)
    ROI_Y0,
    /// Auto focus ROI bottom-right corner horizontal position in pixels.
    /// Auto focus ROI is rectangle.
    /// (write/read)
    ROI_X1,
    /// Auto focus ROI bottom-right corner vertical position in pixels.
    /// Auto focus ROI is rectangle.
    /// (write/read)
    ROI_Y1,
    /// Auto focus auto ROI top-left corner vertical position in pixels.
    /// Auto focus ROI is rectangle.
    /// (read)
    AUTO_ROI_Y0,
    /// Auto focus auto ROI top-left corner horizontal position in pixels.
    /// Auto focus ROI is rectangle.
    /// (read)
    AUTO_ROI_X0,
    /// ROI width (pixels) for auto focus algorithm when lens controller detects
    /// ROI position automatically. Value: from 8 to (video frame width -
    /// AUTO_ROI_BORDER * 2).
    /// (write/read)
    AUTO_ROI_WIDTH,
    /// ROI height (pixels) for auto focus algorithm when lens controller
    /// detects ROI position automatically. Value: from 8 to
    /// (video frame height - AUTO_ROI_BORDER * 2).
    /// (write/read)
    AUTO_ROI_HEIGHT,
    /// Video frame border size (along vertical and horizontal axes).
    /// Value: border size from 0 to video frame
    /// min(video frame width/height) / 2.
    /// (write/read)
    AUTO_ROI_BORDER,
    /// AF ROI mode. Value: 0 - Manual position, 1 - Auto position.
    /// (write/read)
    ROI_MODE,
    /// Focus factor threshold for CAF mode. Value 0-100 (%).
    /// (write/read)
    CAF_FF_THRESHOLD,
    /// AF refocus timeout sec in CAF mode. 0 - no refocus by timeout
    /// (write/read)
    CAF_REFOCUS_TIMEOUT_SEC,
    /// Focus factor value
    /// (read)
    FOCUS_FACTOR,
    /// Threshold to detect FOCUS moving.
    /// Depends on implementation
    /// (write/read)
    FOCUS_MOVE_THRESHOLD,
    /// Threshold to detect ZOOM moving. 
    /// Depends on implementation
    /// (write/read)
    ZOOM_MOVE_THRESHOLD,
    /// Time adjustment for AF procedure, ms.
    /// Basically frame come with some delay relative to the position,
    /// For optimal FF taken past position.
    /// (write/read)
    TIME_ADJUSTMENT,
    /// FOCUS position accuracy to detect position reached 
    /// in case focus position feadback is not accurate
    /// AFEngine decide that required position reached if FOCUS stop moving 
    /// (according FOCUS_MOVE_THRESHOLD option) and
    /// current position differ from required less than FOCUS_POSITION_ACCURACY
    /// (write/read)
    FOCUS_POSITION_ACCURACY,
    /// Focus factor decreasing threshold. Value 0-100 (%).
    /// In AF procedure switch focus moving direction if
    /// MAX FOCUS_FACTOR * FF_DECREASE_THRESHOLD > CURRENT FOCUS_FACTOR.
    /// Default 80%.
    /// (write/read)
    FF_DECREASE_THRESHOLD
};

Table 3 - Auto focus engine params description.

Parameter Access Description
MODE read / write Autofocus mode: 0 - Off (method updateData(…) always returns 0) 1 - Push AF (doing auto focus algorithm only by command), 2 - Continuous AF (start autofocus after zoom changed).
ROI_X0 read / write Autofocus ROI top-left corner horizontal position, pixels. Initial auto focus ROI position must be set by user in advance according to frame size.
ROI_Y0 read / write Autofocus ROI top-left corner vertical position, pixels. Initial auto focus ROI position must be set by user in advance according to frame size.
ROI_X1 read / write Autofocus ROI bottom-right corner horizontal position, pixels. Initial auto focus ROI position must be set by user in advance according to frame size.
ROI_Y1 read / write Autofocus ROI bottom-right corner vertical position, pixels. Initial auto focus ROI position must be set by user in advance according to frame size.
AUTO_ROI_Y0 read only Autofocus auto ROI top-left corner vertical position in pixels. If parameter ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AUTO_ROI_X0 read only Autofocus auto ROI top-left corner horizontal position in pixels. If parameter ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AUTO_ROI_WIDTH read / write Auto ROI width (pixels) for autofocus algorithm. By default 128. User should set preferable auto focus ROI width. If parameter ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AUTO_ROI_HEIGHT read / write Auto ROI height (pixels) for autofocus algorithm. User should set preferable auto focus ROI height. If parameter ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AUTO_ROI_BORDER read / write Auto ROI border size, pixels. Border size used to exclude video frame borders for auto ROI detection.
ROI_MODE read / write Auto focus ROI mode: 0 - Manual position (user must set ROI position), 1 - Auto position (“optimal” ROI position will be detected by library).
CAF_FF_THRESHOLD read / write Threshold for changes of focus factor to start refocus in Continuous AF mode: 0% - no check (the library will no control focus factor to start AF automatically), 100% - changing x2.
CAF_REFOCUS_TIMEOUT_SEC read / write Timeout for automatic refocus, seconds. 0 - no automatic refocus, 100000 - maximum value.
FOCUS_FACTOR read only Focus factor value, relative units depends on image (>0).
FOCUS_MOVE_THRESHOLD read / write Focus moving threshold in units ([0:65535] range). Value depends on lens controller. Used to detect Focus movement. Some lens controller may give us zoom and focus position with fluctuations. To avoid false focus movement detection user should set threshold (if current focus position has absolute value ([0:65535] range) more than previous +/- threshold the AFEngine will decide that focus is moving.)
ZOOM_MOVE_THRESHOLD read / write Zoom moving threshold in units ([0:65535] range). Value depends on lens controller. Used to detect Zoom movement. Some lens controller may give us zoom and focus position with fluctuations. To avoid false zoom movement detection user should set threshold (if current zoom position has absolute value ([0:65535] range) more than previous +/- threshold the AFEngine will decide that zoom is moving.)
TIME_ADJUSTMENT read / write Usually in the systems there is a latency between video frame and actual zoom and focus position obtained from lens hardware. Also there usually number of zoom and focus measurements per second more then video FPS. The library assumes that obtaining zoom and focus position faster than corresponding frame coming to AFEngine. The value means delay in ms. between current zoom/focus position and corresponding frame. May be measured by CALIBRATE command.
FOCUS_POSITION_ACCURACY read / write Focus position accuracy to detect position reached in units ([0:65535] range). It used to detect when lens reached particular position. In case focus position feedback is not accurate AFEngine decide that required position reached if FOCUS stop moving (according FOCUS_MOVE_THRESHOLD option) and current position differ from required less than FOCUS_POSITION_ACCURACY. Default: 0.5% of the full 0-65535 range (65535 × 0.005 ≈ 328).
FF_DECREASE_THRESHOLD read / write Focus factor decreasing threshold, 0-100 (%). During the autofocus sweep the moving direction is reversed (peak considered passed) as soon as the current focus factor drops below this percentage of the maximum focus factor seen so far. Default 80%. Lower values make the peak detection more tolerant to noise; higher values stop the sweep sooner.

Build and connect to your project

Typical commands to build AFEngine library:

cd AFEngine 
mkdir build
cd build
cmake ..
make

If you want connect AFEngine library to your CMake project as source code you can make follow. For example, if your repository has structure:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp

Create folder 3rdparty in your repository and copy AFEngine repository folder there. New structure of your repository:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp
3rdparty
    AFEngine

Create CMakeLists.txt file in 3rdparty folder. CMakeLists.txt should contain:

cmake_minimum_required(VERSION 3.13)

################################################################################
## 3RD-PARTY
## dependencies for the project
################################################################################
project(3rdparty LANGUAGES CXX)

################################################################################
## SETTINGS
## basic 3rd-party settings before use
################################################################################
# To inherit the top-level architecture when the project is used as a submodule.
SET(PARENT ${PARENT}_YOUR_PROJECT_3RDPARTY)
# Disable self-overwriting of parameters inside included subdirectories.
SET(${PARENT}_SUBMODULE_CACHE_OVERWRITE OFF CACHE BOOL "" FORCE)

################################################################################
## INCLUDING SUBDIRECTORIES
## Adding subdirectories according to the 3rd-party configuration
################################################################################
if (${PARENT}_SUBMODULE_AF_ENGINE)
    add_subdirectory(AFEngine)
endif()

File 3rdparty/CMakeLists.txt adds folder AFEngine to your project and will exclude test application from compiling (by default tests excluded from compiling if AFEngine included as sub-repository). Your repository new structure will be:

CMakeLists.txt
src
    CMakeList.txt
    yourLib.h
    yourLib.cpp
3rdparty
    CMakeLists.txt
    AFEngine

Next you need include folder 3rdparty in main CMakeLists.txt file of your repository. Add string at the end of your main CMakeLists.txt:

add_subdirectory(3rdparty)

Next you have to include AFEngine library in your src/CMakeLists.txt file:

target_link_libraries(${PROJECT_NAME} AFEngine)

Done!

Example

Pseudo code of using AFEngine in lens controller library:

yourLens.h

#include "AFEngine.h"
***
class yourLens : public Lens
{
    ***
private:
    cr::af::AFEngine m_afEngine;
    ***
}

yourLens.cpp

#include "yourLens.h"
***
/// Class constructor.
cr::lens::yourLens::yourLens()
{
    ***
 	m_afEngine.setParam(cr::af::AFParam::FOCUS_MOVE_THRESHOLD, 0);
    m_afEngine.setParam(cr::af::AFParam::ZOOM_MOVE_THRESHOLD, 0);
    m_afEngine.setParam(cr::af::AFParam::FOCUS_POSITION_ACCURACY, 350);
}
/// Add video frame to calculate focus factor.
void cr::lens::yourLens::addVideoFrame(cr::video::Frame& frame)
{
    m_afEngine.addVideoFrame(frame);
}

void cr::lens::yourLens::lensCommunicationThreadFunction()
{
	***
    int reqPos=0;
    int afAction = 0;
    int afActionPrev = 0;
    ***
    while(true)
    {
        ***
        afAction = m_afEngine.updateData(m_params.zoomPos,
                                        m_params.focusPos,
                                        reqPos);
        if(afAction == 0)
        m_params.afIsActive = false;
        else
        m_params.afIsActive = true;
        switch(afAction)
        {
            case 0:  // nothing to do

            break;
            case 1:  // move to far
            if(afAction!= afActionPrev)
            {
               	/// Place code to move lens FAR with AF_HW_SPEED
            }
            break;
            case 2:  // move to Start or optimal
            if(afAction!= afActionPrev)
            {
				/// Place code to move lens as fast as possible to FOCUS_TO_ABS_POS = reqPos  
            }
            break;
            case 3:  // move to near
            if(afAction!= afActionPrev)
            {
                /// Place code to move lens NEAR with AF_HW_SPEED
            }
            break;
        }
        afActionPrev = afAction;
    }
}

Test application

AFEngineTest is a small OpenCV application that tests the AFEngine itself through its public interface. It does not compute the focus factor on its own - it feeds video frames to the engine and obeys the focus commands the engine returns. Source code: test/main.cpp.

The video file plays the role of a lens with a fixed zoom: a focus position (0 - 65535) is mapped to a frame number (0 - frameCount-1) of the selected video. On start the user chooses the video type (thermal or daylight); the chosen file (thermal.mp4 or daylight.mp4, located in static of the repository) must be in the working directory. All frames are then pre-loaded into memory (std::vector<cv::Mat>) as colour images, so the display loop only picks the corresponding frame from the array - the video is shown at maximum speed (cv::waitKey(1)) in any mode. Each cycle the application displays the colour frame (with overlays) but feeds a grayscale copy of it to the engine via addVideoFrame.

A Focus position track bar (range 0 - 65535) simulates the focus position. While the engine is idle, moving the track bar selects the corresponding frame (track bar value scaled to the frame count) and reports that focus position to the engine. The ROI the engine uses is drawn as a cyan rectangle, and the engine state (focus position, frame, zoom, last AF command, focus factor, and the AFEngine per-frame compute time in microseconds) is shown over the image.

When autofocus runs, the application obeys the engine commands by moving one frame per display cycle: FOCUS FAR steps one frame forward, FOCUS NEAR one frame back, GO TO POS moves one frame towards the requested position. The current zoom position is passed to the engine every cycle (addVideoFrame + updateData). Thus “focusing” means the AFEngine stopping the focus on the sharpest frame. User interface:

afengine_focus_detector_test

Controls:

Key Action
1 Auto-select the AF ROI (ROI_MODE = 1) and run autofocus (the START command).
2 Run autofocus (push AF - START) with the current ROI.
Left mouse button Drag on the video to draw a new ROI rectangle (shown in green while drawing); on release it is applied as the manual ROI (sets ROI_X0/Y0/X1/Y1).
R Start / stop recording the displayed video to afengine_<date>_<time>.mp4 (the file name carries the recording start date and time).
Track bar Set the focus position manually while the engine is idle.
ESC Stop the recording (if active) and exit the application.

The whole behaviour is driven by the AFEngine state machine. With a manual ROI (key 2) on a video whose focus-factor curve has a single clear peak (e.g. thermal.mp4) the autofocus reaches the sharpest frame from any starting position. On a video whose focus-factor curve has several local maxima (e.g. daylight.mp4) the hill-climb may settle on a local peak. Key 1 auto-selects the most textured region of the current frame as the ROI before focusing, so it focuses that region (which is the one already near focus at the start).

Video recording. Pressing R starts recording with cv::VideoWriter (MPEG-4, the source video frame rate) to a file named afengine_<date>_<time>.mp4, where the date and time are taken at the moment recording starts. Pressing R again, or ESC, stops the recording. The recorded frames contain only the source video with the ROI overlay (the active ROI rectangle and the green rectangle drawn while selecting a ROI with the mouse); the text overlays and the REC indicator are drawn afterwards and are not written to the file.


Table of contents