[libcamera-devel] [PATCH v1 11/14] ipa: raspberrypi: First version of autofocus algorithm using PDAF

Nick Hollinghurst nick.hollinghurst at raspberrypi.com
Fri Jan 20 17:50:41 CET 2023


Hi Kieran,

On Fri, 20 Jan 2023 at 16:39, Kieran Bingham
<kieran.bingham at ideasonboard.com> wrote:
>
> Hi Nick, / Naush,
>
> Quoting Nick Hollinghurst via libcamera-devel (2023-01-19 13:07:44)
> > Hi all,
> >
> > This patch needs a tweak to handle the case where setWindows is called
> > before configure -- see Af::Af(Controller *controller) constructor
> > below.
> >
> > On Thu, 19 Jan 2023 at 10:46, Naushir Patuck <naush at raspberrypi.com> wrote:
> > >
> > > From: Nick Hollinghurst <nick.hollinghurst at raspberrypi.com>
> > >
> > > Provide the first version of the Raspberry Pi autofocus algorithm. This
> > > implementation uses a hybrid of contrast detect autofocus (CDAF) and phase
> > > detect autofocus (PDAF) statistics. PDAF is always preferred over CDAF due to
> > > having less "hunting" behavior.
> > >
> > > Signed-off-by: Nick Hollinghurst <nick.hollinghurst at raspberrypi.com>
> > > Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
> > > Reviewed-by: Naushir Patuck <naush at raspberrypi.com>
> > > Reviewed-by: David Plowman <david.plowman at raspberrypi.com>
> > > ---
> > >  src/ipa/raspberrypi/controller/rpi/af.cpp | 755 ++++++++++++++++++++++
> > >  src/ipa/raspberrypi/controller/rpi/af.h   | 153 +++++
> > >  src/ipa/raspberrypi/meson.build           |   1 +
> > >  3 files changed, 909 insertions(+)
> > >  create mode 100644 src/ipa/raspberrypi/controller/rpi/af.cpp
> > >  create mode 100644 src/ipa/raspberrypi/controller/rpi/af.h
> > >
> > > diff --git a/src/ipa/raspberrypi/controller/rpi/af.cpp b/src/ipa/raspberrypi/controller/rpi/af.cpp
> > > new file mode 100644
> > > index 000000000000..7e2e8961085a
> > > --- /dev/null
> > > +++ b/src/ipa/raspberrypi/controller/rpi/af.cpp
> > > @@ -0,0 +1,755 @@
> > > +/* SPDX-License-Identifier: BSD-2-Clause */
> > > +/*
> > > + * Copyright (C) 2022-2023, Raspberry Pi Ltd
> > > + *
> > > + * af.cpp - Autofocus control algorithm
> > > + */
> > > +
> > > +#include "af.h"
> > > +
> > > +#include <iomanip>
> > > +#include <math.h>
> > > +#include <stdlib.h>
> > > +
> > > +#include <libcamera/base/log.h>
> > > +
> > > +#include <libcamera/control_ids.h>
> > > +
> > > +using namespace RPiController;
> > > +using namespace libcamera;
> > > +
> > > +LOG_DEFINE_CATEGORY(RPiAf)
> > > +
> > > +#define NAME "rpi.af"
> > > +
> > > +/*
> > > + * Default values for parameters. All may be overridden in the tuning file.
> > > + * Many of these values are sensor- or module-dependent; the defaults here
> > > + * assume IMX708 in a Raspberry Pi V3 camera with the standard lens.
> > > + *
> > > + * Here all focus values are in dioptres (1/m). They are converted to hardware
> > > + * units when written to status.lensSetting or returned from setLensPosition().
> > > + *
> > > + * Gain and delay values are relative to the update rate, since much (not all)
> > > + * of the delay is in the sensor and (for CDAF) ISP, not the lens mechanism;
> > > + * but note that algorithms are updated at no more than 30 Hz.
> > > + */
> > > +
> > > +Af::RangeDependentParams::RangeDependentParams()
> > > +       : focusMin(0.0),
> > > +         focusMax(12.0),
> > > +         focusDefault(1.0)
> > > +{
> > > +}
> > > +
> > > +Af::SpeedDependentParams::SpeedDependentParams()
> > > +       : stepCoarse(1.0),
> > > +         stepFine(0.25),
> > > +         contrastRatio(0.75),
> > > +         pdafGain(-0.02),
> > > +         pdafSquelch(0.125),
> > > +         maxSlew(2.0),
> > > +         pdafFrames(20),
> > > +         dropoutFrames(6),
> > > +         stepFrames(4)
> > > +{
> > > +}
> > > +
> > > +Af::CfgParams::CfgParams()
> > > +       : confEpsilon(8),
> > > +         confThresh(16),
> > > +         confClip(512),
> > > +         skipFrames(5),
> > > +         map()
> > > +{
> > > +}
> > > +
> > > +template<typename T>
> > > +static void readNumber(T &dest, const libcamera::YamlObject &params, char const *name)
> > > +{
> > > +       auto value = params[name].get<T>();
> > > +       if (value)
> > > +               dest = *value;
> > > +       else
> > > +               LOG(RPiAf, Warning) << "Missing parameter \"" << name << "\"";
> > > +}
> > > +
> > > +void Af::RangeDependentParams::read(const libcamera::YamlObject &params)
> > > +{
> > > +
> > > +       readNumber<double>(focusMin, params, "min");
> > > +       readNumber<double>(focusMax, params, "max");
> > > +       readNumber<double>(focusDefault, params, "default");
> > > +}
> > > +
> > > +void Af::SpeedDependentParams::read(const libcamera::YamlObject &params)
> > > +{
> > > +       readNumber<double>(stepCoarse, params, "step_coarse");
> > > +       readNumber<double>(stepFine, params, "step_fine");
> > > +       readNumber<double>(contrastRatio, params, "contrast_ratio");
> > > +       readNumber<double>(pdafGain, params, "pdaf_gain");
> > > +       readNumber<double>(pdafSquelch, params, "pdaf_squelch");
> > > +       readNumber<double>(maxSlew, params, "max_slew");
> > > +       readNumber<uint32_t>(pdafFrames, params, "pdaf_frames");
> > > +       readNumber<uint32_t>(dropoutFrames, params, "dropout_frames");
> > > +       readNumber<uint32_t>(stepFrames, params, "step_frames");
> > > +}
> > > +
> > > +int Af::CfgParams::read(const libcamera::YamlObject &params)
> > > +{
> > > +       if (params.contains("ranges")) {
> > > +               auto &rr = params["ranges"];
> > > +
> > > +               if (rr.contains("normal"))
> > > +                       ranges[AfRangeNormal].read(rr["normal"]);
> > > +               else
> > > +                       LOG(RPiAf, Warning) << "Missing range \"normal\"";
> > > +
> > > +               ranges[AfRangeMacro] = ranges[AfRangeNormal];
> > > +               if (rr.contains("macro"))
> > > +                       ranges[AfRangeMacro].read(rr["macro"]);
> > > +
> > > +               ranges[AfRangeFull].focusMin = std::min(ranges[AfRangeNormal].focusMin,
> > > +                                                       ranges[AfRangeMacro].focusMin);
> > > +               ranges[AfRangeFull].focusMax = std::max(ranges[AfRangeNormal].focusMax,
> > > +                                                       ranges[AfRangeMacro].focusMax);
> > > +               ranges[AfRangeFull].focusDefault = ranges[AfRangeNormal].focusDefault;
> > > +               if (rr.contains("full"))
> > > +                       ranges[AfRangeFull].read(rr["full"]);
> > > +       } else
> > > +               LOG(RPiAf, Warning) << "No ranges defined";
> > > +
> > > +       if (params.contains("speeds")) {
> > > +               auto &ss = params["speeds"];
> > > +
> > > +               if (ss.contains("normal"))
> > > +                       speeds[AfSpeedNormal].read(ss["normal"]);
> > > +               else
> > > +                       LOG(RPiAf, Warning) << "Missing speed \"normal\"";
> > > +
> > > +               speeds[AfSpeedFast] = speeds[AfSpeedNormal];
> > > +               if (ss.contains("fast"))
> > > +                       speeds[AfSpeedFast].read(ss["fast"]);
> > > +       } else
> > > +               LOG(RPiAf, Warning) << "No speeds defined";
> > > +
> > > +       readNumber<uint32_t>(confEpsilon, params, "conf_epsilon");
> > > +       readNumber<uint32_t>(confThresh, params, "conf_thresh");
> > > +       readNumber<uint32_t>(confClip, params, "conf_clip");
> > > +       readNumber<uint32_t>(skipFrames, params, "skip_frames");
> > > +
> > > +       if (params.contains("map"))
> > > +               map.read(params["map"]);
> > > +       else
> > > +               LOG(RPiAf, Warning) << "No map defined";
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +void Af::CfgParams::initialise()
> > > +{
> > > +       if (map.empty()) {
> > > +               /* Default mapping from dioptres to hardware setting */
> > > +               static constexpr double DefaultMapX0 = 0.0;
> > > +               static constexpr double DefaultMapY0 = 445.0;
> > > +               static constexpr double DefaultMapX1 = 15.0;
> > > +               static constexpr double DefaultMapY1 = 925.0;
> > > +
> > > +               map.append(DefaultMapX0, DefaultMapY0);
> > > +               map.append(DefaultMapX1, DefaultMapY1);
> > > +
> > > +               LOG(RPiAf, Warning) << "af.map is not defined, ";
> > > +       }
> > > +}
> > > +
> > > +/* Af Algorithm class */
> > > +
> > > +Af::Af(Controller *controller)
> > > +       : AfAlgorithm(controller),
> > > +         cfg_(),
> > > +         range_(AfRangeNormal),
> > > +         speed_(AfSpeedNormal),
> > > +         mode_(AfAlgorithm::AfModeManual),
> > > +         pauseFlag_(false),
> > > +         sensorSize_{ 0, 0 },
> >
> > sensorSize_ needs to be set before setWindows() is called. For this
> > version it suffices to initialize it to
> >
> >         sensorSize_ { 4608, 2502 },
> >
> > a more general fix may follow later.
>
> Can you send a tested update to this patch please? No need to send the
> whole series again.
>
> If that can include the fix I highlighted, (Remove pdafSeen_) I believe
> I can merge this whole series.
>
> --
> Kieran

I have done a bit of re-work to fix this "properly" and am testing it
now. I'll also remove pdafSeen_.
The re-work touches "af.cpp", "af.h" only so it affects only this patch.

Regards,

 Nick


<snipped remainder>


More information about the libcamera-devel mailing list