mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-23 16:45:07 +03:00
ipa: rpi: controller: Use libipa's Pwl class
To reduce code duplication, use the Pwl class from libipa. This also removes the Pwl class from the Raspberry Pi IPA. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> Acked-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
parent
95fa5c40ba
commit
9fcc0029ec
22 changed files with 106 additions and 494 deletions
|
@ -6,8 +6,6 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "pwl.h"
|
||||
|
||||
struct CacStatus {
|
||||
std::vector<double> lutRx;
|
||||
std::vector<double> lutRy;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "pwl.h"
|
||||
#include "libipa/pwl.h"
|
||||
|
||||
/*
|
||||
* The "contrast" algorithm creates a gamma curve, optionally doing a little bit
|
||||
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
struct ContrastStatus {
|
||||
RPiController::Pwl gammaCurve;
|
||||
libcamera::ipa::Pwl gammaCurve;
|
||||
double brightness;
|
||||
double contrast;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@ rpi_ipa_controller_sources = files([
|
|||
'controller.cpp',
|
||||
'device_status.cpp',
|
||||
'histogram.cpp',
|
||||
'pwl.cpp',
|
||||
'rpi/af.cpp',
|
||||
'rpi/agc.cpp',
|
||||
'rpi/agc_channel.cpp',
|
||||
|
@ -32,4 +31,5 @@ rpi_ipa_controller_deps = [
|
|||
]
|
||||
|
||||
rpi_ipa_controller_lib = static_library('rpi_ipa_controller', rpi_ipa_controller_sources,
|
||||
include_directories : libipa_includes,
|
||||
dependencies : rpi_ipa_controller_deps)
|
||||
|
|
|
@ -1,269 +0,0 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* Copyright (C) 2019, Raspberry Pi Ltd
|
||||
*
|
||||
* piecewise linear functions
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "pwl.h"
|
||||
|
||||
using namespace RPiController;
|
||||
|
||||
int Pwl::read(const libcamera::YamlObject ¶ms)
|
||||
{
|
||||
if (!params.size() || params.size() % 2)
|
||||
return -EINVAL;
|
||||
|
||||
const auto &list = params.asList();
|
||||
|
||||
for (auto it = list.begin(); it != list.end(); it++) {
|
||||
auto x = it->get<double>();
|
||||
if (!x)
|
||||
return -EINVAL;
|
||||
if (it != list.begin() && *x <= points_.back().x)
|
||||
return -EINVAL;
|
||||
|
||||
auto y = (++it)->get<double>();
|
||||
if (!y)
|
||||
return -EINVAL;
|
||||
|
||||
points_.push_back(Point(*x, *y));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Pwl::append(double x, double y, const double eps)
|
||||
{
|
||||
if (points_.empty() || points_.back().x + eps < x)
|
||||
points_.push_back(Point(x, y));
|
||||
}
|
||||
|
||||
void Pwl::prepend(double x, double y, const double eps)
|
||||
{
|
||||
if (points_.empty() || points_.front().x - eps > x)
|
||||
points_.insert(points_.begin(), Point(x, y));
|
||||
}
|
||||
|
||||
Pwl::Interval Pwl::domain() const
|
||||
{
|
||||
return Interval(points_[0].x, points_[points_.size() - 1].x);
|
||||
}
|
||||
|
||||
Pwl::Interval Pwl::range() const
|
||||
{
|
||||
double lo = points_[0].y, hi = lo;
|
||||
for (auto &p : points_)
|
||||
lo = std::min(lo, p.y), hi = std::max(hi, p.y);
|
||||
return Interval(lo, hi);
|
||||
}
|
||||
|
||||
bool Pwl::empty() const
|
||||
{
|
||||
return points_.empty();
|
||||
}
|
||||
|
||||
double Pwl::eval(double x, int *spanPtr, bool updateSpan) const
|
||||
{
|
||||
int span = findSpan(x, spanPtr && *spanPtr != -1 ? *spanPtr : points_.size() / 2 - 1);
|
||||
if (spanPtr && updateSpan)
|
||||
*spanPtr = span;
|
||||
return points_[span].y +
|
||||
(x - points_[span].x) * (points_[span + 1].y - points_[span].y) /
|
||||
(points_[span + 1].x - points_[span].x);
|
||||
}
|
||||
|
||||
int Pwl::findSpan(double x, int span) const
|
||||
{
|
||||
/*
|
||||
* Pwls are generally small, so linear search may well be faster than
|
||||
* binary, though could review this if large PWls start turning up.
|
||||
*/
|
||||
int lastSpan = points_.size() - 2;
|
||||
/*
|
||||
* some algorithms may call us with span pointing directly at the last
|
||||
* control point
|
||||
*/
|
||||
span = std::max(0, std::min(lastSpan, span));
|
||||
while (span < lastSpan && x >= points_[span + 1].x)
|
||||
span++;
|
||||
while (span && x < points_[span].x)
|
||||
span--;
|
||||
return span;
|
||||
}
|
||||
|
||||
Pwl::PerpType Pwl::invert(Point const &xy, Point &perp, int &span,
|
||||
const double eps) const
|
||||
{
|
||||
assert(span >= -1);
|
||||
bool prevOffEnd = false;
|
||||
for (span = span + 1; span < (int)points_.size() - 1; span++) {
|
||||
Point spanVec = points_[span + 1] - points_[span];
|
||||
double t = ((xy - points_[span]) % spanVec) / spanVec.len2();
|
||||
if (t < -eps) /* off the start of this span */
|
||||
{
|
||||
if (span == 0) {
|
||||
perp = points_[span];
|
||||
return PerpType::Start;
|
||||
} else if (prevOffEnd) {
|
||||
perp = points_[span];
|
||||
return PerpType::Vertex;
|
||||
}
|
||||
} else if (t > 1 + eps) /* off the end of this span */
|
||||
{
|
||||
if (span == (int)points_.size() - 2) {
|
||||
perp = points_[span + 1];
|
||||
return PerpType::End;
|
||||
}
|
||||
prevOffEnd = true;
|
||||
} else /* a true perpendicular */
|
||||
{
|
||||
perp = points_[span] + spanVec * t;
|
||||
return PerpType::Perpendicular;
|
||||
}
|
||||
}
|
||||
return PerpType::None;
|
||||
}
|
||||
|
||||
Pwl Pwl::inverse(bool *trueInverse, const double eps) const
|
||||
{
|
||||
bool appended = false, prepended = false, neither = false;
|
||||
Pwl inverse;
|
||||
|
||||
for (Point const &p : points_) {
|
||||
if (inverse.empty())
|
||||
inverse.append(p.y, p.x, eps);
|
||||
else if (std::abs(inverse.points_.back().x - p.y) <= eps ||
|
||||
std::abs(inverse.points_.front().x - p.y) <= eps)
|
||||
/* do nothing */;
|
||||
else if (p.y > inverse.points_.back().x) {
|
||||
inverse.append(p.y, p.x, eps);
|
||||
appended = true;
|
||||
} else if (p.y < inverse.points_.front().x) {
|
||||
inverse.prepend(p.y, p.x, eps);
|
||||
prepended = true;
|
||||
} else
|
||||
neither = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is not a proper inverse if we found ourselves putting points
|
||||
* onto both ends of the inverse, or if there were points that couldn't
|
||||
* go on either.
|
||||
*/
|
||||
if (trueInverse)
|
||||
*trueInverse = !(neither || (appended && prepended));
|
||||
|
||||
return inverse;
|
||||
}
|
||||
|
||||
Pwl Pwl::compose(Pwl const &other, const double eps) const
|
||||
{
|
||||
double thisX = points_[0].x, thisY = points_[0].y;
|
||||
int thisSpan = 0, otherSpan = other.findSpan(thisY, 0);
|
||||
Pwl result({ { thisX, other.eval(thisY, &otherSpan, false) } });
|
||||
while (thisSpan != (int)points_.size() - 1) {
|
||||
double dx = points_[thisSpan + 1].x - points_[thisSpan].x,
|
||||
dy = points_[thisSpan + 1].y - points_[thisSpan].y;
|
||||
if (std::abs(dy) > eps &&
|
||||
otherSpan + 1 < (int)other.points_.size() &&
|
||||
points_[thisSpan + 1].y >=
|
||||
other.points_[otherSpan + 1].x + eps) {
|
||||
/*
|
||||
* next control point in result will be where this
|
||||
* function's y reaches the next span in other
|
||||
*/
|
||||
thisX = points_[thisSpan].x +
|
||||
(other.points_[otherSpan + 1].x -
|
||||
points_[thisSpan].y) *
|
||||
dx / dy;
|
||||
thisY = other.points_[++otherSpan].x;
|
||||
} else if (std::abs(dy) > eps && otherSpan > 0 &&
|
||||
points_[thisSpan + 1].y <=
|
||||
other.points_[otherSpan - 1].x - eps) {
|
||||
/*
|
||||
* next control point in result will be where this
|
||||
* function's y reaches the previous span in other
|
||||
*/
|
||||
thisX = points_[thisSpan].x +
|
||||
(other.points_[otherSpan + 1].x -
|
||||
points_[thisSpan].y) *
|
||||
dx / dy;
|
||||
thisY = other.points_[--otherSpan].x;
|
||||
} else {
|
||||
/* we stay in the same span in other */
|
||||
thisSpan++;
|
||||
thisX = points_[thisSpan].x,
|
||||
thisY = points_[thisSpan].y;
|
||||
}
|
||||
result.append(thisX, other.eval(thisY, &otherSpan, false),
|
||||
eps);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Pwl::map(std::function<void(double x, double y)> f) const
|
||||
{
|
||||
for (auto &pt : points_)
|
||||
f(pt.x, pt.y);
|
||||
}
|
||||
|
||||
void Pwl::map2(Pwl const &pwl0, Pwl const &pwl1,
|
||||
std::function<void(double x, double y0, double y1)> f)
|
||||
{
|
||||
int span0 = 0, span1 = 0;
|
||||
double x = std::min(pwl0.points_[0].x, pwl1.points_[0].x);
|
||||
f(x, pwl0.eval(x, &span0, false), pwl1.eval(x, &span1, false));
|
||||
while (span0 < (int)pwl0.points_.size() - 1 ||
|
||||
span1 < (int)pwl1.points_.size() - 1) {
|
||||
if (span0 == (int)pwl0.points_.size() - 1)
|
||||
x = pwl1.points_[++span1].x;
|
||||
else if (span1 == (int)pwl1.points_.size() - 1)
|
||||
x = pwl0.points_[++span0].x;
|
||||
else if (pwl0.points_[span0 + 1].x > pwl1.points_[span1 + 1].x)
|
||||
x = pwl1.points_[++span1].x;
|
||||
else
|
||||
x = pwl0.points_[++span0].x;
|
||||
f(x, pwl0.eval(x, &span0, false), pwl1.eval(x, &span1, false));
|
||||
}
|
||||
}
|
||||
|
||||
Pwl Pwl::combine(Pwl const &pwl0, Pwl const &pwl1,
|
||||
std::function<double(double x, double y0, double y1)> f,
|
||||
const double eps)
|
||||
{
|
||||
Pwl result;
|
||||
map2(pwl0, pwl1, [&](double x, double y0, double y1) {
|
||||
result.append(x, f(x, y0, y1), eps);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void Pwl::matchDomain(Interval const &domain, bool clip, const double eps)
|
||||
{
|
||||
int span = 0;
|
||||
prepend(domain.start, eval(clip ? points_[0].x : domain.start, &span),
|
||||
eps);
|
||||
span = points_.size() - 2;
|
||||
append(domain.end, eval(clip ? points_.back().x : domain.end, &span),
|
||||
eps);
|
||||
}
|
||||
|
||||
Pwl &Pwl::operator*=(double d)
|
||||
{
|
||||
for (auto &pt : points_)
|
||||
pt.y *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Pwl::debug(FILE *fp) const
|
||||
{
|
||||
fprintf(fp, "Pwl {\n");
|
||||
for (auto &p : points_)
|
||||
fprintf(fp, "\t(%g, %g)\n", p.x, p.y);
|
||||
fprintf(fp, "}\n");
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* Copyright (C) 2019, Raspberry Pi Ltd
|
||||
*
|
||||
* piecewise linear functions interface
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
|
||||
#include "libcamera/internal/yaml_parser.h"
|
||||
|
||||
namespace RPiController {
|
||||
|
||||
class Pwl
|
||||
{
|
||||
public:
|
||||
struct Interval {
|
||||
Interval(double _start, double _end)
|
||||
: start(_start), end(_end)
|
||||
{
|
||||
}
|
||||
double start, end;
|
||||
bool contains(double value)
|
||||
{
|
||||
return value >= start && value <= end;
|
||||
}
|
||||
double clip(double value)
|
||||
{
|
||||
return value < start ? start
|
||||
: (value > end ? end : value);
|
||||
}
|
||||
double len() const { return end - start; }
|
||||
};
|
||||
struct Point {
|
||||
Point() : x(0), y(0) {}
|
||||
Point(double _x, double _y)
|
||||
: x(_x), y(_y) {}
|
||||
double x, y;
|
||||
Point operator-(Point const &p) const
|
||||
{
|
||||
return Point(x - p.x, y - p.y);
|
||||
}
|
||||
Point operator+(Point const &p) const
|
||||
{
|
||||
return Point(x + p.x, y + p.y);
|
||||
}
|
||||
double operator%(Point const &p) const
|
||||
{
|
||||
return x * p.x + y * p.y;
|
||||
}
|
||||
Point operator*(double f) const { return Point(x * f, y * f); }
|
||||
Point operator/(double f) const { return Point(x / f, y / f); }
|
||||
double len2() const { return x * x + y * y; }
|
||||
double len() const { return sqrt(len2()); }
|
||||
};
|
||||
Pwl() {}
|
||||
Pwl(std::vector<Point> const &points) : points_(points) {}
|
||||
int read(const libcamera::YamlObject ¶ms);
|
||||
void append(double x, double y, const double eps = 1e-6);
|
||||
void prepend(double x, double y, const double eps = 1e-6);
|
||||
Interval domain() const;
|
||||
Interval range() const;
|
||||
bool empty() const;
|
||||
/*
|
||||
* Evaluate Pwl, optionally supplying an initial guess for the
|
||||
* "span". The "span" may be optionally be updated. If you want to know
|
||||
* the "span" value but don't have an initial guess you can set it to
|
||||
* -1.
|
||||
*/
|
||||
double eval(double x, int *spanPtr = nullptr,
|
||||
bool updateSpan = true) const;
|
||||
/*
|
||||
* Find perpendicular closest to xy, starting from span+1 so you can
|
||||
* call it repeatedly to check for multiple closest points (set span to
|
||||
* -1 on the first call). Also returns "pseudo" perpendiculars; see
|
||||
* PerpType enum.
|
||||
*/
|
||||
enum class PerpType {
|
||||
None, /* no perpendicular found */
|
||||
Start, /* start of Pwl is closest point */
|
||||
End, /* end of Pwl is closest point */
|
||||
Vertex, /* vertex of Pwl is closest point */
|
||||
Perpendicular /* true perpendicular found */
|
||||
};
|
||||
PerpType invert(Point const &xy, Point &perp, int &span,
|
||||
const double eps = 1e-6) const;
|
||||
/*
|
||||
* Compute the inverse function. Indicate if it is a proper (true)
|
||||
* inverse, or only a best effort (e.g. input was non-monotonic).
|
||||
*/
|
||||
Pwl inverse(bool *trueInverse = nullptr, const double eps = 1e-6) const;
|
||||
/* Compose two Pwls together, doing "this" first and "other" after. */
|
||||
Pwl compose(Pwl const &other, const double eps = 1e-6) const;
|
||||
/* Apply function to (x,y) values at every control point. */
|
||||
void map(std::function<void(double x, double y)> f) const;
|
||||
/*
|
||||
* Apply function to (x, y0, y1) values wherever either Pwl has a
|
||||
* control point.
|
||||
*/
|
||||
static void map2(Pwl const &pwl0, Pwl const &pwl1,
|
||||
std::function<void(double x, double y0, double y1)> f);
|
||||
/*
|
||||
* Combine two Pwls, meaning we create a new Pwl where the y values are
|
||||
* given by running f wherever either has a knot.
|
||||
*/
|
||||
static Pwl
|
||||
combine(Pwl const &pwl0, Pwl const &pwl1,
|
||||
std::function<double(double x, double y0, double y1)> f,
|
||||
const double eps = 1e-6);
|
||||
/*
|
||||
* Make "this" match (at least) the given domain. Any extension my be
|
||||
* clipped or linear.
|
||||
*/
|
||||
void matchDomain(Interval const &domain, bool clip = true,
|
||||
const double eps = 1e-6);
|
||||
Pwl &operator*=(double d);
|
||||
void debug(FILE *fp = stdout) const;
|
||||
|
||||
private:
|
||||
int findSpan(double x, int span) const;
|
||||
std::vector<Point> points_;
|
||||
};
|
||||
|
||||
} /* namespace RPiController */
|
|
@ -139,7 +139,7 @@ int Af::CfgParams::read(const libcamera::YamlObject ¶ms)
|
|||
readNumber<uint32_t>(skipFrames, params, "skip_frames");
|
||||
|
||||
if (params.contains("map"))
|
||||
map.read(params["map"]);
|
||||
map.readYaml(params["map"]);
|
||||
else
|
||||
LOG(RPiAf, Warning) << "No map defined";
|
||||
|
||||
|
@ -721,7 +721,7 @@ bool Af::setLensPosition(double dioptres, int *hwpos)
|
|||
|
||||
if (mode_ == AfModeManual) {
|
||||
LOG(RPiAf, Debug) << "setLensPosition: " << dioptres;
|
||||
ftarget_ = cfg_.map.domain().clip(dioptres);
|
||||
ftarget_ = cfg_.map.domain().clamp(dioptres);
|
||||
changed = !(initted_ && fsmooth_ == ftarget_);
|
||||
updateLensPosition();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#include "../af_algorithm.h"
|
||||
#include "../af_status.h"
|
||||
#include "../pdaf_data.h"
|
||||
#include "../pwl.h"
|
||||
|
||||
#include "libipa/pwl.h"
|
||||
|
||||
/*
|
||||
* This algorithm implements a hybrid of CDAF and PDAF, favouring PDAF.
|
||||
|
@ -100,7 +101,7 @@ private:
|
|||
uint32_t confThresh; /* PDAF confidence cell min (sensor-specific) */
|
||||
uint32_t confClip; /* PDAF confidence cell max (sensor-specific) */
|
||||
uint32_t skipFrames; /* frames to skip at start or modeswitch */
|
||||
Pwl map; /* converts dioptres -> lens driver position */
|
||||
libcamera::ipa::Pwl map; /* converts dioptres -> lens driver position */
|
||||
|
||||
CfgParams();
|
||||
int read(const libcamera::YamlObject ¶ms);
|
||||
|
|
|
@ -130,7 +130,7 @@ int AgcConstraint::read(const libcamera::YamlObject ¶ms)
|
|||
return -EINVAL;
|
||||
qHi = *value;
|
||||
|
||||
return yTarget.read(params["y_target"]);
|
||||
return yTarget.readYaml(params["y_target"]);
|
||||
}
|
||||
|
||||
static std::tuple<int, AgcConstraintMode>
|
||||
|
@ -237,7 +237,7 @@ int AgcConfig::read(const libcamera::YamlObject ¶ms)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = yTarget.read(params["y_target"]);
|
||||
ret = yTarget.readYaml(params["y_target"]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -715,7 +715,7 @@ static constexpr double EvGainYTargetLimit = 0.9;
|
|||
static double constraintComputeGain(AgcConstraint &c, const Histogram &h, double lux,
|
||||
double evGain, double &targetY)
|
||||
{
|
||||
targetY = c.yTarget.eval(c.yTarget.domain().clip(lux));
|
||||
targetY = c.yTarget.eval(c.yTarget.domain().clamp(lux));
|
||||
targetY = std::min(EvGainYTargetLimit, targetY * evGain);
|
||||
double iqm = h.interQuantileMean(c.qLo, c.qHi);
|
||||
return (targetY * h.bins()) / iqm;
|
||||
|
@ -734,7 +734,7 @@ void AgcChannel::computeGain(StatisticsPtr &statistics, Metadata *imageMetadata,
|
|||
* The initial gain and target_Y come from some of the regions. After
|
||||
* that we consider the histogram constraints.
|
||||
*/
|
||||
targetY = config_.yTarget.eval(config_.yTarget.domain().clip(lux.lux));
|
||||
targetY = config_.yTarget.eval(config_.yTarget.domain().clamp(lux.lux));
|
||||
targetY = std::min(EvGainYTargetLimit, targetY * evGain);
|
||||
|
||||
/*
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
#include <libipa/pwl.h>
|
||||
|
||||
#include "../agc_status.h"
|
||||
#include "../awb_status.h"
|
||||
#include "../controller.h"
|
||||
#include "../pwl.h"
|
||||
|
||||
/* This is our implementation of AGC. */
|
||||
|
||||
|
@ -40,7 +41,7 @@ struct AgcConstraint {
|
|||
Bound bound;
|
||||
double qLo;
|
||||
double qHi;
|
||||
Pwl yTarget;
|
||||
libcamera::ipa::Pwl yTarget;
|
||||
int read(const libcamera::YamlObject ¶ms);
|
||||
};
|
||||
|
||||
|
@ -61,7 +62,7 @@ struct AgcConfig {
|
|||
std::map<std::string, AgcExposureMode> exposureModes;
|
||||
std::map<std::string, AgcConstraintMode> constraintModes;
|
||||
std::vector<AgcChannelConstraint> channelConstraints;
|
||||
Pwl yTarget;
|
||||
libcamera::ipa::Pwl yTarget;
|
||||
double speed;
|
||||
uint16_t startupFrames;
|
||||
unsigned int convergenceFrames;
|
||||
|
|
|
@ -49,10 +49,10 @@ int AwbPrior::read(const libcamera::YamlObject ¶ms)
|
|||
return -EINVAL;
|
||||
lux = *value;
|
||||
|
||||
return prior.read(params["prior"]);
|
||||
return prior.readYaml(params["prior"]);
|
||||
}
|
||||
|
||||
static int readCtCurve(Pwl &ctR, Pwl &ctB, const libcamera::YamlObject ¶ms)
|
||||
static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::YamlObject ¶ms)
|
||||
{
|
||||
if (params.size() % 3) {
|
||||
LOG(RPiAwb, Error) << "AwbConfig: incomplete CT curve entry";
|
||||
|
@ -103,8 +103,8 @@ int AwbConfig::read(const libcamera::YamlObject ¶ms)
|
|||
if (ret)
|
||||
return ret;
|
||||
/* We will want the inverse functions of these too. */
|
||||
ctRInverse = ctR.inverse();
|
||||
ctBInverse = ctB.inverse();
|
||||
ctRInverse = ctR.inverse().first;
|
||||
ctBInverse = ctB.inverse().first;
|
||||
}
|
||||
|
||||
if (params.contains("priors")) {
|
||||
|
@ -207,7 +207,7 @@ void Awb::initialise()
|
|||
* them.
|
||||
*/
|
||||
if (!config_.ctR.empty() && !config_.ctB.empty()) {
|
||||
syncResults_.temperatureK = config_.ctR.domain().clip(4000);
|
||||
syncResults_.temperatureK = config_.ctR.domain().clamp(4000);
|
||||
syncResults_.gainR = 1.0 / config_.ctR.eval(syncResults_.temperatureK);
|
||||
syncResults_.gainG = 1.0;
|
||||
syncResults_.gainB = 1.0 / config_.ctB.eval(syncResults_.temperatureK);
|
||||
|
@ -273,8 +273,8 @@ void Awb::setManualGains(double manualR, double manualB)
|
|||
syncResults_.gainB = prevSyncResults_.gainB = manualB_;
|
||||
if (config_.bayes) {
|
||||
/* Also estimate the best corresponding colour temperature from the curves. */
|
||||
double ctR = config_.ctRInverse.eval(config_.ctRInverse.domain().clip(1 / manualR_));
|
||||
double ctB = config_.ctBInverse.eval(config_.ctBInverse.domain().clip(1 / manualB_));
|
||||
double ctR = config_.ctRInverse.eval(config_.ctRInverse.domain().clamp(1 / manualR_));
|
||||
double ctB = config_.ctBInverse.eval(config_.ctBInverse.domain().clamp(1 / manualB_));
|
||||
prevSyncResults_.temperatureK = (ctR + ctB) / 2;
|
||||
syncResults_.temperatureK = prevSyncResults_.temperatureK;
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ double Awb::computeDelta2Sum(double gainR, double gainB)
|
|||
return delta2Sum;
|
||||
}
|
||||
|
||||
Pwl Awb::interpolatePrior()
|
||||
ipa::Pwl Awb::interpolatePrior()
|
||||
{
|
||||
/*
|
||||
* Interpolate the prior log likelihood function for our current lux
|
||||
|
@ -485,7 +485,7 @@ Pwl Awb::interpolatePrior()
|
|||
idx++;
|
||||
double lux0 = config_.priors[idx].lux,
|
||||
lux1 = config_.priors[idx + 1].lux;
|
||||
return Pwl::combine(config_.priors[idx].prior,
|
||||
return ipa::Pwl::combine(config_.priors[idx].prior,
|
||||
config_.priors[idx + 1].prior,
|
||||
[&](double /*x*/, double y0, double y1) {
|
||||
return y0 + (y1 - y0) *
|
||||
|
@ -494,26 +494,26 @@ Pwl Awb::interpolatePrior()
|
|||
}
|
||||
}
|
||||
|
||||
static double interpolateQuadatric(Pwl::Point const &a, Pwl::Point const &b,
|
||||
Pwl::Point const &c)
|
||||
static double interpolateQuadatric(ipa::Pwl::Point const &a, ipa::Pwl::Point const &b,
|
||||
ipa::Pwl::Point const &c)
|
||||
{
|
||||
/*
|
||||
* Given 3 points on a curve, find the extremum of the function in that
|
||||
* interval by fitting a quadratic.
|
||||
*/
|
||||
const double eps = 1e-3;
|
||||
Pwl::Point ca = c - a, ba = b - a;
|
||||
double denominator = 2 * (ba.y * ca.x - ca.y * ba.x);
|
||||
ipa::Pwl::Point ca = c - a, ba = b - a;
|
||||
double denominator = 2 * (ba.y() * ca.x() - ca.y() * ba.x());
|
||||
if (abs(denominator) > eps) {
|
||||
double numerator = ba.y * ca.x * ca.x - ca.y * ba.x * ba.x;
|
||||
double result = numerator / denominator + a.x;
|
||||
return std::max(a.x, std::min(c.x, result));
|
||||
double numerator = ba.y() * ca.x() * ca.x() - ca.y() * ba.x() * ba.x();
|
||||
double result = numerator / denominator + a.x();
|
||||
return std::max(a.x(), std::min(c.x(), result));
|
||||
}
|
||||
/* has degenerated to straight line segment */
|
||||
return a.y < c.y - eps ? a.x : (c.y < a.y - eps ? c.x : b.x);
|
||||
return a.y() < c.y() - eps ? a.x() : (c.y() < a.y() - eps ? c.x() : b.x());
|
||||
}
|
||||
|
||||
double Awb::coarseSearch(Pwl const &prior)
|
||||
double Awb::coarseSearch(ipa::Pwl const &prior)
|
||||
{
|
||||
points_.clear(); /* assume doesn't deallocate memory */
|
||||
size_t bestPoint = 0;
|
||||
|
@ -525,22 +525,22 @@ double Awb::coarseSearch(Pwl const &prior)
|
|||
double b = config_.ctB.eval(t, &spanB);
|
||||
double gainR = 1 / r, gainB = 1 / b;
|
||||
double delta2Sum = computeDelta2Sum(gainR, gainB);
|
||||
double priorLogLikelihood = prior.eval(prior.domain().clip(t));
|
||||
double priorLogLikelihood = prior.eval(prior.domain().clamp(t));
|
||||
double finalLogLikelihood = delta2Sum - priorLogLikelihood;
|
||||
LOG(RPiAwb, Debug)
|
||||
<< "t: " << t << " gain R " << gainR << " gain B "
|
||||
<< gainB << " delta2_sum " << delta2Sum
|
||||
<< " prior " << priorLogLikelihood << " final "
|
||||
<< finalLogLikelihood;
|
||||
points_.push_back(Pwl::Point(t, finalLogLikelihood));
|
||||
if (points_.back().y < points_[bestPoint].y)
|
||||
points_.push_back(ipa::Pwl::Point({ t, finalLogLikelihood }));
|
||||
if (points_.back().y() < points_[bestPoint].y())
|
||||
bestPoint = points_.size() - 1;
|
||||
if (t == mode_->ctHi)
|
||||
break;
|
||||
/* for even steps along the r/b curve scale them by the current t */
|
||||
t = std::min(t + t / 10 * config_.coarseStep, mode_->ctHi);
|
||||
}
|
||||
t = points_[bestPoint].x;
|
||||
t = points_[bestPoint].x();
|
||||
LOG(RPiAwb, Debug) << "Coarse search found CT " << t;
|
||||
/*
|
||||
* We have the best point of the search, but refine it with a quadratic
|
||||
|
@ -559,7 +559,7 @@ double Awb::coarseSearch(Pwl const &prior)
|
|||
return t;
|
||||
}
|
||||
|
||||
void Awb::fineSearch(double &t, double &r, double &b, Pwl const &prior)
|
||||
void Awb::fineSearch(double &t, double &r, double &b, ipa::Pwl const &prior)
|
||||
{
|
||||
int spanR = -1, spanB = -1;
|
||||
config_.ctR.eval(t, &spanR);
|
||||
|
@ -570,14 +570,14 @@ void Awb::fineSearch(double &t, double &r, double &b, Pwl const &prior)
|
|||
config_.ctR.eval(t - nsteps * step, &spanR);
|
||||
double bDiff = config_.ctB.eval(t + nsteps * step, &spanB) -
|
||||
config_.ctB.eval(t - nsteps * step, &spanB);
|
||||
Pwl::Point transverse(bDiff, -rDiff);
|
||||
if (transverse.len2() < 1e-6)
|
||||
ipa::Pwl::Point transverse({ bDiff, -rDiff });
|
||||
if (transverse.length2() < 1e-6)
|
||||
return;
|
||||
/*
|
||||
* unit vector orthogonal to the b vs. r function (pointing outwards
|
||||
* with r and b increasing)
|
||||
*/
|
||||
transverse = transverse / transverse.len();
|
||||
transverse = transverse / transverse.length();
|
||||
double bestLogLikelihood = 0, bestT = 0, bestR = 0, bestB = 0;
|
||||
double transverseRange = config_.transverseNeg + config_.transversePos;
|
||||
const int maxNumDeltas = 12;
|
||||
|
@ -592,26 +592,26 @@ void Awb::fineSearch(double &t, double &r, double &b, Pwl const &prior)
|
|||
for (int i = -nsteps; i <= nsteps; i++) {
|
||||
double tTest = t + i * step;
|
||||
double priorLogLikelihood =
|
||||
prior.eval(prior.domain().clip(tTest));
|
||||
prior.eval(prior.domain().clamp(tTest));
|
||||
double rCurve = config_.ctR.eval(tTest, &spanR);
|
||||
double bCurve = config_.ctB.eval(tTest, &spanB);
|
||||
/* x will be distance off the curve, y the log likelihood there */
|
||||
Pwl::Point points[maxNumDeltas];
|
||||
ipa::Pwl::Point points[maxNumDeltas];
|
||||
int bestPoint = 0;
|
||||
/* Take some measurements transversely *off* the CT curve. */
|
||||
for (int j = 0; j < numDeltas; j++) {
|
||||
points[j].x = -config_.transverseNeg +
|
||||
(transverseRange * j) / (numDeltas - 1);
|
||||
Pwl::Point rbTest = Pwl::Point(rCurve, bCurve) +
|
||||
transverse * points[j].x;
|
||||
double rTest = rbTest.x, bTest = rbTest.y;
|
||||
points[j][0] = -config_.transverseNeg +
|
||||
(transverseRange * j) / (numDeltas - 1);
|
||||
ipa::Pwl::Point rbTest = ipa::Pwl::Point({ rCurve, bCurve }) +
|
||||
transverse * points[j].x();
|
||||
double rTest = rbTest.x(), bTest = rbTest.y();
|
||||
double gainR = 1 / rTest, gainB = 1 / bTest;
|
||||
double delta2Sum = computeDelta2Sum(gainR, gainB);
|
||||
points[j].y = delta2Sum - priorLogLikelihood;
|
||||
points[j][1] = delta2Sum - priorLogLikelihood;
|
||||
LOG(RPiAwb, Debug)
|
||||
<< "At t " << tTest << " r " << rTest << " b "
|
||||
<< bTest << ": " << points[j].y;
|
||||
if (points[j].y < points[bestPoint].y)
|
||||
<< bTest << ": " << points[j].y();
|
||||
if (points[j].y() < points[bestPoint].y())
|
||||
bestPoint = j;
|
||||
}
|
||||
/*
|
||||
|
@ -619,11 +619,11 @@ void Awb::fineSearch(double &t, double &r, double &b, Pwl const &prior)
|
|||
* now let's do a quadratic interpolation for the best result.
|
||||
*/
|
||||
bestPoint = std::max(1, std::min(bestPoint, numDeltas - 2));
|
||||
Pwl::Point rbTest = Pwl::Point(rCurve, bCurve) +
|
||||
transverse * interpolateQuadatric(points[bestPoint - 1],
|
||||
points[bestPoint],
|
||||
points[bestPoint + 1]);
|
||||
double rTest = rbTest.x, bTest = rbTest.y;
|
||||
ipa::Pwl::Point rbTest = ipa::Pwl::Point({ rCurve, bCurve }) +
|
||||
transverse * interpolateQuadatric(points[bestPoint - 1],
|
||||
points[bestPoint],
|
||||
points[bestPoint + 1]);
|
||||
double rTest = rbTest.x(), bTest = rbTest.y();
|
||||
double gainR = 1 / rTest, gainB = 1 / bTest;
|
||||
double delta2Sum = computeDelta2Sum(gainR, gainB);
|
||||
double finalLogLikelihood = delta2Sum - priorLogLikelihood;
|
||||
|
@ -653,7 +653,7 @@ void Awb::awbBayes()
|
|||
* Get the current prior, and scale according to how many zones are
|
||||
* valid... not entirely sure about this.
|
||||
*/
|
||||
Pwl prior = interpolatePrior();
|
||||
ipa::Pwl prior = interpolatePrior();
|
||||
prior *= zones_.size() / (double)(statistics_->awbRegions.numRegions());
|
||||
prior.map([](double x, double y) {
|
||||
LOG(RPiAwb, Debug) << "(" << x << "," << y << ")";
|
||||
|
|
|
@ -10,11 +10,14 @@
|
|||
#include <condition_variable>
|
||||
#include <thread>
|
||||
|
||||
#include <libcamera/geometry.h>
|
||||
|
||||
#include "../awb_algorithm.h"
|
||||
#include "../pwl.h"
|
||||
#include "../awb_status.h"
|
||||
#include "../statistics.h"
|
||||
|
||||
#include "libipa/pwl.h"
|
||||
|
||||
namespace RPiController {
|
||||
|
||||
/* Control algorithm to perform AWB calculations. */
|
||||
|
@ -28,7 +31,7 @@ struct AwbMode {
|
|||
struct AwbPrior {
|
||||
int read(const libcamera::YamlObject ¶ms);
|
||||
double lux; /* lux level */
|
||||
Pwl prior; /* maps CT to prior log likelihood for this lux level */
|
||||
libcamera::ipa::Pwl prior; /* maps CT to prior log likelihood for this lux level */
|
||||
};
|
||||
|
||||
struct AwbConfig {
|
||||
|
@ -41,10 +44,10 @@ struct AwbConfig {
|
|||
unsigned int convergenceFrames; /* approx number of frames to converge */
|
||||
double speed; /* IIR filter speed applied to algorithm results */
|
||||
bool fast; /* "fast" mode uses a 16x16 rather than 32x32 grid */
|
||||
Pwl ctR; /* function maps CT to r (= R/G) */
|
||||
Pwl ctB; /* function maps CT to b (= B/G) */
|
||||
Pwl ctRInverse; /* inverse of ctR */
|
||||
Pwl ctBInverse; /* inverse of ctB */
|
||||
libcamera::ipa::Pwl ctR; /* function maps CT to r (= R/G) */
|
||||
libcamera::ipa::Pwl ctB; /* function maps CT to b (= B/G) */
|
||||
libcamera::ipa::Pwl ctRInverse; /* inverse of ctR */
|
||||
libcamera::ipa::Pwl ctBInverse; /* inverse of ctB */
|
||||
/* table of illuminant priors at different lux levels */
|
||||
std::vector<AwbPrior> priors;
|
||||
/* AWB "modes" (determines the search range) */
|
||||
|
@ -161,11 +164,11 @@ private:
|
|||
void awbGrey();
|
||||
void prepareStats();
|
||||
double computeDelta2Sum(double gainR, double gainB);
|
||||
Pwl interpolatePrior();
|
||||
double coarseSearch(Pwl const &prior);
|
||||
void fineSearch(double &t, double &r, double &b, Pwl const &prior);
|
||||
libcamera::ipa::Pwl interpolatePrior();
|
||||
double coarseSearch(libcamera::ipa::Pwl const &prior);
|
||||
void fineSearch(double &t, double &r, double &b, libcamera::ipa::Pwl const &prior);
|
||||
std::vector<RGB> zones_;
|
||||
std::vector<Pwl::Point> points_;
|
||||
std::vector<libcamera::ipa::Pwl::Point> points_;
|
||||
/* manual r setting */
|
||||
double manualR_;
|
||||
/* manual b setting */
|
||||
|
|
|
@ -71,7 +71,7 @@ int Ccm::read(const libcamera::YamlObject ¶ms)
|
|||
int ret;
|
||||
|
||||
if (params.contains("saturation")) {
|
||||
ret = config_.saturation.read(params["saturation"]);
|
||||
ret = config_.saturation.readYaml(params["saturation"]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ void Ccm::prepare(Metadata *imageMetadata)
|
|||
ccmStatus.saturation = saturation;
|
||||
if (!config_.saturation.empty())
|
||||
saturation *= config_.saturation.eval(
|
||||
config_.saturation.domain().clip(lux.lux));
|
||||
config_.saturation.domain().clamp(lux.lux));
|
||||
ccm = applySaturation(ccm, saturation);
|
||||
for (int j = 0; j < 3; j++)
|
||||
for (int i = 0; i < 3; i++)
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include <libipa/pwl.h>
|
||||
|
||||
#include "../ccm_algorithm.h"
|
||||
#include "../pwl.h"
|
||||
|
||||
namespace RPiController {
|
||||
|
||||
|
@ -54,7 +55,7 @@ struct CtCcm {
|
|||
|
||||
struct CcmConfig {
|
||||
std::vector<CtCcm> ccms;
|
||||
Pwl saturation;
|
||||
libcamera::ipa::Pwl saturation;
|
||||
};
|
||||
|
||||
class Ccm : public CcmAlgorithm
|
||||
|
|
|
@ -53,7 +53,7 @@ int Contrast::read(const libcamera::YamlObject ¶ms)
|
|||
config_.hiHistogram = params["hi_histogram"].get<double>(0.95);
|
||||
config_.hiLevel = params["hi_level"].get<double>(0.95);
|
||||
config_.hiMax = params["hi_max"].get<double>(2000);
|
||||
return config_.gammaCurve.read(params["gamma_curve"]);
|
||||
return config_.gammaCurve.readYaml(params["gamma_curve"]);
|
||||
}
|
||||
|
||||
void Contrast::setBrightness(double brightness)
|
||||
|
@ -92,10 +92,10 @@ void Contrast::prepare(Metadata *imageMetadata)
|
|||
imageMetadata->set("contrast.status", status_);
|
||||
}
|
||||
|
||||
Pwl computeStretchCurve(Histogram const &histogram,
|
||||
ipa::Pwl computeStretchCurve(Histogram const &histogram,
|
||||
ContrastConfig const &config)
|
||||
{
|
||||
Pwl enhance;
|
||||
ipa::Pwl enhance;
|
||||
enhance.append(0, 0);
|
||||
/*
|
||||
* If the start of the histogram is rather empty, try to pull it down a
|
||||
|
@ -136,10 +136,10 @@ Pwl computeStretchCurve(Histogram const &histogram,
|
|||
return enhance;
|
||||
}
|
||||
|
||||
Pwl applyManualContrast(Pwl const &gammaCurve, double brightness,
|
||||
double contrast)
|
||||
ipa::Pwl applyManualContrast(ipa::Pwl const &gammaCurve, double brightness,
|
||||
double contrast)
|
||||
{
|
||||
Pwl newGammaCurve;
|
||||
ipa::Pwl newGammaCurve;
|
||||
LOG(RPiContrast, Debug)
|
||||
<< "Manual brightness " << brightness << " contrast " << contrast;
|
||||
gammaCurve.map([&](double x, double y) {
|
||||
|
@ -160,7 +160,7 @@ void Contrast::process(StatisticsPtr &stats,
|
|||
* ways: 1. Adjust the gamma curve so as to pull the start of the
|
||||
* histogram down, and possibly push the end up.
|
||||
*/
|
||||
Pwl gammaCurve = config_.gammaCurve;
|
||||
ipa::Pwl gammaCurve = config_.gammaCurve;
|
||||
if (ceEnable_) {
|
||||
if (config_.loMax != 0 || config_.hiMax != 0)
|
||||
gammaCurve = computeStretchCurve(histogram, config_).compose(gammaCurve);
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
#include <mutex>
|
||||
|
||||
#include <libipa/pwl.h>
|
||||
|
||||
#include "../contrast_algorithm.h"
|
||||
#include "../pwl.h"
|
||||
|
||||
namespace RPiController {
|
||||
|
||||
|
@ -26,7 +27,7 @@ struct ContrastConfig {
|
|||
double hiHistogram;
|
||||
double hiLevel;
|
||||
double hiMax;
|
||||
Pwl gammaCurve;
|
||||
libcamera::ipa::Pwl gammaCurve;
|
||||
};
|
||||
|
||||
class Contrast : public ContrastAlgorithm
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "../device_status.h"
|
||||
#include "../lux_status.h"
|
||||
#include "../pwl.h"
|
||||
|
||||
#include "geq.h"
|
||||
|
||||
|
@ -45,7 +44,7 @@ int Geq::read(const libcamera::YamlObject ¶ms)
|
|||
}
|
||||
|
||||
if (params.contains("strength")) {
|
||||
int ret = config_.strength.read(params["strength"]);
|
||||
int ret = config_.strength.readYaml(params["strength"]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -67,7 +66,7 @@ void Geq::prepare(Metadata *imageMetadata)
|
|||
GeqStatus geqStatus = {};
|
||||
double strength = config_.strength.empty()
|
||||
? 1.0
|
||||
: config_.strength.eval(config_.strength.domain().clip(luxStatus.lux));
|
||||
: config_.strength.eval(config_.strength.domain().clamp(luxStatus.lux));
|
||||
strength *= deviceStatus.analogueGain;
|
||||
double offset = config_.offset * strength;
|
||||
double slope = config_.slope * strength;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <libipa/pwl.h>
|
||||
|
||||
#include "../algorithm.h"
|
||||
#include "../geq_status.h"
|
||||
|
||||
|
@ -16,7 +18,7 @@ namespace RPiController {
|
|||
struct GeqConfig {
|
||||
uint16_t offset;
|
||||
double slope;
|
||||
Pwl strength; /* lux to strength factor */
|
||||
libcamera::ipa::Pwl strength; /* lux to strength factor */
|
||||
};
|
||||
|
||||
class Geq : public Algorithm
|
||||
|
|
|
@ -42,7 +42,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod
|
|||
|
||||
/* Lens shading related parameters. */
|
||||
if (params.contains("spatial_gain_curve")) {
|
||||
spatialGainCurve.read(params["spatial_gain_curve"]);
|
||||
spatialGainCurve.readYaml(params["spatial_gain_curve"]);
|
||||
} else if (params.contains("spatial_gain")) {
|
||||
double spatialGain = params["spatial_gain"].get<double>(2.0);
|
||||
spatialGainCurve.append(0.0, spatialGain);
|
||||
|
@ -66,7 +66,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod
|
|||
iirStrength = params["iir_strength"].get<double>(8.0);
|
||||
strength = params["strength"].get<double>(1.5);
|
||||
if (tonemapEnable)
|
||||
tonemap.read(params["tonemap"]);
|
||||
tonemap.readYaml(params["tonemap"]);
|
||||
speed = params["speed"].get<double>(1.0);
|
||||
if (params.contains("hi_quantile_targets")) {
|
||||
hiQuantileTargets = params["hi_quantile_targets"].getList<double>().value();
|
||||
|
@ -212,7 +212,7 @@ bool Hdr::updateTonemap([[maybe_unused]] StatisticsPtr &stats, HdrConfig &config
|
|||
/* When there's a change of HDR mode we start over with a new tonemap curve. */
|
||||
if (delayedStatus_.mode != previousMode_) {
|
||||
previousMode_ = delayedStatus_.mode;
|
||||
tonemap_ = Pwl();
|
||||
tonemap_ = ipa::Pwl();
|
||||
}
|
||||
|
||||
/* No tonemapping. No need to output a tonemap.status. */
|
||||
|
@ -275,7 +275,7 @@ bool Hdr::updateTonemap([[maybe_unused]] StatisticsPtr &stats, HdrConfig &config
|
|||
double power = std::clamp(min_power, config.powerMin, config.powerMax);
|
||||
|
||||
/* Generate the tonemap, including the contrast adjustment factors. */
|
||||
Pwl tonemap;
|
||||
libcamera::ipa::Pwl tonemap;
|
||||
tonemap.append(0, 0);
|
||||
for (unsigned int i = 0; i <= 6; i++) {
|
||||
double x = 1 << (i + 9); /* x loops from 512 to 32768 inclusive */
|
||||
|
|
|
@ -12,9 +12,10 @@
|
|||
|
||||
#include <libcamera/geometry.h>
|
||||
|
||||
#include <libipa/pwl.h>
|
||||
|
||||
#include "../hdr_algorithm.h"
|
||||
#include "../hdr_status.h"
|
||||
#include "../pwl.h"
|
||||
|
||||
/* This is our implementation of an HDR algorithm. */
|
||||
|
||||
|
@ -26,7 +27,7 @@ struct HdrConfig {
|
|||
std::map<unsigned int, std::string> channelMap;
|
||||
|
||||
/* Lens shading related parameters. */
|
||||
Pwl spatialGainCurve; /* Brightness to gain curve for different image regions. */
|
||||
libcamera::ipa::Pwl spatialGainCurve; /* Brightness to gain curve for different image regions. */
|
||||
unsigned int diffusion; /* How much to diffuse the gain spatially. */
|
||||
|
||||
/* Tonemap related parameters. */
|
||||
|
@ -35,7 +36,7 @@ struct HdrConfig {
|
|||
double detailSlope;
|
||||
double iirStrength;
|
||||
double strength;
|
||||
Pwl tonemap;
|
||||
libcamera::ipa::Pwl tonemap;
|
||||
/* These relate to adaptive tonemap calculation. */
|
||||
double speed;
|
||||
std::vector<double> hiQuantileTargets; /* quantiles to check for unsaturated images */
|
||||
|
@ -75,7 +76,7 @@ private:
|
|||
HdrStatus status_; /* track the current HDR mode and channel */
|
||||
HdrStatus delayedStatus_; /* track the delayed HDR mode and channel */
|
||||
std::string previousMode_;
|
||||
Pwl tonemap_;
|
||||
libcamera::ipa::Pwl tonemap_;
|
||||
libcamera::Size regions_; /* stats regions */
|
||||
unsigned int numRegions_; /* total number of stats regions */
|
||||
std::vector<double> gains_[2];
|
||||
|
|
|
@ -33,7 +33,7 @@ int Tonemap::read(const libcamera::YamlObject ¶ms)
|
|||
config_.detailSlope = params["detail_slope"].get<double>(0.1);
|
||||
config_.iirStrength = params["iir_strength"].get<double>(1.0);
|
||||
config_.strength = params["strength"].get<double>(1.0);
|
||||
config_.tonemap.read(params["tone_curve"]);
|
||||
config_.tonemap.readYaml(params["tone_curve"]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <libipa/pwl.h>
|
||||
|
||||
#include "algorithm.h"
|
||||
#include "pwl.h"
|
||||
|
||||
namespace RPiController {
|
||||
|
||||
|
@ -16,7 +17,7 @@ struct TonemapConfig {
|
|||
double detailSlope;
|
||||
double iirStrength;
|
||||
double strength;
|
||||
Pwl tonemap;
|
||||
libcamera::ipa::Pwl tonemap;
|
||||
};
|
||||
|
||||
class Tonemap : public Algorithm
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "pwl.h"
|
||||
#include <libipa/pwl.h>
|
||||
|
||||
struct TonemapStatus {
|
||||
uint16_t detailConstant;
|
||||
double detailSlope;
|
||||
double iirStrength;
|
||||
double strength;
|
||||
RPiController::Pwl tonemap;
|
||||
libcamera::ipa::Pwl tonemap;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue