afengine_web_logo

AFEngine C++ library

v2.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 doing 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 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.

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.

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 library.
    FocusDetector.cpp ----- C++ implementation file.
tests --------------------- Folder with test applications.
    CMakeLists.txt -------- CMake file to includes test applications.
    FocusDetectorTest ----- Focus detector test application.
        CMakeLists.txt ---- CMake file of test application.
        main.cpp ---------- Source code file of test application.
        test.png ---------- Test image for test application.

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:
    
    /// Class constructor.
    AFEngine();

    /// Class destructor.
    ~AFEngine();

    /// 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: 2.0.1

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 of 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 up to 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 os 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 is 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 of the parameters 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

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
AF_START Start autofocus. Push focus.
AF_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 horizontal position in pixels.
    /// Auto focus ROI is rectangle.
    /// (read)
    AUTO_ROI_Y0,
    /// Auto focus auto ROI top-left corner vertical 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_AF_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
    /// (video frame width - AUTO_AF_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,
    /// AF threshold. 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|ZOOM moving. Depends on implementation
    /// 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.
    /// Basicaly 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 * AF_FF_DECREASE_THRESHOLD > CURRENT FOCUS_FACTOR
    /// (write/read)
    FF_DECREASE_THRESHOLD
};

Table 3 - Auto focus engine params description.

Parameter Access Description
AF_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).
AF_ROI_X0 read / write Autofocus ROI top-left corner horizontal position, pixels. Initial auto focus ROI position should be set by user in advance according to frame size.
AF_ROI_Y0 read / write Autofocus ROI top-left corner vertical position, pixels. Initial auto focus ROI position should be set by user in advance according to frame size.
AF_ROI_X1 read / write Autofocus ROI bottom-right corner horizontal position, pixels. Initial auto focus ROI position should be set by user in advance according to frame size.
AF_ROI_Y1 read / write Autofocus ROI bottom-right corner vertical position, pixels. Initial auto focus ROI position should be set by user in advance according to frame size.
AF_AUTO_ROI_Y0 read only Autofocus auto ROI top-left corner horizontal position in pixels. If parameter AF_ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AF_AUTO_ROI_X0 read only Autofocus auto ROI top-left corner vertical position in pixels. If parameter AF_ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AF_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 AF_ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AF_AUTO_ROI_HEIGHT read / write Auto ROI height (pixels) for autofocus algorithm. User should set preferable auto focus ROI height. If parameter AF_ROI_MODE == 1 the library will detect “optimal” auto focus ROI position.
AF_AUTO_ROI_BORDER read / write Auto ROI border size, pixels. Border size used to exclude video frame borders for auto ROI detection.
AF_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).
AF_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.
AF_CAF_REFOCUS_TIMEOUT_SEC read / write Timeout for automatic refocus, seconds. 0 - no automatic refocus, 100000 - maximum value.
AF_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 curent position differ from required less than FOCUS_POSITION_ACCURACY
FF_DECREASE_THRESHOLD read / write Focus factor decreasing threshold. Value 0 - 100%. Default value is 80%. When auto focus starts the library detect when to stop and start moving focus in opposite direction if focus factor decreasing more than threshold from initial value before auto focus start.

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)

################################################################################
## CONFIGURATION
## 3rd-party submodules configuration
################################################################################
SET(${PARENT}_SUBMODULE_AF_ENGINE                       ON  CACHE BOOL "" FORCE)
if (${PARENT}_SUBMODULE_AF_ENGINE)
    SET(${PARENT}_AF_ENGINE                             ON  CACHE BOOL "" FORCE)
    SET(${PARENT}_AF_ENGINE_TESTS                       OFF CACHE BOOL "" FORCE)
endif()

################################################################################
## 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);
    m_afEngine.setParam(cr::af::AFParam::FF_DECREASE_THRESHOLD, 80);
}
/// 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 FAR with AF_HW_SPEED
            }
            break;
        }
        afActionPrev = afAction;
    }
}