API Reference
=============

The ``epctofcam`` library provides both a C++ and a Python API, giving you full flexibility
to integrate EPC670 ToF camera support into your application.


.. image:: ../_static/diagrams/epc_architecture.drawio.png
   :alt: epctofcam library overview
   :align: center

- The **Python API** (``epc_tofcam_native``) is a pybind11 binding of the C++ API and returns
  image data as ``numpy`` arrays, making it ideal for rapid prototyping and data analysis.
- The **C++ API** offers direct, low-overhead access to the camera and is suitable for
  performance-critical applications and embedded systems.

.. toctree::
   :maxdepth: 1

   python_api
   cpp_api

Camera State Machine
--------------------

The library follows a simple three-state lifecycle: a camera starts **Disconnected**, moves to
**Idle** after ``open()``, and enters **Streaming** via ``startStream()``. Controls and frame
captures are available in both **Idle** and **Streaming** states.

.. image:: ../_static/diagrams/libStateMachine.drawio.svg
   :alt: TOFCam library state machine
   :align: center

Acquisition Modes
-----------------

The camera supports multiple acquisition modes that determine how frames are captured and processed.  
The mode is set via the ``ACQUISITION_MODE`` control and affects the type of frames returned by the call to ``captureFrame()``.  

+---------------------+----------------------------------------------+
| Mode                | Frame content returned by ``captureFrame()`` |
+=====================+==============================================+
| ``DIST_AMP``        | DISTANCE, AMPLITUDE, 4x DCS, PHASE           |
+---------------------+----------------------------------------------+
| ``DIST_AMP_HDR``    | DISTANCE, AMPLITUDE, 12x DCS, PHASE          |
+---------------------+----------------------------------------------+
| ``DCS4``            | 4x DCS                                       |
+---------------------+----------------------------------------------+
| ``GRAYSCALE``       | GRAYSCALE                                    |
+---------------------+----------------------------------------------+

See also:  

- ``Acquisition modes``: :cpp:enum:`epc::AcquisitionMode`, :py:class:`epc_tofcam_native.AcquisitionMode`.
- ``Frame types``: :cpp:enum:`epc::FrameType`, :py:class:`epc_tofcam_native.FrameType`

HDR Rolling Mode
~~~~~~~~~~~~~~~~

In standard ``DIST_AMP_HDR`` mode, the camera waits until three frames with different
integration times have been captured before combining them into a single HDR distance/amplitude
image, which limits the output framerate to one-third of the raw acquisition rate.

Rolling HDR mode removes this bottleneck: a new HDR image is computed after **every** acquired
raw frame by combining it with the two most recently captured frames (each at a different
integration time). This produces an HDR result at the full raw acquisition rate, at the cost
of the three input frames no longer being perfectly synchronised in time, and at the expense
of higher memory and CPU usage since the pipeline must retain and process more frames
concurrently.

Enable rolling HDR mode via the ``ENABLE_HDR_ROLLING_MODE`` control:

.. code-block:: cpp
   :caption: C++

   cam.setControl(epc::ControlID::ENABLE_HDR_ROLLING_MODE, 1);

.. code-block:: python
   :caption: Python

   cam.set_control(epc_tofcam_native.ControlID.ENABLE_HDR_ROLLING_MODE, 1)

DCS Rolling Mode
~~~~~~~~~~~~~~~~

In standard ``DIST_AMP`` mode, the camera captures four DCS frames per distance/amplitude frame. 
In rolling DCS mode, a new distance/amplitude frame is computed after **every** acquired DCS frame by combining it 
with the three most recently captured DCS frames. 
This produces a new distance/amplitude result at the full raw acquisition rate, 
at the cost of the four input frames no longer being perfectly synchronised in time, 
and at the expense of higher memory and CPU usage since the pipeline must retain and process more frames concurrently.
Enable DCS rolling mode via the ``ENABLE_DCS_ROLLING_MODE`` control:

.. code-block:: cpp
   :caption: C++

   cam.setControl(epc::ControlID::ENABLE_DCS_ROLLING_MODE, 1);

.. code-block:: python
   :caption: Python
   
   cam.set_control(epc_tofcam_native.ControlID.ENABLE_DCS_ROLLING_MODE, 1)



Image Filters
-------------

In the ``DIST_AMP`` and ``DIST_AMP_HDR`` modes, optional image filters can be applied to the
distance image. All filters are disabled by default. Once enabled, the filters are applied in
a fixed order that cannot be changed. The order is as follows:

#. Median Filter
#. Average Filter
#. Temporal Filter
#. Kalman Filter
#. Edge Filter
#. Interference Filter
#. Minimum Amplitude  Filter

The filters are discussed in detail in the following sections.

Median Filter
~~~~~~~~~~~~~

3x3 sliding window median filter.
At the image boundaries, the pixels on the edge of the image are used to fill the missing pixels of the window.

.. seealso::
   :cpp:enumerator:`epc::ControlID::MEDIAN_FILTER_ENABLE`

Average Filter
~~~~~~~~~~~~~~

3x3 sliding window average (aka. box blur) filter. 
At the image boundaries, the pixels on the edge of the image are used to fill the missing pixels of the window.

.. seealso::
   :cpp:enumerator:`epc::ControlID::AVERAGE_FILTER_ENABLE`

Temporal Filter
~~~~~~~~~~~~~~~

Per-pixel exponential moving average (EMA) filter with jump detection.
The filter strength is determined by the value of alpha, representing the weight of the input frame.
The moving average is weighted as `(1-alpha)`. When `|input - average|>threshold`, the average for this pixel is dropped
and reset to the current input value.

.. seealso::
   :cpp:enumerator:`epc::ControlID::TEMPORAL_FILTER_ENABLE`
   :cpp:enumerator:`epc::ControlID::TEMPORAL_FILTER_ALPHA`
   :cpp:enumerator:`epc::ControlID::TEMPORAL_FILTER_THRESHOLD`

Kalman Filter
~~~~~~~~~~~~~

Per-pixel 1D Kalman filter with strong tracking.
The filter estimates the measurement noise directly from the pixel amplitude.
The process noise variance can be set explicitly for better convergence in very static or very dynamic scenes.
The filter implements strong tracking by boosting the uncertainty for pixels with high innovation.
Additionally, when the uncertainty (standard deviation `σ`) is larger than the threshold for a pixel, the filter flags the pixel with the error code for low amplitude. 
This way, the Kalman filter can be used to get reliable data even without the `Min Amplitude`
filter, making it especially useful for scenes with low illumination.

.. seealso::
   :cpp:enumerator:`epc::ControlID::KALMAN_FILTER_ENABLE`
   :cpp:enumerator:`epc::ControlID::KALMAN_FILTER_PROCESS_NOISE`
   :cpp:enumerator:`epc::ControlID::KALMAN_FILTER_THRESHOLD`

Edge Filter
~~~~~~~~~~~

Filter that masks pixels that lie on a depth edge.
Pixels on such depth edges often have a distance value that is the average of the foreground and background
distance, resulting in "floating" distance pixels.
This filter flags pixels with the corresponding error code when their vertical or horizontal second order
central difference exceeds the specified threshold.

.. seealso::
   :cpp:enumerator:`epc::ControlID::EDGE_FILTER_ENABLE`
   :cpp:enumerator:`epc::ControlID::EDGE_FILTER_THRESHOLD`

Interference Filter
~~~~~~~~~~~~~~~~~~~~

Filter that masks pixels where interference from other illumination sources is detected.
The filter is based on the principle that the sum of opposing DCS frames is zero for ideal illumination.
When the sum of opposing DCS values exceeds the specified threshold (e.g. caused by a second camera), the
filter flags the pixel with the corresponding error code.
In latching mode, the pixel value from the previous frame is returned instead of an error.

.. seealso::
   :cpp:enumerator:`epc::ControlID::INTERFERENCE_DETECTION_ENABLE`
   :cpp:enumerator:`epc::ControlID::INTERFERENCE_DETECTION_THRESHOLD`
   :cpp:enumerator:`epc::ControlID::INTERFERENCE_ENABLE_LATCHING`

Min Amplitude Filter
~~~~~~~~~~~~~~~~~~~~

Filter that flags pixels with weak illumination with the corresponding error code.

.. seealso::
   :cpp:enumerator:`epc::ControlID::MIN_AMPLITUDE`
