[libcamera-devel] [PATCH 1/2] ipa: Create a camera sensor helper class

Jean-Michel Hautbois jeanmichel.hautbois at ideasonboard.com
Mon Jun 7 20:15:31 CEST 2021


Hi Naushir,

On 07/06/2021 19:31, Naushir Patuck wrote:
> Hi Jean-Michel,
> 
> 
> 
> On Mon, 7 Jun 2021 at 13:35, Jean-Michel Hautbois
> <jeanmichel.hautbois at ideasonboard.com
> <mailto:jeanmichel.hautbois at ideasonboard.com>> wrote:
> 
>     Setting analogue gain for a specific sensor is not a straghtforward
>     operation, as one needs to know how the gain is calculated for it.
> 
>     This commit introduces a new camera sensor helper in libipa which aims
>     to solve this specific issue.
>     It is based on the MIPI alliance Specification for Camera Command Set
>     and implements, for now, only the analogue "Global gain" mode.
> 
> 
> I know this has probably been discussed in detail internally, but what
> provisions
> do you expect for gain formulas that do not conform to the CCI formula,
> or  those
> that are entirely table based?

It has not been discussed in detail no, and I am sure I have missed a
lot of cases.
For those specific cases, we may, for instance, have a new value in
AnalogueGainCapability enum and let the subclass calculate the proper
value ?
I don't have this case right now in my hands, so it is difficult to know
precisely what is the best way to do so ;-).

> Thanks,
> Naush
> 
> 
>     Is makes it possible to only have 4 parameters to store per sensor, and
>     the gain calculation is then done identically for all of them. This
>     commit gives the gains for imx219 (based on RPi cam_helper), ov5670 and
>     ov5693.
> 
>     Adding a new sensor is pretty straightfoward as one only needs to
>     implement the sub-class for it and register that class to the
>     CameraSensorHelperFactory.
> 
>     Signed-off-by: Jean-Michel Hautbois
>     <jeanmichel.hautbois at ideasonboard.com
>     <mailto:jeanmichel.hautbois at ideasonboard.com>>
>     ---
>      src/ipa/libipa/camera_sensor_helper.cpp | 361 ++++++++++++++++++++++++
>      src/ipa/libipa/camera_sensor_helper.h   |  91 ++++++
>      src/ipa/libipa/meson.build              |   2 +
>      3 files changed, 454 insertions(+)
>      create mode 100644 src/ipa/libipa/camera_sensor_helper.cpp
>      create mode 100644 src/ipa/libipa/camera_sensor_helper.h
> 
>     diff --git a/src/ipa/libipa/camera_sensor_helper.cpp
>     b/src/ipa/libipa/camera_sensor_helper.cpp
>     new file mode 100644
>     index 00000000..2bd82861
>     --- /dev/null
>     +++ b/src/ipa/libipa/camera_sensor_helper.cpp
>     @@ -0,0 +1,361 @@
>     +/* SPDX-License-Identifier: BSD-2-Clause */
>     +/*
>     + * Copyright (C) 2021 Ideas On Board
>     + *
>     + * camera_sensor_helper.cpp - helper class providing camera
>     informations
>     + */
>     +#include "camera_sensor_helper.h"
>     +
>     +#include <map>
>     +
>     +#include "libcamera/internal/log.h"
>     +
>     +/**
>     + * \file camera_sensor_helper.h
>     + * \brief Create helper class for each sensor
>     + *
>     + * Each camera sensor supported by libcamera may need specific
>     informations to
>     + * be sent (analogue gain is sensor dependant for instance).
>     + *
>     + * Every subclass of CameraSensorHelper shall be registered with
>     libipa using
>     + * the REGISTER_CAMERA_SENSOR_HELPER() macro.
>     + */
>     +
>     +namespace libcamera {
>     +
>     +LOG_DEFINE_CATEGORY(CameraSensorHelper)
>     +
>     +namespace ipa {
>     +
>     +/**
>     + * \class CameraSensorHelper
>     + * \brief Create and give helpers for each camera sensor in the
>     pipeline
>     + *
>     + * CameraSensorHelper instances are unique and sensor dependant.
>     + */
>     +
>     +/**
>     + * \brief Construct a CameraSensorHelper instance
>     + * \param[in] name The sensor model name
>     + *
>     + * The CameraSensorHelper instances shall never be constructed
>     manually, but always
>     + * through the CameraSensorHelperFactory::create() method
>     implemented by the
>     + * respective factories.
>     + */
>     +
>     +CameraSensorHelper::CameraSensorHelper(const char *name)
>     +       : name_(name)
>     +{
>     +       analogueGain_ = { GlobalGain, 1, 1, 0, 0 };
>     +}
>     +
>     +CameraSensorHelper::~CameraSensorHelper()
>     +{
>     +}
>     +
>     +/**
>     + * \fn CameraSensorHelper::getGainCode(double gain)
>     + * \brief Get the analogue gain code to pass to V4L2 subdev control
>     + * \param[in] gain The real gain to pass
>     + *
>     + * This function aims to abstract the calculation of the gain
>     letting the IPA
>     + * use the real gain for its estimations.
>     + *
>     + * The parameters come from the MIPI Alliance Camera Specification for
>     + * Camera Command Set (CCS).
>     + */
>     +uint32_t CameraSensorHelper::getGainCode(double gain) const
>     +{
>     +       /* \todo we only support the global gain mode for now */
>     +       if (analogueGain_.type != GlobalGain)
>     +               return UINT32_MAX;
>     +
>     +       if (analogueGain_.m0 == 0)
>     +               return (analogueGain_.c0 - gain * analogueGain_.c1)
>     / (gain * analogueGain_.m1);
>     +       if (analogueGain_.m1 == 0)
>     +               return (gain * analogueGain_.c1 - analogueGain_.c0)
>     / analogueGain_.m0;
>     +
>     +       LOG(CameraSensorHelper, Error) << "For any given image
>     sensor either m0 or m1 shall be zero.";
>     +       return 1;
>     +}
>     +
>     +/**
>     + * \fn CameraSensorHelper::getGain
>     + * \brief Get the real gain from the V4l2 subdev control gain
>     + * \param[in] gainCode The V4l2 subdev control gain
>     + *
>     + * This function aims to abstract the calculation of the gain
>     letting the IPA
>     + * use the real gain for its estimations. It is the counterpart of
>     the function
>     + * CameraSensorHelper::getGainCode.
>     + *
>     + * The parameters come from the MIPI Alliance Camera Specification for
>     + * Camera Command Set (CCS).
>     + */
>     +double CameraSensorHelper::getGain(uint32_t gainCode) const
>     +{
>     +       if (analogueGain_.type != GlobalGain)
>     +               return UINT32_MAX;
>     +
>     +       if (analogueGain_.m0 == 0)
>     +               return analogueGain_.c0 / (analogueGain_.m1 *
>     gainCode + analogueGain_.c1);
>     +       if (analogueGain_.m1 == 0)
>     +               return (analogueGain_.m0 * gainCode +
>     analogueGain_.c0) / analogueGain_.c1;
>     +
>     +       LOG(CameraSensorHelper, Error) << "For any given image
>     sensor either m0 or m1 shall be zero.";
>     +       return 1.0;
>     +}
>     +
>     +/**
>     + * \fn CameraSensorHelper::name()
>     + * \brief Retrieve the camera sensor helper name
>     + * \return The camera sensor helper name
>     + */
>     +
>     +/**
>     + * \enum CameraSensorHelper::AnalogueGainCapability
>     + * \brief Specify the Gain mode supported by the sensor
>     + *
>     + * Describes the image sensor analog Gain capabilities.
>     + * Two modes are possible, depending on the sensor: Global and
>     Alternate.
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::GlobalGain
>     + * \brief Sensor supports Global gain
>     + *
>     + * The relationship between the integer Gain parameter and the
>     resulting Gain
>     + * multiplier is given by the following equation:
>     + *
>     + * \f$\frac{m0x+c0}{m1x+c1}\f$
>     + *
>     + * Where 'x' is the gain control parameter, and m0, m1, c0 and c1 are
>     + * image-sensor-specific constants exposed by the sensor.
>     + * These constants are static parameters, and for any given image
>     sensor either
>     + * m0 or m1 shall be zero.
>     + *
>     + * The full Gain equation therefore reduces to either:
>     + *
>     + * \f$\frac{c0}{m1x+c1}\f$ or \f$\frac{m0x+c0}{c1}\f$
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::AlternateGlobalGain
>     + * \brief Sensor supports Analogue Global gain (introduced in CCS v1.1)
>     + *
>     + * Starting with CCS v1.1, Alternate Global Analog Gain is also
>     available.
>     + * If the image sensor supports it, then the global analog Gain can
>     be controlled
>     + * by linear and exponential gain formula:
>     + *
>     + * \f$gain = analogLinearGainGlobal *
>     2^{analogExponentialGainGlobal} \f$
>     + * \todo not implemented in libipa
>     + */
>     +
>     +/**
>     + * \struct CameraSensorHelper::analogueGainConstants
>     + * \brief Analogue gain constants used for gain calculation
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::analogueGainConstants::type
>     + * \brief Analogue gain coding type
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::analogueGainConstants::m0
>     + * \brief Constant used in the analog Gain control coding/decoding.
>     + *
>     + * Note: either m0 or m1 shall be zero.
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::analogueGainConstants::c0
>     + * \brief Constant used in the analog Gain control coding/decoding.
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::analogueGainConstants::m1
>     + * \brief Constant used in the analog Gain control coding/decoding.
>     + *
>     + * Note: either m0 or m1 shall be zero.
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::analogueGainConstants::c1
>     + * \brief Constant used in the analog Gain control coding/decoding.
>     + */
>     +
>     +/**
>     + * \var CameraSensorHelper::analogueGain_
>     + * \brief The analogue gain parameters used for calculation
>     + *
>     + * The analogue gain is calculated through a formula, and its
>     parameters are
>     + * sensor specific. Use this variable to store the values at init time.
>     + *
>     + */
>     +
>     +/**
>     + * \class CameraSensorHelperFactory
>     + * \brief Registration of CameraSensorHelperFactory classes and
>     creation of instances
>     + *
>     + * To facilitate discovery and instantiation of CameraSensorHelper
>     classes, the
>     + * CameraSensorHelperFactory class maintains a registry of camera
>     sensor helper
>     + * classes. Each CameraSensorHelper subclass shall register itself
>     using the
>     + * REGISTER_CAMERA_SENSOR_HELPER() macro, which will create a
>     corresponding
>     + * instance of a CameraSensorHelperFactory subclass and register it
>     with the
>     + * static list of factories.
>     + */
>     +
>     +/**
>     + * \brief Construct a camera sensor helper factory
>     + * \param[in] name Name of the camera sensor helper class
>     + *
>     + * Creating an instance of the factory registers it with the global
>     list of
>     + * factories, accessible through the factories() function.
>     + *
>     + * The factory \a name is used for debug purpose and shall be unique.
>     + */
>     +
>     +CameraSensorHelperFactory::CameraSensorHelperFactory(const char *name)
>     +       : name_(name)
>     +{
>     +       registerType(this);
>     +}
>     +
>     +/**
>     + * \brief Create an instance of the CameraSensorHelper
>     corresponding to the factory
>     + *
>     + * \return A unique pointer to a new instance of the
>     CameraSensorHelper subclass
>     + * corresponding to the factory
>     + */
>     +std::unique_ptr<CameraSensorHelper> CameraSensorHelperFactory::create()
>     +{
>     +       CameraSensorHelper *handler = createInstance();
>     +       return std::unique_ptr<CameraSensorHelper>(handler);
>     +}
>     +
>     +/**
>     + * \fn CameraSensorHelperFactory::name()
>     + * \brief Retrieve the factory name
>     + * \return The factory name
>     + */
>     +
>     +/**
>     + * \brief Add a camera sensor helper class to the registry
>     + * \param[in] factory Factory to use to construct the camera sensor
>     helper
>     + *
>     + * The caller is responsible to guarantee the uniqueness of the
>     camera sensor helper
>     + * name.
>     + */
>     +void
>     CameraSensorHelperFactory::registerType(CameraSensorHelperFactory
>     *factory)
>     +{
>     +       std::vector<CameraSensorHelperFactory *> &factories =
>     CameraSensorHelperFactory::factories();
>     +
>     +       factories.push_back(factory);
>     +}
>     +
>     +/**
>     + * \brief Retrieve the list of all camera sensor helper factories
>     + *
>     + * The static factories map is defined inside the function to
>     ensures it gets
>     + * initialized on first use, without any dependency on link order.
>     + *
>     + * \return The list of camera sensor helper factories
>     + */
>     +std::vector<CameraSensorHelperFactory *>
>     &CameraSensorHelperFactory::factories()
>     +{
>     +       static std::vector<CameraSensorHelperFactory *> factories;
>     +       return factories;
>     +}
>     +
>     +/**
>     + * \fn CameraSensorHelperFactory::createInstance()
>     + * \brief Create an instance of the CameraSensorHelper
>     corresponding to the factory
>     + *
>     + * This virtual function is implemented by the
>     REGISTER_CAMERA_SENSOR_HELPER()
>     + * macro. It creates a camera sensor helper instance associated
>     with the camera
>     + * sensor model.
>     + *
>     + * \return A pointer to a newly constructed instance of the
>     CameraSensorHelper
>     + * subclass corresponding to the factory
>     + */
>     +
>     +/**
>     + * \def REGISTER_CAMERA_SENSOR_HELPER
>     + * \brief Register a camera sensor helper with the camera sensor
>     helper factory
>     + * \param[in] name Sensor model name used to register the class
>     + * \param[in] handler Class name of CameraSensorHelper derived
>     class to register
>     + *
>     + * Register a CameraSensorHelper subclass with the factory and make
>     it available to
>     + * try and match devices.
>     + */
>     +
>     +/**
>     + * \class CameraSensorHelperImx219
>     + * \brief Create and give helpers for the imx219 sensor
>     + */
>     +
>     +/**
>     + * \fn CameraSensorHelperImx219::CameraSensorHelperImx219
>     + * \brief Construct a CameraSensorHelperImx219 instance for imx219
>     + * \param[in] name The sensor model name
>     + */
>     +class CameraSensorHelperImx219 : public CameraSensorHelper
>     +{
>     +public:
>     +       CameraSensorHelperImx219(const char *name);
>     +};
>     +REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219)
>     +CameraSensorHelperImx219::CameraSensorHelperImx219(const char *name)
>     +       : CameraSensorHelper(name)
>     +{
>     +       analogueGain_ = { GlobalGain, 0, -1, 256, 256 };
>     +}
>     +
>     +/**
>     + * \class CameraSensorHelperOv5670
>     + * \brief Create and give helpers for the ov5670 sensor
>     + */
>     +
>     +/**
>     + * \fn CameraSensorHelperOv5670::CameraSensorHelperOv5670
>     + * \brief Construct a CameraSensorHelperOv5670 instance for ov5670
>     + * \param[in] name The sensor model name
>     + */
>     +class CameraSensorHelperOv5670 : public CameraSensorHelper
>     +{
>     +public:
>     +       CameraSensorHelperOv5670(const char *name);
>     +};
>     +REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670)
>     +CameraSensorHelperOv5670::CameraSensorHelperOv5670(const char *name)
>     +       : CameraSensorHelper(name)
>     +{
>     +       analogueGain_ = { GlobalGain, 1, 0, 0, 256 };
>     +}
>     +
>     +/**
>     + * \class CameraSensorHelperOv5693
>     + * \brief Create and give helpers for the ov5693 sensor
>     + */
>     +
>     +/**
>     + * \fn CameraSensorHelperOv5693::CameraSensorHelperOv5693
>     + * \brief Construct a CameraSensorHelperOv5693 instance for ov5693
>     + * \param[in] name The sensor model name
>     + */
>     +class CameraSensorHelperOv5693 : public CameraSensorHelper
>     +{
>     +public:
>     +       CameraSensorHelperOv5693(const char *name);
>     +};
>     +REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693)
>     +CameraSensorHelperOv5693::CameraSensorHelperOv5693(const char *name)
>     +       : CameraSensorHelper(name)
>     +{
>     +       analogueGain_ = { GlobalGain, 1, 0, 0, 16 };
>     +}
>     +
>     +} /* namespace ipa */
>     +
>     +} /* namespace libcamera */
>     +
>     diff --git a/src/ipa/libipa/camera_sensor_helper.h
>     b/src/ipa/libipa/camera_sensor_helper.h
>     new file mode 100644
>     index 00000000..63031902
>     --- /dev/null
>     +++ b/src/ipa/libipa/camera_sensor_helper.h
>     @@ -0,0 +1,91 @@
>     +/* SPDX-License-Identifier: BSD-2-Clause */
>     +/*
>     + * Copyright (C) 2021 Ideas On Board
>     + *
>     + * camera_sensor_helper.h - helper class providing camera informations
>     + */
>     +#ifndef __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__
>     +#define __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__
>     +
>     +#include <stdint.h>
>     +
>     +#include <string>
>     +
>     +#include <libcamera/class.h>
>     +#include <libcamera/object.h>
>     +
>     +namespace libcamera {
>     +
>     +namespace ipa {
>     +
>     +class CameraSensorHelper;
>     +
>     +class CameraSensorHelper : public Object
>     +{
>     +public:
>     +       CameraSensorHelper(const char *name);
>     +       virtual ~CameraSensorHelper();
>     +
>     +       const std::string &name() const { return name_; }
>     +       uint32_t getGainCode(double gain) const;
>     +       double getGain(uint32_t gainCode) const;
>     +
>     +protected:
>     +       enum AnalogueGainCapability : uint16_t {
>     +               GlobalGain = 0,
>     +               AlternateGlobalGain = 2,
>     +       };
>     +
>     +       struct analogueGainConstants {
>     +               uint16_t type;
>     +               int16_t m0;
>     +               int16_t c0;
>     +               int16_t m1;
>     +               int16_t c1;
>     +       };
>     +       analogueGainConstants analogueGain_;
>     +
>     +private:
>     +       std::string name_;
>     +       friend class CameraSensorHelperFactory;
>     +};
>     +
>     +class CameraSensorHelperFactory
>     +{
>     +public:
>     +       CameraSensorHelperFactory(const char *name);
>     +       virtual ~CameraSensorHelperFactory() = default;
>     +
>     +       std::unique_ptr<CameraSensorHelper> create();
>     +
>     +       const std::string &name() const { return name_; }
>     +
>     +       static void registerType(CameraSensorHelperFactory *factory);
>     +       static std::vector<CameraSensorHelperFactory *> &factories();
>     +
>     +private:
>     +       virtual CameraSensorHelper *createInstance() = 0;
>     +
>     +       std::string name_;
>     +};
>     +
>     +#define REGISTER_CAMERA_SENSOR_HELPER(name, handler)               
>             \
>     +       class handler##Factory final : public
>     CameraSensorHelperFactory     \
>     +       {                                                           
>            \
>     +       public:                                                     
>            \
>     +               handler##Factory() :
>     CameraSensorHelperFactory(#handler) {} \
>     +                                                                   
>             \
>     +       private:                                                   
>             \
>     +               CameraSensorHelper *createInstance()               
>             \
>     +               {                                                   
>            \
>     +                       return new handler(name);                   
>            \
>     +               }                                                   
>            \
>     +       };                                                         
>             \
>     +       static handler##Factory global_##handler##Factory;
>     +
>     +} /* namespace ipa */
>     +
>     +} /* namespace libcamera */
>     +
>     +#endif /* __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__ */
>     +
>     diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
>     index 038fc490..dc90542c 100644
>     --- a/src/ipa/libipa/meson.build
>     +++ b/src/ipa/libipa/meson.build
>     @@ -2,11 +2,13 @@
> 
>      libipa_headers = files([
>          'algorithm.h',
>     +    'camera_sensor_helper.h',
>          'histogram.h'
>      ])
> 
>      libipa_sources = files([
>          'algorithm.cpp',
>     +    'camera_sensor_helper.cpp',
>          'histogram.cpp'
>      ])
> 
>     -- 
>     2.30.2
> 


More information about the libcamera-devel mailing list