summaryrefslogtreecommitdiff
path: root/src/ipa/raspberrypi/controller/rpi/alsc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipa/raspberrypi/controller/rpi/alsc.cpp')
-rw-r--r--src/ipa/raspberrypi/controller/rpi/alsc.cpp641
1 files changed, 304 insertions, 337 deletions
diff --git a/src/ipa/raspberrypi/controller/rpi/alsc.cpp b/src/ipa/raspberrypi/controller/rpi/alsc.cpp
index e575c14a..98b77154 100644
--- a/src/ipa/raspberrypi/controller/rpi/alsc.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/alsc.cpp
@@ -26,31 +26,31 @@ LOG_DEFINE_CATEGORY(RPiAlsc)
static const int X = ALSC_CELLS_X;
static const int Y = ALSC_CELLS_Y;
static const int XY = X * Y;
-static const double INSUFFICIENT_DATA = -1.0;
+static const double InsufficientData = -1.0;
Alsc::Alsc(Controller *controller)
: Algorithm(controller)
{
- async_abort_ = async_start_ = async_started_ = async_finished_ = false;
- async_thread_ = std::thread(std::bind(&Alsc::asyncFunc, this));
+ asyncAbort_ = asyncStart_ = asyncStarted_ = asyncFinished_ = false;
+ asyncThread_ = std::thread(std::bind(&Alsc::asyncFunc, this));
}
Alsc::~Alsc()
{
{
std::lock_guard<std::mutex> lock(mutex_);
- async_abort_ = true;
+ asyncAbort_ = true;
}
- async_signal_.notify_one();
- async_thread_.join();
+ asyncSignal_.notify_one();
+ asyncThread_.join();
}
-char const *Alsc::Name() const
+char const *Alsc::name() const
{
return NAME;
}
-static void generate_lut(double *lut, boost::property_tree::ptree const &params)
+static void generateLut(double *lut, boost::property_tree::ptree const &params)
{
double cstrength = params.get<double>("corner_strength", 2.0);
if (cstrength <= 1.0)
@@ -73,34 +73,34 @@ static void generate_lut(double *lut, boost::property_tree::ptree const &params)
}
}
-static void read_lut(double *lut, boost::property_tree::ptree const &params)
+static void readLut(double *lut, boost::property_tree::ptree const &params)
{
int num = 0;
- const int max_num = XY;
+ const int maxNum = XY;
for (auto &p : params) {
- if (num == max_num)
+ if (num == maxNum)
throw std::runtime_error(
"Alsc: too many entries in LSC table");
lut[num++] = p.second.get_value<double>();
}
- if (num < max_num)
+ if (num < maxNum)
throw std::runtime_error("Alsc: too few entries in LSC table");
}
-static void read_calibrations(std::vector<AlscCalibration> &calibrations,
- boost::property_tree::ptree const &params,
- std::string const &name)
+static void readCalibrations(std::vector<AlscCalibration> &calibrations,
+ boost::property_tree::ptree const &params,
+ std::string const &name)
{
if (params.get_child_optional(name)) {
- double last_ct = 0;
+ double lastCt = 0;
for (auto &p : params.get_child(name)) {
double ct = p.second.get<double>("ct");
- if (ct <= last_ct)
+ if (ct <= lastCt)
throw std::runtime_error(
"Alsc: entries in " + name +
" must be in increasing ct order");
AlscCalibration calibration;
- calibration.ct = last_ct = ct;
+ calibration.ct = lastCt = ct;
boost::property_tree::ptree const &table =
p.second.get_child("table");
int num = 0;
@@ -124,249 +124,239 @@ static void read_calibrations(std::vector<AlscCalibration> &calibrations,
}
}
-void Alsc::Read(boost::property_tree::ptree const &params)
+void Alsc::read(boost::property_tree::ptree const &params)
{
- config_.frame_period = params.get<uint16_t>("frame_period", 12);
- config_.startup_frames = params.get<uint16_t>("startup_frames", 10);
+ config_.framePeriod = params.get<uint16_t>("frame_period", 12);
+ config_.startupFrames = params.get<uint16_t>("startup_frames", 10);
config_.speed = params.get<double>("speed", 0.05);
double sigma = params.get<double>("sigma", 0.01);
- config_.sigma_Cr = params.get<double>("sigma_Cr", sigma);
- config_.sigma_Cb = params.get<double>("sigma_Cb", sigma);
- config_.min_count = params.get<double>("min_count", 10.0);
- config_.min_G = params.get<uint16_t>("min_G", 50);
+ config_.sigmaCr = params.get<double>("sigma_Cr", sigma);
+ config_.sigmaCb = params.get<double>("sigma_Cb", sigma);
+ config_.minCount = params.get<double>("min_count", 10.0);
+ config_.minG = params.get<uint16_t>("min_G", 50);
config_.omega = params.get<double>("omega", 1.3);
- config_.n_iter = params.get<uint32_t>("n_iter", X + Y);
- config_.luminance_strength =
+ config_.nIter = params.get<uint32_t>("n_iter", X + Y);
+ config_.luminanceStrength =
params.get<double>("luminance_strength", 1.0);
for (int i = 0; i < XY; i++)
- config_.luminance_lut[i] = 1.0;
+ config_.luminanceLut[i] = 1.0;
if (params.get_child_optional("corner_strength"))
- generate_lut(config_.luminance_lut, params);
+ generateLut(config_.luminanceLut, params);
else if (params.get_child_optional("luminance_lut"))
- read_lut(config_.luminance_lut,
- params.get_child("luminance_lut"));
+ readLut(config_.luminanceLut,
+ params.get_child("luminance_lut"));
else
LOG(RPiAlsc, Warning)
<< "no luminance table - assume unity everywhere";
- read_calibrations(config_.calibrations_Cr, params, "calibrations_Cr");
- read_calibrations(config_.calibrations_Cb, params, "calibrations_Cb");
- config_.default_ct = params.get<double>("default_ct", 4500.0);
+ readCalibrations(config_.calibrationsCr, params, "calibrations_Cr");
+ readCalibrations(config_.calibrationsCb, params, "calibrations_Cb");
+ config_.defaultCt = params.get<double>("default_ct", 4500.0);
config_.threshold = params.get<double>("threshold", 1e-3);
- config_.lambda_bound = params.get<double>("lambda_bound", 0.05);
-}
-
-static double get_ct(Metadata *metadata, double default_ct);
-static void get_cal_table(double ct,
- std::vector<AlscCalibration> const &calibrations,
- double cal_table[XY]);
-static void resample_cal_table(double const cal_table_in[XY],
- CameraMode const &camera_mode,
- double cal_table_out[XY]);
-static void compensate_lambdas_for_cal(double const cal_table[XY],
- double const old_lambdas[XY],
- double new_lambdas[XY]);
-static void add_luminance_to_tables(double results[3][Y][X],
- double const lambda_r[XY], double lambda_g,
- double const lambda_b[XY],
- double const luminance_lut[XY],
- double luminance_strength);
-
-void Alsc::Initialise()
-{
- frame_count2_ = frame_count_ = frame_phase_ = 0;
- first_time_ = true;
- ct_ = config_.default_ct;
+ config_.lambdaBound = params.get<double>("lambda_bound", 0.05);
+}
+
+static double getCt(Metadata *metadata, double defaultCt);
+static void getCalTable(double ct, std::vector<AlscCalibration> const &calibrations,
+ double calTable[XY]);
+static void resampleCalTable(double const calTableIn[XY], CameraMode const &cameraMode,
+ double calTableOut[XY]);
+static void compensateLambdasForCal(double const calTable[XY], double const oldLambdas[XY],
+ double newLambdas[XY]);
+static void addLuminanceToTables(double results[3][Y][X], double const lambdaR[XY], double lambdaG,
+ double const lambdaB[XY], double const luminanceLut[XY],
+ double luminanceStrength);
+
+void Alsc::initialise()
+{
+ frameCount2_ = frameCount_ = framePhase_ = 0;
+ firstTime_ = true;
+ ct_ = config_.defaultCt;
// The lambdas are initialised in the SwitchMode.
}
void Alsc::waitForAysncThread()
{
- if (async_started_) {
- async_started_ = false;
+ if (asyncStarted_) {
+ asyncStarted_ = false;
std::unique_lock<std::mutex> lock(mutex_);
- sync_signal_.wait(lock, [&] {
- return async_finished_;
+ syncSignal_.wait(lock, [&] {
+ return asyncFinished_;
});
- async_finished_ = false;
+ asyncFinished_ = false;
}
}
-static bool compare_modes(CameraMode const &cm0, CameraMode const &cm1)
+static bool compareModes(CameraMode const &cm0, CameraMode const &cm1)
{
// Return true if the modes crop from the sensor significantly differently,
// or if the user transform has changed.
if (cm0.transform != cm1.transform)
return true;
- int left_diff = abs(cm0.crop_x - cm1.crop_x);
- int top_diff = abs(cm0.crop_y - cm1.crop_y);
- int right_diff = fabs(cm0.crop_x + cm0.scale_x * cm0.width -
- cm1.crop_x - cm1.scale_x * cm1.width);
- int bottom_diff = fabs(cm0.crop_y + cm0.scale_y * cm0.height -
- cm1.crop_y - cm1.scale_y * cm1.height);
+ int leftDiff = abs(cm0.cropX - cm1.cropX);
+ int topDiff = abs(cm0.cropY - cm1.cropY);
+ int rightDiff = fabs(cm0.cropX + cm0.scaleX * cm0.width -
+ cm1.cropX - cm1.scaleX * cm1.width);
+ int bottomDiff = fabs(cm0.cropY + cm0.scaleY * cm0.height -
+ cm1.cropY - cm1.scaleY * cm1.height);
// These thresholds are a rather arbitrary amount chosen to trigger
// when carrying on with the previously calculated tables might be
// worse than regenerating them (but without the adaptive algorithm).
- int threshold_x = cm0.sensor_width >> 4;
- int threshold_y = cm0.sensor_height >> 4;
- return left_diff > threshold_x || right_diff > threshold_x ||
- top_diff > threshold_y || bottom_diff > threshold_y;
+ int thresholdX = cm0.sensorWidth >> 4;
+ int thresholdY = cm0.sensorHeight >> 4;
+ return leftDiff > thresholdX || rightDiff > thresholdX ||
+ topDiff > thresholdY || bottomDiff > thresholdY;
}
-void Alsc::SwitchMode(CameraMode const &camera_mode,
+void Alsc::switchMode(CameraMode const &cameraMode,
[[maybe_unused]] Metadata *metadata)
{
// We're going to start over with the tables if there's any "significant"
// change.
- bool reset_tables = first_time_ || compare_modes(camera_mode_, camera_mode);
+ bool resetTables = firstTime_ || compareModes(cameraMode_, cameraMode);
// Believe the colour temperature from the AWB, if there is one.
- ct_ = get_ct(metadata, ct_);
+ ct_ = getCt(metadata, ct_);
// Ensure the other thread isn't running while we do this.
waitForAysncThread();
- camera_mode_ = camera_mode;
+ cameraMode_ = cameraMode;
// We must resample the luminance table like we do the others, but it's
// fixed so we can simply do it up front here.
- resample_cal_table(config_.luminance_lut, camera_mode_, luminance_table_);
+ resampleCalTable(config_.luminanceLut, cameraMode_, luminanceTable_);
- if (reset_tables) {
+ if (resetTables) {
// Upon every "table reset", arrange for something sensible to be
// generated. Construct the tables for the previous recorded colour
// temperature. In order to start over from scratch we initialise
// the lambdas, but the rest of this code then echoes the code in
// doAlsc, without the adaptive algorithm.
for (int i = 0; i < XY; i++)
- lambda_r_[i] = lambda_b_[i] = 1.0;
- double cal_table_r[XY], cal_table_b[XY], cal_table_tmp[XY];
- get_cal_table(ct_, config_.calibrations_Cr, cal_table_tmp);
- resample_cal_table(cal_table_tmp, camera_mode_, cal_table_r);
- get_cal_table(ct_, config_.calibrations_Cb, cal_table_tmp);
- resample_cal_table(cal_table_tmp, camera_mode_, cal_table_b);
- compensate_lambdas_for_cal(cal_table_r, lambda_r_,
- async_lambda_r_);
- compensate_lambdas_for_cal(cal_table_b, lambda_b_,
- async_lambda_b_);
- add_luminance_to_tables(sync_results_, async_lambda_r_, 1.0,
- async_lambda_b_, luminance_table_,
- config_.luminance_strength);
- memcpy(prev_sync_results_, sync_results_,
- sizeof(prev_sync_results_));
- frame_phase_ = config_.frame_period; // run the algo again asap
- first_time_ = false;
+ lambdaR_[i] = lambdaB_[i] = 1.0;
+ double calTableR[XY], calTableB[XY], calTableTmp[XY];
+ getCalTable(ct_, config_.calibrationsCr, calTableTmp);
+ resampleCalTable(calTableTmp, cameraMode_, calTableR);
+ getCalTable(ct_, config_.calibrationsCb, calTableTmp);
+ resampleCalTable(calTableTmp, cameraMode_, calTableB);
+ compensateLambdasForCal(calTableR, lambdaR_, asyncLambdaR_);
+ compensateLambdasForCal(calTableB, lambdaB_, asyncLambdaB_);
+ addLuminanceToTables(syncResults_, asyncLambdaR_, 1.0, asyncLambdaB_,
+ luminanceTable_, config_.luminanceStrength);
+ memcpy(prevSyncResults_, syncResults_, sizeof(prevSyncResults_));
+ framePhase_ = config_.framePeriod; // run the algo again asap
+ firstTime_ = false;
}
}
void Alsc::fetchAsyncResults()
{
LOG(RPiAlsc, Debug) << "Fetch ALSC results";
- async_finished_ = false;
- async_started_ = false;
- memcpy(sync_results_, async_results_, sizeof(sync_results_));
+ asyncFinished_ = false;
+ asyncStarted_ = false;
+ memcpy(syncResults_, asyncResults_, sizeof(syncResults_));
}
-double get_ct(Metadata *metadata, double default_ct)
+double getCt(Metadata *metadata, double defaultCt)
{
- AwbStatus awb_status;
- awb_status.temperature_K = default_ct; // in case nothing found
- if (metadata->Get("awb.status", awb_status) != 0)
+ AwbStatus awbStatus;
+ awbStatus.temperatureK = defaultCt; // in case nothing found
+ if (metadata->get("awb.status", awbStatus) != 0)
LOG(RPiAlsc, Debug) << "no AWB results found, using "
- << awb_status.temperature_K;
+ << awbStatus.temperatureK;
else
LOG(RPiAlsc, Debug) << "AWB results found, using "
- << awb_status.temperature_K;
- return awb_status.temperature_K;
+ << awbStatus.temperatureK;
+ return awbStatus.temperatureK;
}
-static void copy_stats(bcm2835_isp_stats_region regions[XY], StatisticsPtr &stats,
- AlscStatus const &status)
+static void copyStats(bcm2835_isp_stats_region regions[XY], StatisticsPtr &stats,
+ AlscStatus const &status)
{
- bcm2835_isp_stats_region *input_regions = stats->awb_stats;
- double *r_table = (double *)status.r;
- double *g_table = (double *)status.g;
- double *b_table = (double *)status.b;
+ bcm2835_isp_stats_region *inputRegions = stats->awb_stats;
+ double *rTable = (double *)status.r;
+ double *gTable = (double *)status.g;
+ double *bTable = (double *)status.b;
for (int i = 0; i < XY; i++) {
- regions[i].r_sum = input_regions[i].r_sum / r_table[i];
- regions[i].g_sum = input_regions[i].g_sum / g_table[i];
- regions[i].b_sum = input_regions[i].b_sum / b_table[i];
- regions[i].counted = input_regions[i].counted;
+ regions[i].r_sum = inputRegions[i].r_sum / rTable[i];
+ regions[i].g_sum = inputRegions[i].g_sum / gTable[i];
+ regions[i].b_sum = inputRegions[i].b_sum / bTable[i];
+ regions[i].counted = inputRegions[i].counted;
// (don't care about the uncounted value)
}
}
-void Alsc::restartAsync(StatisticsPtr &stats, Metadata *image_metadata)
+void Alsc::restartAsync(StatisticsPtr &stats, Metadata *imageMetadata)
{
LOG(RPiAlsc, Debug) << "Starting ALSC calculation";
// Get the current colour temperature. It's all we need from the
// metadata. Default to the last CT value (which could be the default).
- ct_ = get_ct(image_metadata, ct_);
+ ct_ = getCt(imageMetadata, ct_);
// We have to copy the statistics here, dividing out our best guess of
// the LSC table that the pipeline applied to them.
- AlscStatus alsc_status;
- if (image_metadata->Get("alsc.status", alsc_status) != 0) {
+ AlscStatus alscStatus;
+ if (imageMetadata->get("alsc.status", alscStatus) != 0) {
LOG(RPiAlsc, Warning)
<< "No ALSC status found for applied gains!";
for (int y = 0; y < Y; y++)
for (int x = 0; x < X; x++) {
- alsc_status.r[y][x] = 1.0;
- alsc_status.g[y][x] = 1.0;
- alsc_status.b[y][x] = 1.0;
+ alscStatus.r[y][x] = 1.0;
+ alscStatus.g[y][x] = 1.0;
+ alscStatus.b[y][x] = 1.0;
}
}
- copy_stats(statistics_, stats, alsc_status);
- frame_phase_ = 0;
- async_started_ = true;
+ copyStats(statistics_, stats, alscStatus);
+ framePhase_ = 0;
+ asyncStarted_ = true;
{
std::lock_guard<std::mutex> lock(mutex_);
- async_start_ = true;
+ asyncStart_ = true;
}
- async_signal_.notify_one();
+ asyncSignal_.notify_one();
}
-void Alsc::Prepare(Metadata *image_metadata)
+void Alsc::prepare(Metadata *imageMetadata)
{
// Count frames since we started, and since we last poked the async
// thread.
- if (frame_count_ < (int)config_.startup_frames)
- frame_count_++;
- double speed = frame_count_ < (int)config_.startup_frames
+ if (frameCount_ < (int)config_.startupFrames)
+ frameCount_++;
+ double speed = frameCount_ < (int)config_.startupFrames
? 1.0
: config_.speed;
LOG(RPiAlsc, Debug)
- << "frame_count " << frame_count_ << " speed " << speed;
+ << "frame count " << frameCount_ << " speed " << speed;
{
std::unique_lock<std::mutex> lock(mutex_);
- if (async_started_ && async_finished_)
+ if (asyncStarted_ && asyncFinished_)
fetchAsyncResults();
}
// Apply IIR filter to results and program into the pipeline.
- double *ptr = (double *)sync_results_,
- *pptr = (double *)prev_sync_results_;
- for (unsigned int i = 0;
- i < sizeof(sync_results_) / sizeof(double); i++)
+ double *ptr = (double *)syncResults_,
+ *pptr = (double *)prevSyncResults_;
+ for (unsigned int i = 0; i < sizeof(syncResults_) / sizeof(double); i++)
pptr[i] = speed * ptr[i] + (1.0 - speed) * pptr[i];
// Put output values into status metadata.
AlscStatus status;
- memcpy(status.r, prev_sync_results_[0], sizeof(status.r));
- memcpy(status.g, prev_sync_results_[1], sizeof(status.g));
- memcpy(status.b, prev_sync_results_[2], sizeof(status.b));
- image_metadata->Set("alsc.status", status);
+ memcpy(status.r, prevSyncResults_[0], sizeof(status.r));
+ memcpy(status.g, prevSyncResults_[1], sizeof(status.g));
+ memcpy(status.b, prevSyncResults_[2], sizeof(status.b));
+ imageMetadata->set("alsc.status", status);
}
-void Alsc::Process(StatisticsPtr &stats, Metadata *image_metadata)
+void Alsc::process(StatisticsPtr &stats, Metadata *imageMetadata)
{
// Count frames since we started, and since we last poked the async
// thread.
- if (frame_phase_ < (int)config_.frame_period)
- frame_phase_++;
- if (frame_count2_ < (int)config_.startup_frames)
- frame_count2_++;
- LOG(RPiAlsc, Debug) << "frame_phase " << frame_phase_;
- if (frame_phase_ >= (int)config_.frame_period ||
- frame_count2_ < (int)config_.startup_frames) {
- if (async_started_ == false)
- restartAsync(stats, image_metadata);
+ if (framePhase_ < (int)config_.framePeriod)
+ framePhase_++;
+ if (frameCount2_ < (int)config_.startupFrames)
+ frameCount2_++;
+ LOG(RPiAlsc, Debug) << "frame_phase " << framePhase_;
+ if (framePhase_ >= (int)config_.framePeriod ||
+ frameCount2_ < (int)config_.startupFrames) {
+ if (asyncStarted_ == false)
+ restartAsync(stats, imageMetadata);
}
}
@@ -375,143 +365,140 @@ void Alsc::asyncFunc()
while (true) {
{
std::unique_lock<std::mutex> lock(mutex_);
- async_signal_.wait(lock, [&] {
- return async_start_ || async_abort_;
+ asyncSignal_.wait(lock, [&] {
+ return asyncStart_ || asyncAbort_;
});
- async_start_ = false;
- if (async_abort_)
+ asyncStart_ = false;
+ if (asyncAbort_)
break;
}
doAlsc();
{
std::lock_guard<std::mutex> lock(mutex_);
- async_finished_ = true;
+ asyncFinished_ = true;
}
- sync_signal_.notify_one();
+ syncSignal_.notify_one();
}
}
-void get_cal_table(double ct, std::vector<AlscCalibration> const &calibrations,
- double cal_table[XY])
+void getCalTable(double ct, std::vector<AlscCalibration> const &calibrations,
+ double calTable[XY])
{
if (calibrations.empty()) {
for (int i = 0; i < XY; i++)
- cal_table[i] = 1.0;
+ calTable[i] = 1.0;
LOG(RPiAlsc, Debug) << "no calibrations found";
} else if (ct <= calibrations.front().ct) {
- memcpy(cal_table, calibrations.front().table,
- XY * sizeof(double));
+ memcpy(calTable, calibrations.front().table, XY * sizeof(double));
LOG(RPiAlsc, Debug) << "using calibration for "
<< calibrations.front().ct;
} else if (ct >= calibrations.back().ct) {
- memcpy(cal_table, calibrations.back().table,
- XY * sizeof(double));
+ memcpy(calTable, calibrations.back().table, XY * sizeof(double));
LOG(RPiAlsc, Debug) << "using calibration for "
<< calibrations.back().ct;
} else {
int idx = 0;
while (ct > calibrations[idx + 1].ct)
idx++;
- double ct0 = calibrations[idx].ct,
- ct1 = calibrations[idx + 1].ct;
+ double ct0 = calibrations[idx].ct, ct1 = calibrations[idx + 1].ct;
LOG(RPiAlsc, Debug)
<< "ct is " << ct << ", interpolating between "
<< ct0 << " and " << ct1;
for (int i = 0; i < XY; i++)
- cal_table[i] =
+ calTable[i] =
(calibrations[idx].table[i] * (ct1 - ct) +
calibrations[idx + 1].table[i] * (ct - ct0)) /
(ct1 - ct0);
}
}
-void resample_cal_table(double const cal_table_in[XY],
- CameraMode const &camera_mode, double cal_table_out[XY])
+void resampleCalTable(double const calTableIn[XY],
+ CameraMode const &cameraMode, double calTableOut[XY])
{
// Precalculate and cache the x sampling locations and phases to save
// recomputing them on every row.
- int x_lo[X], x_hi[X];
+ int xLo[X], xHi[X];
double xf[X];
- double scale_x = camera_mode.sensor_width /
- (camera_mode.width * camera_mode.scale_x);
- double x_off = camera_mode.crop_x / (double)camera_mode.sensor_width;
- double x = .5 / scale_x + x_off * X - .5;
- double x_inc = 1 / scale_x;
- for (int i = 0; i < X; i++, x += x_inc) {
- x_lo[i] = floor(x);
- xf[i] = x - x_lo[i];
- x_hi[i] = std::min(x_lo[i] + 1, X - 1);
- x_lo[i] = std::max(x_lo[i], 0);
- if (!!(camera_mode.transform & libcamera::Transform::HFlip)) {
- x_lo[i] = X - 1 - x_lo[i];
- x_hi[i] = X - 1 - x_hi[i];
+ double scaleX = cameraMode.sensorWidth /
+ (cameraMode.width * cameraMode.scaleX);
+ double xOff = cameraMode.cropX / (double)cameraMode.sensorWidth;
+ double x = .5 / scaleX + xOff * X - .5;
+ double xInc = 1 / scaleX;
+ for (int i = 0; i < X; i++, x += xInc) {
+ xLo[i] = floor(x);
+ xf[i] = x - xLo[i];
+ xHi[i] = std::min(xLo[i] + 1, X - 1);
+ xLo[i] = std::max(xLo[i], 0);
+ if (!!(cameraMode.transform & libcamera::Transform::HFlip)) {
+ xLo[i] = X - 1 - xLo[i];
+ xHi[i] = X - 1 - xHi[i];
}
}
// Now march over the output table generating the new values.
- double scale_y = camera_mode.sensor_height /
- (camera_mode.height * camera_mode.scale_y);
- double y_off = camera_mode.crop_y / (double)camera_mode.sensor_height;
- double y = .5 / scale_y + y_off * Y - .5;
- double y_inc = 1 / scale_y;
- for (int j = 0; j < Y; j++, y += y_inc) {
- int y_lo = floor(y);
- double yf = y - y_lo;
- int y_hi = std::min(y_lo + 1, Y - 1);
- y_lo = std::max(y_lo, 0);
- if (!!(camera_mode.transform & libcamera::Transform::VFlip)) {
- y_lo = Y - 1 - y_lo;
- y_hi = Y - 1 - y_hi;
+ double scaleY = cameraMode.sensorHeight /
+ (cameraMode.height * cameraMode.scaleY);
+ double yOff = cameraMode.cropY / (double)cameraMode.sensorHeight;
+ double y = .5 / scaleY + yOff * Y - .5;
+ double yInc = 1 / scaleY;
+ for (int j = 0; j < Y; j++, y += yInc) {
+ int yLo = floor(y);
+ double yf = y - yLo;
+ int yHi = std::min(yLo + 1, Y - 1);
+ yLo = std::max(yLo, 0);
+ if (!!(cameraMode.transform & libcamera::Transform::VFlip)) {
+ yLo = Y - 1 - yLo;
+ yHi = Y - 1 - yHi;
}
- double const *row_above = cal_table_in + X * y_lo;
- double const *row_below = cal_table_in + X * y_hi;
+ double const *rowAbove = calTableIn + X * yLo;
+ double const *rowBelow = calTableIn + X * yHi;
for (int i = 0; i < X; i++) {
- double above = row_above[x_lo[i]] * (1 - xf[i]) +
- row_above[x_hi[i]] * xf[i];
- double below = row_below[x_lo[i]] * (1 - xf[i]) +
- row_below[x_hi[i]] * xf[i];
- *(cal_table_out++) = above * (1 - yf) + below * yf;
+ double above = rowAbove[xLo[i]] * (1 - xf[i]) +
+ rowAbove[xHi[i]] * xf[i];
+ double below = rowBelow[xLo[i]] * (1 - xf[i]) +
+ rowBelow[xHi[i]] * xf[i];
+ *(calTableOut++) = above * (1 - yf) + below * yf;
}
}
}
// Calculate chrominance statistics (R/G and B/G) for each region.
static_assert(XY == AWB_REGIONS, "ALSC/AWB statistics region mismatch");
-static void calculate_Cr_Cb(bcm2835_isp_stats_region *awb_region, double Cr[XY],
- double Cb[XY], uint32_t min_count, uint16_t min_G)
+static void calculateCrCb(bcm2835_isp_stats_region *awbRegion, double cr[XY],
+ double cb[XY], uint32_t minCount, uint16_t minG)
{
for (int i = 0; i < XY; i++) {
- bcm2835_isp_stats_region &zone = awb_region[i];
- if (zone.counted <= min_count ||
- zone.g_sum / zone.counted <= min_G) {
- Cr[i] = Cb[i] = INSUFFICIENT_DATA;
+ bcm2835_isp_stats_region &zone = awbRegion[i];
+ if (zone.counted <= minCount ||
+ zone.g_sum / zone.counted <= minG) {
+ cr[i] = cb[i] = InsufficientData;
continue;
}
- Cr[i] = zone.r_sum / (double)zone.g_sum;
- Cb[i] = zone.b_sum / (double)zone.g_sum;
+ cr[i] = zone.r_sum / (double)zone.g_sum;
+ cb[i] = zone.b_sum / (double)zone.g_sum;
}
}
-static void apply_cal_table(double const cal_table[XY], double C[XY])
+static void applyCalTable(double const calTable[XY], double C[XY])
{
for (int i = 0; i < XY; i++)
- if (C[i] != INSUFFICIENT_DATA)
- C[i] *= cal_table[i];
+ if (C[i] != InsufficientData)
+ C[i] *= calTable[i];
}
-void compensate_lambdas_for_cal(double const cal_table[XY],
- double const old_lambdas[XY],
- double new_lambdas[XY])
+void compensateLambdasForCal(double const calTable[XY],
+ double const oldLambdas[XY],
+ double newLambdas[XY])
{
- double min_new_lambda = std::numeric_limits<double>::max();
+ double minNewLambda = std::numeric_limits<double>::max();
for (int i = 0; i < XY; i++) {
- new_lambdas[i] = old_lambdas[i] * cal_table[i];
- min_new_lambda = std::min(min_new_lambda, new_lambdas[i]);
+ newLambdas[i] = oldLambdas[i] * calTable[i];
+ minNewLambda = std::min(minNewLambda, newLambdas[i]);
}
for (int i = 0; i < XY; i++)
- new_lambdas[i] /= min_new_lambda;
+ newLambdas[i] /= minNewLambda;
}
-[[maybe_unused]] static void print_cal_table(double const C[XY])
+[[maybe_unused]] static void printCalTable(double const C[XY])
{
printf("table: [\n");
for (int j = 0; j < Y; j++) {
@@ -527,31 +514,29 @@ void compensate_lambdas_for_cal(double const cal_table[XY],
// Compute weight out of 1.0 which reflects how similar we wish to make the
// colours of these two regions.
-static double compute_weight(double C_i, double C_j, double sigma)
+static double computeWeight(double Ci, double Cj, double sigma)
{
- if (C_i == INSUFFICIENT_DATA || C_j == INSUFFICIENT_DATA)
+ if (Ci == InsufficientData || Cj == InsufficientData)
return 0;
- double diff = (C_i - C_j) / sigma;
+ double diff = (Ci - Cj) / sigma;
return exp(-diff * diff / 2);
}
// Compute all weights.
-static void compute_W(double const C[XY], double sigma, double W[XY][4])
+static void computeW(double const C[XY], double sigma, double W[XY][4])
{
for (int i = 0; i < XY; i++) {
// Start with neighbour above and go clockwise.
- W[i][0] = i >= X ? compute_weight(C[i], C[i - X], sigma) : 0;
- W[i][1] = i % X < X - 1 ? compute_weight(C[i], C[i + 1], sigma)
- : 0;
- W[i][2] =
- i < XY - X ? compute_weight(C[i], C[i + X], sigma) : 0;
- W[i][3] = i % X ? compute_weight(C[i], C[i - 1], sigma) : 0;
+ W[i][0] = i >= X ? computeWeight(C[i], C[i - X], sigma) : 0;
+ W[i][1] = i % X < X - 1 ? computeWeight(C[i], C[i + 1], sigma) : 0;
+ W[i][2] = i < XY - X ? computeWeight(C[i], C[i + X], sigma) : 0;
+ W[i][3] = i % X ? computeWeight(C[i], C[i - 1], sigma) : 0;
}
}
// Compute M, the large but sparse matrix such that M * lambdas = 0.
-static void construct_M(double const C[XY], double const W[XY][4],
- double M[XY][4])
+static void constructM(double const C[XY], double const W[XY][4],
+ double M[XY][4])
{
double epsilon = 0.001;
for (int i = 0; i < XY; i++) {
@@ -560,108 +545,96 @@ static void construct_M(double const C[XY], double const W[XY][4],
int m = !!(i >= X) + !!(i % X < X - 1) + !!(i < XY - X) +
!!(i % X); // total number of neighbours
// we'll divide the diagonal out straight away
- double diagonal =
- (epsilon + W[i][0] + W[i][1] + W[i][2] + W[i][3]) *
- C[i];
- M[i][0] = i >= X ? (W[i][0] * C[i - X] + epsilon / m * C[i]) /
- diagonal
- : 0;
- M[i][1] = i % X < X - 1
- ? (W[i][1] * C[i + 1] + epsilon / m * C[i]) /
- diagonal
- : 0;
- M[i][2] = i < XY - X
- ? (W[i][2] * C[i + X] + epsilon / m * C[i]) /
- diagonal
- : 0;
- M[i][3] = i % X ? (W[i][3] * C[i - 1] + epsilon / m * C[i]) /
- diagonal
- : 0;
+ double diagonal = (epsilon + W[i][0] + W[i][1] + W[i][2] + W[i][3]) * C[i];
+ M[i][0] = i >= X ? (W[i][0] * C[i - X] + epsilon / m * C[i]) / diagonal : 0;
+ M[i][1] = i % X < X - 1 ? (W[i][1] * C[i + 1] + epsilon / m * C[i]) / diagonal : 0;
+ M[i][2] = i < XY - X ? (W[i][2] * C[i + X] + epsilon / m * C[i]) / diagonal : 0;
+ M[i][3] = i % X ? (W[i][3] * C[i - 1] + epsilon / m * C[i]) / diagonal : 0;
}
}
// In the compute_lambda_ functions, note that the matrix coefficients for the
// left/right neighbours are zero down the left/right edges, so we don't need
// need to test the i value to exclude them.
-static double compute_lambda_bottom(int i, double const M[XY][4],
- double lambda[XY])
+static double computeLambdaBottom(int i, double const M[XY][4],
+ double lambda[XY])
{
return M[i][1] * lambda[i + 1] + M[i][2] * lambda[i + X] +
M[i][3] * lambda[i - 1];
}
-static double compute_lambda_bottom_start(int i, double const M[XY][4],
- double lambda[XY])
+static double computeLambdaBottomStart(int i, double const M[XY][4],
+ double lambda[XY])
{
return M[i][1] * lambda[i + 1] + M[i][2] * lambda[i + X];
}
-static double compute_lambda_interior(int i, double const M[XY][4],
- double lambda[XY])
+static double computeLambdaInterior(int i, double const M[XY][4],
+ double lambda[XY])
{
return M[i][0] * lambda[i - X] + M[i][1] * lambda[i + 1] +
M[i][2] * lambda[i + X] + M[i][3] * lambda[i - 1];
}
-static double compute_lambda_top(int i, double const M[XY][4],
- double lambda[XY])
+static double computeLambdaTop(int i, double const M[XY][4],
+ double lambda[XY])
{
return M[i][0] * lambda[i - X] + M[i][1] * lambda[i + 1] +
M[i][3] * lambda[i - 1];
}
-static double compute_lambda_top_end(int i, double const M[XY][4],
- double lambda[XY])
+static double computeLambdaTopEnd(int i, double const M[XY][4],
+ double lambda[XY])
{
return M[i][0] * lambda[i - X] + M[i][3] * lambda[i - 1];
}
// Gauss-Seidel iteration with over-relaxation.
-static double gauss_seidel2_SOR(double const M[XY][4], double omega,
- double lambda[XY], double lambda_bound)
+static double gaussSeidel2Sor(double const M[XY][4], double omega,
+ double lambda[XY], double lambdaBound)
{
- const double min = 1 - lambda_bound, max = 1 + lambda_bound;
- double old_lambda[XY];
+ const double min = 1 - lambdaBound, max = 1 + lambdaBound;
+ double oldLambda[XY];
int i;
for (i = 0; i < XY; i++)
- old_lambda[i] = lambda[i];
- lambda[0] = compute_lambda_bottom_start(0, M, lambda);
+ oldLambda[i] = lambda[i];
+ lambda[0] = computeLambdaBottomStart(0, M, lambda);
lambda[0] = std::clamp(lambda[0], min, max);
for (i = 1; i < X; i++) {
- lambda[i] = compute_lambda_bottom(i, M, lambda);
+ lambda[i] = computeLambdaBottom(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
}
for (; i < XY - X; i++) {
- lambda[i] = compute_lambda_interior(i, M, lambda);
+ lambda[i] = computeLambdaInterior(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
}
for (; i < XY - 1; i++) {
- lambda[i] = compute_lambda_top(i, M, lambda);
+ lambda[i] = computeLambdaTop(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
}
- lambda[i] = compute_lambda_top_end(i, M, lambda);
+ lambda[i] = computeLambdaTopEnd(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
// Also solve the system from bottom to top, to help spread the updates
// better.
- lambda[i] = compute_lambda_top_end(i, M, lambda);
+ lambda[i] = computeLambdaTopEnd(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
for (i = XY - 2; i >= XY - X; i--) {
- lambda[i] = compute_lambda_top(i, M, lambda);
+ lambda[i] = computeLambdaTop(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
}
for (; i >= X; i--) {
- lambda[i] = compute_lambda_interior(i, M, lambda);
+ lambda[i] = computeLambdaInterior(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
}
for (; i >= 1; i--) {
- lambda[i] = compute_lambda_bottom(i, M, lambda);
+ lambda[i] = computeLambdaBottom(i, M, lambda);
lambda[i] = std::clamp(lambda[i], min, max);
}
- lambda[0] = compute_lambda_bottom_start(0, M, lambda);
+ lambda[0] = computeLambdaBottomStart(0, M, lambda);
lambda[0] = std::clamp(lambda[0], min, max);
- double max_diff = 0;
+ double maxDiff = 0;
for (i = 0; i < XY; i++) {
- lambda[i] = old_lambda[i] + (lambda[i] - old_lambda[i]) * omega;
- if (fabs(lambda[i] - old_lambda[i]) > fabs(max_diff))
- max_diff = lambda[i] - old_lambda[i];
+ lambda[i] = oldLambda[i] + (lambda[i] - oldLambda[i]) * omega;
+ if (fabs(lambda[i] - oldLambda[i]) > fabs(maxDiff))
+ maxDiff = lambda[i] - oldLambda[i];
}
- return max_diff;
+ return maxDiff;
}
// Normalise the values so that the smallest value is 1.
@@ -683,105 +656,99 @@ static void reaverage(Span<double> data)
d *= ratio;
}
-static void run_matrix_iterations(double const C[XY], double lambda[XY],
- double const W[XY][4], double omega,
- int n_iter, double threshold, double lambda_bound)
+static void runMatrixIterations(double const C[XY], double lambda[XY],
+ double const W[XY][4], double omega,
+ int nIter, double threshold, double lambdaBound)
{
double M[XY][4];
- construct_M(C, W, M);
- double last_max_diff = std::numeric_limits<double>::max();
- for (int i = 0; i < n_iter; i++) {
- double max_diff = fabs(gauss_seidel2_SOR(M, omega, lambda, lambda_bound));
- if (max_diff < threshold) {
+ constructM(C, W, M);
+ double lastMaxDiff = std::numeric_limits<double>::max();
+ for (int i = 0; i < nIter; i++) {
+ double maxDiff = fabs(gaussSeidel2Sor(M, omega, lambda, lambdaBound));
+ if (maxDiff < threshold) {
LOG(RPiAlsc, Debug)
<< "Stop after " << i + 1 << " iterations";
break;
}
// this happens very occasionally (so make a note), though
// doesn't seem to matter
- if (max_diff > last_max_diff)
+ if (maxDiff > lastMaxDiff)
LOG(RPiAlsc, Debug)
- << "Iteration " << i << ": max_diff gone up "
- << last_max_diff << " to " << max_diff;
- last_max_diff = max_diff;
+ << "Iteration " << i << ": maxDiff gone up "
+ << lastMaxDiff << " to " << maxDiff;
+ lastMaxDiff = maxDiff;
}
// We're going to normalise the lambdas so the total average is 1.
reaverage({ lambda, XY });
}
-static void add_luminance_rb(double result[XY], double const lambda[XY],
- double const luminance_lut[XY],
- double luminance_strength)
+static void addLuminanceRb(double result[XY], double const lambda[XY],
+ double const luminanceLut[XY],
+ double luminanceStrength)
{
for (int i = 0; i < XY; i++)
- result[i] = lambda[i] *
- ((luminance_lut[i] - 1) * luminance_strength + 1);
+ result[i] = lambda[i] * ((luminanceLut[i] - 1) * luminanceStrength + 1);
}
-static void add_luminance_g(double result[XY], double lambda,
- double const luminance_lut[XY],
- double luminance_strength)
+static void addLuminanceG(double result[XY], double lambda,
+ double const luminanceLut[XY],
+ double luminanceStrength)
{
for (int i = 0; i < XY; i++)
- result[i] = lambda *
- ((luminance_lut[i] - 1) * luminance_strength + 1);
+ result[i] = lambda * ((luminanceLut[i] - 1) * luminanceStrength + 1);
}
-void add_luminance_to_tables(double results[3][Y][X], double const lambda_r[XY],
- double lambda_g, double const lambda_b[XY],
- double const luminance_lut[XY],
- double luminance_strength)
+void addLuminanceToTables(double results[3][Y][X], double const lambdaR[XY],
+ double lambdaG, double const lambdaB[XY],
+ double const luminanceLut[XY],
+ double luminanceStrength)
{
- add_luminance_rb((double *)results[0], lambda_r, luminance_lut,
- luminance_strength);
- add_luminance_g((double *)results[1], lambda_g, luminance_lut,
- luminance_strength);
- add_luminance_rb((double *)results[2], lambda_b, luminance_lut,
- luminance_strength);
+ addLuminanceRb((double *)results[0], lambdaR, luminanceLut, luminanceStrength);
+ addLuminanceG((double *)results[1], lambdaG, luminanceLut, luminanceStrength);
+ addLuminanceRb((double *)results[2], lambdaB, luminanceLut, luminanceStrength);
normalise((double *)results, 3 * XY);
}
void Alsc::doAlsc()
{
- double Cr[XY], Cb[XY], Wr[XY][4], Wb[XY][4], cal_table_r[XY],
- cal_table_b[XY], cal_table_tmp[XY];
+ double cr[XY], cb[XY], wr[XY][4], wb[XY][4], calTableR[XY], calTableB[XY], calTableTmp[XY];
// Calculate our R/B ("Cr"/"Cb") colour statistics, and assess which are
// usable.
- calculate_Cr_Cb(statistics_, Cr, Cb, config_.min_count, config_.min_G);
+ calculateCrCb(statistics_, cr, cb, config_.minCount, config_.minG);
// Fetch the new calibrations (if any) for this CT. Resample them in
// case the camera mode is not full-frame.
- get_cal_table(ct_, config_.calibrations_Cr, cal_table_tmp);
- resample_cal_table(cal_table_tmp, camera_mode_, cal_table_r);
- get_cal_table(ct_, config_.calibrations_Cb, cal_table_tmp);
- resample_cal_table(cal_table_tmp, camera_mode_, cal_table_b);
+ getCalTable(ct_, config_.calibrationsCr, calTableTmp);
+ resampleCalTable(calTableTmp, cameraMode_, calTableR);
+ getCalTable(ct_, config_.calibrationsCb, calTableTmp);
+ resampleCalTable(calTableTmp, cameraMode_, calTableB);
// You could print out the cal tables for this image here, if you're
// tuning the algorithm...
// Apply any calibration to the statistics, so the adaptive algorithm
// makes only the extra adjustments.
- apply_cal_table(cal_table_r, Cr);
- apply_cal_table(cal_table_b, Cb);
+ applyCalTable(calTableR, cr);
+ applyCalTable(calTableB, cb);
// Compute weights between zones.
- compute_W(Cr, config_.sigma_Cr, Wr);
- compute_W(Cb, config_.sigma_Cb, Wb);
+ computeW(cr, config_.sigmaCr, wr);
+ computeW(cb, config_.sigmaCb, wb);
// Run Gauss-Seidel iterations over the resulting matrix, for R and B.
- run_matrix_iterations(Cr, lambda_r_, Wr, config_.omega, config_.n_iter,
- config_.threshold, config_.lambda_bound);
- run_matrix_iterations(Cb, lambda_b_, Wb, config_.omega, config_.n_iter,
- config_.threshold, config_.lambda_bound);
+ runMatrixIterations(cr, lambdaR_, wr, config_.omega, config_.nIter,
+ config_.threshold, config_.lambdaBound);
+ runMatrixIterations(cb, lambdaB_, wb, config_.omega, config_.nIter,
+ config_.threshold, config_.lambdaBound);
// Fold the calibrated gains into our final lambda values. (Note that on
// the next run, we re-start with the lambda values that don't have the
// calibration gains included.)
- compensate_lambdas_for_cal(cal_table_r, lambda_r_, async_lambda_r_);
- compensate_lambdas_for_cal(cal_table_b, lambda_b_, async_lambda_b_);
+ compensateLambdasForCal(calTableR, lambdaR_, asyncLambdaR_);
+ compensateLambdasForCal(calTableB, lambdaB_, asyncLambdaB_);
// Fold in the luminance table at the appropriate strength.
- add_luminance_to_tables(async_results_, async_lambda_r_, 1.0,
- async_lambda_b_, luminance_table_,
- config_.luminance_strength);
+ addLuminanceToTables(asyncResults_, asyncLambdaR_, 1.0,
+ asyncLambdaB_, luminanceTable_,
+ config_.luminanceStrength);
}
// Register algorithm with the system.
-static Algorithm *Create(Controller *controller)
+static Algorithm *create(Controller *controller)
{
return (Algorithm *)new Alsc(controller);
}
-static RegisterAlgorithm reg(NAME, &Create);
+static RegisterAlgorithm reg(NAME, &create);