Message ID | 20220725134639.4572-8-naush@raspberrypi.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi Naush, Thank you for the patch. On Mon, Jul 25, 2022 at 02:46:31PM +0100, Naushir Patuck via libcamera-devel wrote: > Refactor the source files under src/ipa/raspberrypi/controller/rpi/a* to match the > recommended formatting guidelines for the libcamera project. The vast majority > of changes in this commit comprise of switching from snake_case to CamelCase, > and starting class member functions with a lower case character. > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com> One is enough. > --- > src/ipa/raspberrypi/controller/rpi/agc.cpp | 722 ++++++++++---------- > src/ipa/raspberrypi/controller/rpi/agc.hpp | 130 ++-- > src/ipa/raspberrypi/controller/rpi/alsc.cpp | 639 ++++++++--------- > src/ipa/raspberrypi/controller/rpi/alsc.hpp | 86 +-- > src/ipa/raspberrypi/controller/rpi/awb.cpp | 562 ++++++++------- > src/ipa/raspberrypi/controller/rpi/awb.hpp | 110 +-- > 6 files changed, 1089 insertions(+), 1160 deletions(-) > > diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp > index f6a9cb0a2cd8..738cf56c6be0 100644 > --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp > +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp > @@ -30,7 +30,7 @@ LOG_DEFINE_CATEGORY(RPiAgc) > > #define PIPELINE_BITS 13 // seems to be a 13-bit pipeline This could also be switched to static constexpr. > -void AgcMeteringMode::Read(boost::property_tree::ptree const ¶ms) > +void AgcMeteringMode::read(boost::property_tree::ptree const ¶ms) > { > int num = 0; > for (auto &p : params.get_child("weights")) { > @@ -43,265 +43,260 @@ void AgcMeteringMode::Read(boost::property_tree::ptree const ¶ms) > } > > static std::string > -read_metering_modes(std::map<std::string, AgcMeteringMode> &metering_modes, > - boost::property_tree::ptree const ¶ms) > +readMeteringModes(std::map<std::string, AgcMeteringMode> &meteringModes, > + boost::property_tree::ptree const ¶ms) > { > std::string first; > for (auto &p : params) { > - AgcMeteringMode metering_mode; > - metering_mode.Read(p.second); > - metering_modes[p.first] = std::move(metering_mode); > + AgcMeteringMode meteringMode; > + meteringMode.read(p.second); > + meteringModes[p.first] = std::move(meteringMode); > if (first.empty()) > first = p.first; > } > return first; > } > > -static int read_list(std::vector<double> &list, > - boost::property_tree::ptree const ¶ms) > +static int readList(std::vector<double> &list, > + boost::property_tree::ptree const ¶ms) > { > for (auto &p : params) > list.push_back(p.second.get_value<double>()); > return list.size(); > } > > -static int read_list(std::vector<Duration> &list, > - boost::property_tree::ptree const ¶ms) > +static int readList(std::vector<Duration> &list, > + boost::property_tree::ptree const ¶ms) > { > for (auto &p : params) > list.push_back(p.second.get_value<double>() * 1us); > return list.size(); > } > > -void AgcExposureMode::Read(boost::property_tree::ptree const ¶ms) > +void AgcExposureMode::read(boost::property_tree::ptree const ¶ms) > { > - int num_shutters = read_list(shutter, params.get_child("shutter")); > - int num_ags = read_list(gain, params.get_child("gain")); > - if (num_shutters < 2 || num_ags < 2) > + int numShutters = readList(shutter, params.get_child("shutter")); > + int numAgs = readList(gain, params.get_child("gain")); > + if (numShutters < 2 || numAgs < 2) > throw std::runtime_error( > "AgcConfig: must have at least two entries in exposure profile"); > - if (num_shutters != num_ags) > + if (numShutters != numAgs) > throw std::runtime_error( > "AgcConfig: expect same number of exposure and gain entries in exposure profile"); > } > > static std::string > -read_exposure_modes(std::map<std::string, AgcExposureMode> &exposure_modes, > - boost::property_tree::ptree const ¶ms) > +readExposureModes(std::map<std::string, AgcExposureMode> &exposureModes, > + boost::property_tree::ptree const ¶ms) > { > std::string first; > for (auto &p : params) { > - AgcExposureMode exposure_mode; > - exposure_mode.Read(p.second); > - exposure_modes[p.first] = std::move(exposure_mode); > + AgcExposureMode exposureMode; > + exposureMode.read(p.second); > + exposureModes[p.first] = std::move(exposureMode); > if (first.empty()) > first = p.first; > } > return first; > } > > -void AgcConstraint::Read(boost::property_tree::ptree const ¶ms) > +void AgcConstraint::read(boost::property_tree::ptree const ¶ms) > { > - std::string bound_string = params.get<std::string>("bound", ""); > - transform(bound_string.begin(), bound_string.end(), > - bound_string.begin(), ::toupper); > - if (bound_string != "UPPER" && bound_string != "LOWER") > + std::string boundString = params.get<std::string>("bound", ""); > + transform(boundString.begin(), boundString.end(), > + boundString.begin(), ::toupper); > + if (boundString != "UPPER" && boundString != "LOWER") > throw std::runtime_error( > "AGC constraint type should be UPPER or LOWER"); > - bound = bound_string == "UPPER" ? Bound::UPPER : Bound::LOWER; > - q_lo = params.get<double>("q_lo"); > - q_hi = params.get<double>("q_hi"); > - Y_target.Read(params.get_child("y_target")); > + bound = boundString == "UPPER" ? Bound::UPPER : Bound::LOWER; > + qLo = params.get<double>("q_lo"); > + qHi = params.get<double>("q_hi"); > + yTarget.read(params.get_child("y_target")); > } > > static AgcConstraintMode > -read_constraint_mode(boost::property_tree::ptree const ¶ms) > +readConstraintMode(boost::property_tree::ptree const ¶ms) > { > AgcConstraintMode mode; > for (auto &p : params) { > AgcConstraint constraint; > - constraint.Read(p.second); > + constraint.read(p.second); > mode.push_back(std::move(constraint)); > } > return mode; > } > > -static std::string read_constraint_modes( > - std::map<std::string, AgcConstraintMode> &constraint_modes, > - boost::property_tree::ptree const ¶ms) > +static std::string readConstraintModes(std::map<std::string, AgcConstraintMode> &constraintModes, > + boost::property_tree::ptree const ¶ms) > { > std::string first; > for (auto &p : params) { > - constraint_modes[p.first] = read_constraint_mode(p.second); > + constraintModes[p.first] = readConstraintMode(p.second); > if (first.empty()) > first = p.first; > } > return first; > } > > -void AgcConfig::Read(boost::property_tree::ptree const ¶ms) > +void AgcConfig::read(boost::property_tree::ptree const ¶ms) > { > LOG(RPiAgc, Debug) << "AgcConfig"; > - default_metering_mode = read_metering_modes( > - metering_modes, params.get_child("metering_modes")); > - default_exposure_mode = read_exposure_modes( > - exposure_modes, params.get_child("exposure_modes")); > - default_constraint_mode = read_constraint_modes( > - constraint_modes, params.get_child("constraint_modes")); > - Y_target.Read(params.get_child("y_target")); > + defaultMeteringMode = readMeteringModes(meteringModes, params.get_child("metering_modes")); > + defaultExposureMode = readExposureModes(exposureModes, params.get_child("exposure_modes")); > + defaultConstraintMode = readConstraintModes(constraintModes, params.get_child("constraint_modes")); > + yTarget.read(params.get_child("y_target")); > speed = params.get<double>("speed", 0.2); > - startup_frames = params.get<uint16_t>("startup_frames", 10); > - convergence_frames = params.get<unsigned int>("convergence_frames", 6); > - fast_reduce_threshold = > - params.get<double>("fast_reduce_threshold", 0.4); > - base_ev = params.get<double>("base_ev", 1.0); > + startupFrames = params.get<uint16_t>("startup_frames", 10); > + convergenceFrames = params.get<unsigned int>("convergence_frames", 6); > + fastReduceThreshold = params.get<double>("fast_reduce_threshold", 0.4); > + baseEv = params.get<double>("base_ev", 1.0); > // Start with quite a low value as ramping up is easier than ramping down. > - default_exposure_time = params.get<double>("default_exposure_time", 1000) * 1us; > - default_analogue_gain = params.get<double>("default_analogue_gain", 1.0); > + defaultExposureTime = params.get<double>("default_exposure_time", 1000) * 1us; > + defaultAnalogueGain = params.get<double>("default_analogueGain", 1.0); > } > > Agc::ExposureValues::ExposureValues() > - : shutter(0s), analogue_gain(0), > - total_exposure(0s), total_exposure_no_dg(0s) > + : shutter(0s), analogueGain(0), > + totalExposure(0s), totalExposureNoDG(0s) > { > } > > Agc::Agc(Controller *controller) > - : AgcAlgorithm(controller), metering_mode_(nullptr), > - exposure_mode_(nullptr), constraint_mode_(nullptr), > - frame_count_(0), lock_count_(0), > - last_target_exposure_(0s), last_sensitivity_(0.0), > - ev_(1.0), flicker_period_(0s), > - max_shutter_(0s), fixed_shutter_(0s), fixed_analogue_gain_(0.0) > + : AgcAlgorithm(controller), meteringMode_(nullptr), > + exposureMode_(nullptr), constraintMode_(nullptr), > + frameCount_(0), lockCount_(0), > + lastTargetExposure_(0s), lastSensitivity_(0.0), > + ev_(1.0), flickerPeriod_(0s), > + maxShutter_(0s), fixedShutter_(0s), fixedAnalogueGain_(0.0) > { > memset(&awb_, 0, sizeof(awb_)); > - // Setting status_.total_exposure_value_ to zero initially tells us > + // Setting status_.totalExposureValue_ to zero initially tells us > // it's not been calculated yet (i.e. Process hasn't yet run). > memset(&status_, 0, sizeof(status_)); > status_.ev = ev_; > } > > -char const *Agc::Name() const > +char const *Agc::name() const > { > return NAME; > } > > -void Agc::Read(boost::property_tree::ptree const ¶ms) > +void Agc::read(boost::property_tree::ptree const ¶ms) > { > LOG(RPiAgc, Debug) << "Agc"; > - config_.Read(params); > + config_.read(params); > // Set the config's defaults (which are the first ones it read) as our > // current modes, until someone changes them. (they're all known to > // exist at this point) > - metering_mode_name_ = config_.default_metering_mode; > - metering_mode_ = &config_.metering_modes[metering_mode_name_]; > - exposure_mode_name_ = config_.default_exposure_mode; > - exposure_mode_ = &config_.exposure_modes[exposure_mode_name_]; > - constraint_mode_name_ = config_.default_constraint_mode; > - constraint_mode_ = &config_.constraint_modes[constraint_mode_name_]; > + meteringModeName_ = config_.defaultMeteringMode; > + meteringMode_ = &config_.meteringModes[meteringModeName_]; > + exposureModeName_ = config_.defaultExposureMode; > + exposureMode_ = &config_.exposureModes[exposureModeName_]; > + constraintModeName_ = config_.defaultConstraintMode; > + constraintMode_ = &config_.constraintModes[constraintModeName_]; > // Set up the "last shutter/gain" values, in case AGC starts "disabled". > - status_.shutter_time = config_.default_exposure_time; > - status_.analogue_gain = config_.default_analogue_gain; > + status_.shutterTime = config_.defaultExposureTime; > + status_.analogueGain = config_.defaultAnalogueGain; > } > > -bool Agc::IsPaused() const > +bool Agc::isPaused() const > { > return false; > } > > -void Agc::Pause() > +void Agc::pause() > { > - fixed_shutter_ = status_.shutter_time; > - fixed_analogue_gain_ = status_.analogue_gain; > + fixedShutter_ = status_.shutterTime; > + fixedAnalogueGain_ = status_.analogueGain; > } > > -void Agc::Resume() > +void Agc::resume() > { > - fixed_shutter_ = 0s; > - fixed_analogue_gain_ = 0; > + fixedShutter_ = 0s; > + fixedAnalogueGain_ = 0; > } > > -unsigned int Agc::GetConvergenceFrames() const > +unsigned int Agc::getConvergenceFrames() const > { > // If shutter and gain have been explicitly set, there is no > // convergence to happen, so no need to drop any frames - return zero. > - if (fixed_shutter_ && fixed_analogue_gain_) > + if (fixedShutter_ && fixedAnalogueGain_) > return 0; > else > - return config_.convergence_frames; > + return config_.convergenceFrames; > } > > -void Agc::SetEv(double ev) > +void Agc::setEv(double ev) > { > ev_ = ev; > } > > -void Agc::SetFlickerPeriod(Duration flicker_period) > +void Agc::setFlickerPeriod(Duration flickerPeriod) > { > - flicker_period_ = flicker_period; > + flickerPeriod_ = flickerPeriod; > } > > -void Agc::SetMaxShutter(Duration max_shutter) > +void Agc::setMaxShutter(Duration maxShutter) > { > - max_shutter_ = max_shutter; > + maxShutter_ = maxShutter; > } > > -void Agc::SetFixedShutter(Duration fixed_shutter) > +void Agc::setFixedShutter(Duration fixedShutter) > { > - fixed_shutter_ = fixed_shutter; > + fixedShutter_ = fixedShutter; > // Set this in case someone calls Pause() straight after. > - status_.shutter_time = clipShutter(fixed_shutter_); > + status_.shutterTime = clipShutter(fixedShutter_); > } > > -void Agc::SetFixedAnalogueGain(double fixed_analogue_gain) > +void Agc::setFixedAnalogueGain(double fixedAnalogueGain) > { > - fixed_analogue_gain_ = fixed_analogue_gain; > + fixedAnalogueGain_ = fixedAnalogueGain_; > // Set this in case someone calls Pause() straight after. > - status_.analogue_gain = fixed_analogue_gain; > + status_.analogueGain = fixedAnalogueGain; > } > > -void Agc::SetMeteringMode(std::string const &metering_mode_name) > +void Agc::setMeteringMode(std::string const &meteringModeName) > { > - metering_mode_name_ = metering_mode_name; > + meteringModeName_ = meteringModeName; > } > > -void Agc::SetExposureMode(std::string const &exposure_mode_name) > +void Agc::setExposureMode(std::string const &exposureModeName) > { > - exposure_mode_name_ = exposure_mode_name; > + exposureModeName_ = exposureModeName; > } > > -void Agc::SetConstraintMode(std::string const &constraint_mode_name) > +void Agc::setConstraintMode(std::string const &constraintModeName) > { > - constraint_mode_name_ = constraint_mode_name; > + constraintModeName_ = constraintModeName; > } > > -void Agc::SwitchMode(CameraMode const &camera_mode, > +void Agc::switchMode(CameraMode const &cameraMode, > Metadata *metadata) > { > /* AGC expects the mode sensitivity always to be non-zero. */ > - ASSERT(camera_mode.sensitivity); > + ASSERT(cameraMode.sensitivity); > > housekeepConfig(); > > - Duration fixed_shutter = clipShutter(fixed_shutter_); > - if (fixed_shutter && fixed_analogue_gain_) { > + Duration fixedShutter = clipShutter(fixedShutter_); > + if (fixedShutter && fixedAnalogueGain_) { > // We're going to reset the algorithm here with these fixed values. > > fetchAwbStatus(metadata); > - double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 }); > - ASSERT(min_colour_gain != 0.0); > + double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 }); > + ASSERT(minColourGain != 0.0); > > // This is the equivalent of computeTargetExposure and applyDigitalGain. > - target_.total_exposure_no_dg = fixed_shutter * fixed_analogue_gain_; > - target_.total_exposure = target_.total_exposure_no_dg / min_colour_gain; > + target_.totalExposureNoDG = fixedShutter_ * fixedAnalogueGain_; > + target_.totalExposure = target_.totalExposureNoDG / minColourGain; > > // Equivalent of filterExposure. This resets any "history". > filtered_ = target_; > > // Equivalent of divideUpExposure. > - filtered_.shutter = fixed_shutter; > - filtered_.analogue_gain = fixed_analogue_gain_; > - } else if (status_.total_exposure_value) { > + filtered_.shutter = fixedShutter; > + filtered_.analogueGain = fixedAnalogueGain_; > + } else if (status_.totalExposureValue) { > // On a mode switch, various things could happen: > // - the exposure profile might change > // - a fixed exposure or gain might be set > @@ -310,11 +305,11 @@ void Agc::SwitchMode(CameraMode const &camera_mode, > // that we just need to re-divide the exposure/gain according to the > // current exposure profile, which takes care of everything else. > > - double ratio = last_sensitivity_ / camera_mode.sensitivity; > - target_.total_exposure_no_dg *= ratio; > - target_.total_exposure *= ratio; > - filtered_.total_exposure_no_dg *= ratio; > - filtered_.total_exposure *= ratio; > + double ratio = lastSensitivity_ / cameraMode.sensitivity; > + target_.totalExposureNoDG *= ratio; > + target_.totalExposure *= ratio; > + filtered_.totalExposureNoDG *= ratio; > + filtered_.totalExposure *= ratio; > > divideUpExposure(); > } else { > @@ -324,114 +319,110 @@ void Agc::SwitchMode(CameraMode const &camera_mode, > // for any that weren't set. > > // Equivalent of divideUpExposure. > - filtered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time; > - filtered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain; > + filtered_.shutter = fixedShutter ? fixedShutter : config_.defaultExposureTime; > + filtered_.analogueGain = fixedAnalogueGain_ ? fixedAnalogueGain_ : config_.defaultAnalogueGain; > } > > writeAndFinish(metadata, false); > > // We must remember the sensitivity of this mode for the next SwitchMode. > - last_sensitivity_ = camera_mode.sensitivity; > + lastSensitivity_ = cameraMode.sensitivity; > } > > -void Agc::Prepare(Metadata *image_metadata) > +void Agc::prepare(Metadata *imageMetadata) > { > - status_.digital_gain = 1.0; > - fetchAwbStatus(image_metadata); // always fetch it so that Process knows it's been done > + status_.digitalGain = 1.0; > + fetchAwbStatus(imageMetadata); // always fetch it so that Process knows it's been done > > - if (status_.total_exposure_value) { > + if (status_.totalExposureValue) { > // Process has run, so we have meaningful values. > - DeviceStatus device_status; > - if (image_metadata->Get("device.status", device_status) == 0) { > - Duration actual_exposure = device_status.shutter_speed * > - device_status.analogue_gain; > - if (actual_exposure) { > - status_.digital_gain = > - status_.total_exposure_value / > - actual_exposure; > - LOG(RPiAgc, Debug) << "Want total exposure " << status_.total_exposure_value; > + DeviceStatus deviceStatus; > + if (imageMetadata->get("device.status", deviceStatus) == 0) { > + Duration actualExposure = deviceStatus.shutterSpeed * > + deviceStatus.analogueGain; > + if (actualExposure) { > + status_.digitalGain = status_.totalExposureValue / actualExposure; > + LOG(RPiAgc, Debug) << "Want total exposure " << status_.totalExposureValue; > // Never ask for a gain < 1.0, and also impose > // some upper limit. Make it customisable? > - status_.digital_gain = std::max( > - 1.0, > - std::min(status_.digital_gain, 4.0)); > - LOG(RPiAgc, Debug) << "Actual exposure " << actual_exposure; > - LOG(RPiAgc, Debug) << "Use digital_gain " << status_.digital_gain; > + status_.digitalGain = std::max(1.0, std::min(status_.digitalGain, 4.0)); > + LOG(RPiAgc, Debug) << "Actual exposure " << actualExposure; > + LOG(RPiAgc, Debug) << "Use digital_gain " << status_.digitalGain; s/digital_gain/digitalGain/ > LOG(RPiAgc, Debug) << "Effective exposure " > - << actual_exposure * status_.digital_gain; > + << actualExposure * status_.digitalGain; > // Decide whether AEC/AGC has converged. > - updateLockStatus(device_status); > + updateLockStatus(deviceStatus); > } > } else > - LOG(RPiAgc, Warning) << Name() << ": no device metadata"; > - image_metadata->Set("agc.status", status_); > + LOG(RPiAgc, Warning) << name() << ": no device metadata"; > + imageMetadata->set("agc.status", status_); > } > } > > -void Agc::Process(StatisticsPtr &stats, Metadata *image_metadata) > +void Agc::process(StatisticsPtr &stats, Metadata *imageMetadata) > { > - frame_count_++; > + frameCount_++; > // First a little bit of housekeeping, fetching up-to-date settings and > // configuration, that kind of thing. > housekeepConfig(); > // Get the current exposure values for the frame that's just arrived. > - fetchCurrentExposure(image_metadata); > + fetchCurrentExposure(imageMetadata); > // Compute the total gain we require relative to the current exposure. > - double gain, target_Y; > - computeGain(stats.get(), image_metadata, gain, target_Y); > + double gain, targetY; > + computeGain(stats.get(), imageMetadata, gain, targetY); > // Now compute the target (final) exposure which we think we want. > computeTargetExposure(gain); > // Some of the exposure has to be applied as digital gain, so work out > // what that is. This function also tells us whether it's decided to > // "desaturate" the image more quickly. > - bool desaturate = applyDigitalGain(gain, target_Y); > + bool desaturate = applyDigitalGain(gain, targetY); > // The results have to be filtered so as not to change too rapidly. > filterExposure(desaturate); > // The last thing is to divide up the exposure value into a shutter time > - // and analogue_gain, according to the current exposure mode. > + // and analogue gain, according to the current exposure mode. > divideUpExposure(); > // Finally advertise what we've done. > - writeAndFinish(image_metadata, desaturate); > + writeAndFinish(imageMetadata, desaturate); > } > > -void Agc::updateLockStatus(DeviceStatus const &device_status) > +void Agc::updateLockStatus(DeviceStatus const &deviceStatus) > { > - const double ERROR_FACTOR = 0.10; // make these customisable? > - const int MAX_LOCK_COUNT = 5; > - // Reset "lock count" when we exceed this multiple of ERROR_FACTOR > - const double RESET_MARGIN = 1.5; > + const double errorFactor = 0.10; // make these customisable? > + const int maxLockCount = 5; > + // Reset "lock count" when we exceed this multiple of errorFactor > + const double resetMargin = 1.5; > > // Add 200us to the exposure time error to allow for line quantisation. > - Duration exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200us; > - double gain_error = last_device_status_.analogue_gain * ERROR_FACTOR; > - Duration target_error = last_target_exposure_ * ERROR_FACTOR; > + Duration exposureError = lastDeviceStatus_.shutterSpeed * errorFactor + 200us; > + double gainError = lastDeviceStatus_.analogueGain * errorFactor; > + Duration targetError = lastTargetExposure_ * errorFactor; > > // Note that we don't know the exposure/gain limits of the sensor, so > // the values we keep requesting may be unachievable. For this reason > // we only insist that we're close to values in the past few frames. > - if (device_status.shutter_speed > last_device_status_.shutter_speed - exposure_error && > - device_status.shutter_speed < last_device_status_.shutter_speed + exposure_error && > - device_status.analogue_gain > last_device_status_.analogue_gain - gain_error && > - device_status.analogue_gain < last_device_status_.analogue_gain + gain_error && > - status_.target_exposure_value > last_target_exposure_ - target_error && > - status_.target_exposure_value < last_target_exposure_ + target_error) > - lock_count_ = std::min(lock_count_ + 1, MAX_LOCK_COUNT); > - else if (device_status.shutter_speed < last_device_status_.shutter_speed - RESET_MARGIN * exposure_error || > - device_status.shutter_speed > last_device_status_.shutter_speed + RESET_MARGIN * exposure_error || > - device_status.analogue_gain < last_device_status_.analogue_gain - RESET_MARGIN * gain_error || > - device_status.analogue_gain > last_device_status_.analogue_gain + RESET_MARGIN * gain_error || > - status_.target_exposure_value < last_target_exposure_ - RESET_MARGIN * target_error || > - status_.target_exposure_value > last_target_exposure_ + RESET_MARGIN * target_error) > - lock_count_ = 0; > - > - last_device_status_ = device_status; > - last_target_exposure_ = status_.target_exposure_value; > - > - LOG(RPiAgc, Debug) << "Lock count updated to " << lock_count_; > - status_.locked = lock_count_ == MAX_LOCK_COUNT; > -} > - > -static void copy_string(std::string const &s, char *d, size_t size) > + if (deviceStatus.shutterSpeed > lastDeviceStatus_.shutterSpeed - exposureError && > + deviceStatus.shutterSpeed < lastDeviceStatus_.shutterSpeed + exposureError && > + deviceStatus.analogueGain > lastDeviceStatus_.analogueGain - gainError && > + deviceStatus.analogueGain < lastDeviceStatus_.analogueGain + gainError && > + status_.targetExposureValue > lastTargetExposure_ - targetError && > + status_.targetExposureValue < lastTargetExposure_ + targetError) > + lockCount_ = std::min(lockCount_ + 1, maxLockCount); > + else if (deviceStatus.shutterSpeed < lastDeviceStatus_.shutterSpeed - resetMargin * exposureError || > + deviceStatus.shutterSpeed > lastDeviceStatus_.shutterSpeed + resetMargin * exposureError || > + deviceStatus.analogueGain < lastDeviceStatus_.analogueGain - resetMargin * gainError || > + deviceStatus.analogueGain > lastDeviceStatus_.analogueGain + resetMargin * gainError || > + status_.targetExposureValue < lastTargetExposure_ - resetMargin * targetError || > + status_.targetExposureValue > lastTargetExposure_ + resetMargin * targetError) > + lockCount_ = 0; > + > + lastDeviceStatus_ = deviceStatus; > + lastTargetExposure_ = status_.targetExposureValue; > + > + LOG(RPiAgc, Debug) << "Lock count updated to " << lockCount_; > + status_.locked = lockCount_ == maxLockCount; > +} > + > +static void copyString(std::string const &s, char *d, size_t size) > { > size_t length = s.copy(d, size - 1); > d[length] = '\0'; > @@ -441,97 +432,97 @@ void Agc::housekeepConfig() > { > // First fetch all the up-to-date settings, so no one else has to do it. > status_.ev = ev_; > - status_.fixed_shutter = clipShutter(fixed_shutter_); > - status_.fixed_analogue_gain = fixed_analogue_gain_; > - status_.flicker_period = flicker_period_; > - LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixed_shutter " > - << status_.fixed_shutter << " fixed_analogue_gain " > - << status_.fixed_analogue_gain; > + status_.fixedShutter = clipShutter(fixedShutter_); > + status_.fixedAnalogueGain = fixedAnalogueGain_; > + status_.flickerPeriod = flickerPeriod_; > + LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixedShutter " > + << status_.fixedShutter << " fixedAnalogueGain " > + << status_.fixedAnalogueGain; > // Make sure the "mode" pointers point to the up-to-date things, if > // they've changed. > - if (strcmp(metering_mode_name_.c_str(), status_.metering_mode)) { > - auto it = config_.metering_modes.find(metering_mode_name_); > - if (it == config_.metering_modes.end()) > + if (strcmp(meteringModeName_.c_str(), status_.meteringMode)) { > + auto it = config_.meteringModes.find(meteringModeName_); > + if (it == config_.meteringModes.end()) > throw std::runtime_error("Agc: no metering mode " + > - metering_mode_name_); > - metering_mode_ = &it->second; > - copy_string(metering_mode_name_, status_.metering_mode, > - sizeof(status_.metering_mode)); > + meteringModeName_); > + meteringMode_ = &it->second; > + copyString(meteringModeName_, status_.meteringMode, > + sizeof(status_.meteringMode)); > } > - if (strcmp(exposure_mode_name_.c_str(), status_.exposure_mode)) { > - auto it = config_.exposure_modes.find(exposure_mode_name_); > - if (it == config_.exposure_modes.end()) > + if (strcmp(exposureModeName_.c_str(), status_.exposureMode)) { > + auto it = config_.exposureModes.find(exposureModeName_); > + if (it == config_.exposureModes.end()) > throw std::runtime_error("Agc: no exposure profile " + > - exposure_mode_name_); > - exposure_mode_ = &it->second; > - copy_string(exposure_mode_name_, status_.exposure_mode, > - sizeof(status_.exposure_mode)); > + exposureModeName_); > + exposureMode_ = &it->second; > + copyString(exposureModeName_, status_.exposureMode, > + sizeof(status_.exposureMode)); > } > - if (strcmp(constraint_mode_name_.c_str(), status_.constraint_mode)) { > + if (strcmp(constraintModeName_.c_str(), status_.constraint_mode)) { AgcStatus::constraint_mode should also be renamed to constraintMode. > auto it = > - config_.constraint_modes.find(constraint_mode_name_); > - if (it == config_.constraint_modes.end()) > + config_.constraintModes.find(constraintModeName_); > + if (it == config_.constraintModes.end()) > throw std::runtime_error("Agc: no constraint list " + > - constraint_mode_name_); > - constraint_mode_ = &it->second; > - copy_string(constraint_mode_name_, status_.constraint_mode, > - sizeof(status_.constraint_mode)); > + constraintModeName_); > + constraintMode_ = &it->second; > + copyString(constraintModeName_, status_.constraint_mode, > + sizeof(status_.constraint_mode)); > } > - LOG(RPiAgc, Debug) << "exposure_mode " > - << exposure_mode_name_ << " constraint_mode " > - << constraint_mode_name_ << " metering_mode " > - << metering_mode_name_; > + LOG(RPiAgc, Debug) << "exposureMode " > + << exposureModeName_ << " constraint_mode " > + << constraintModeName_ << " meteringMode " > + << meteringModeName_; > } > > -void Agc::fetchCurrentExposure(Metadata *image_metadata) > +void Agc::fetchCurrentExposure(Metadata *imageMetadata) > { > - std::unique_lock<Metadata> lock(*image_metadata); > - DeviceStatus *device_status = > - image_metadata->GetLocked<DeviceStatus>("device.status"); > - if (!device_status) > + std::unique_lock<Metadata> lock(*imageMetadata); > + DeviceStatus *deviceStatus = > + imageMetadata->getLocked<DeviceStatus>("device.status"); > + if (!deviceStatus) > throw std::runtime_error("Agc: no device metadata"); > - current_.shutter = device_status->shutter_speed; > - current_.analogue_gain = device_status->analogue_gain; > - AgcStatus *agc_status = > - image_metadata->GetLocked<AgcStatus>("agc.status"); > - current_.total_exposure = agc_status ? agc_status->total_exposure_value : 0s; > - current_.total_exposure_no_dg = current_.shutter * current_.analogue_gain; > + current_.shutter = deviceStatus->shutterSpeed; > + current_.analogueGain = deviceStatus->analogueGain; > + AgcStatus *agcStatus = > + imageMetadata->getLocked<AgcStatus>("agc.status"); > + current_.totalExposure = agcStatus ? agcStatus->totalExposureValue : 0s; > + current_.totalExposureNoDG = current_.shutter * current_.analogueGain; > } > > -void Agc::fetchAwbStatus(Metadata *image_metadata) > +void Agc::fetchAwbStatus(Metadata *imageMetadata) > { > - awb_.gain_r = 1.0; // in case not found in metadata > - awb_.gain_g = 1.0; > - awb_.gain_b = 1.0; > - if (image_metadata->Get("awb.status", awb_) != 0) > + awb_.gainR = 1.0; // in case not found in metadata > + awb_.gainG = 1.0; > + awb_.gainB = 1.0; > + if (imageMetadata->get("awb.status", awb_) != 0) > LOG(RPiAgc, Debug) << "Agc: no AWB status found"; > } > > -static double compute_initial_Y(bcm2835_isp_stats *stats, AwbStatus const &awb, > - double weights[], double gain) > +static double computeInitialY(bcm2835_isp_stats *stats, AwbStatus const &awb, > + double weights[], double gain) > { > bcm2835_isp_stats_region *regions = stats->agc_stats; > // Note how the calculation below means that equal weights give you > // "average" metering (i.e. all pixels equally important). > - double R_sum = 0, G_sum = 0, B_sum = 0, pixel_sum = 0; > + double rSum = 0, gSum = 0, bSum = 0, pixelSum = 0; > for (int i = 0; i < AGC_STATS_SIZE; i++) { > double counted = regions[i].counted; > - double r_sum = std::min(regions[i].r_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); > - double g_sum = std::min(regions[i].g_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); > - double b_sum = std::min(regions[i].b_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); > - R_sum += r_sum * weights[i]; > - G_sum += g_sum * weights[i]; > - B_sum += b_sum * weights[i]; > - pixel_sum += counted * weights[i]; > + double rAcc = std::min(regions[i].r_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); > + double gAcc = std::min(regions[i].g_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); > + double bAcc = std::min(regions[i].b_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); > + rSum += rAcc * weights[i]; > + gSum += gAcc * weights[i]; > + bSum += bAcc * weights[i]; > + pixelSum += counted * weights[i]; > } > - if (pixel_sum == 0.0) { > + if (pixelSum == 0.0) { > LOG(RPiAgc, Warning) << "compute_initial_Y: pixel_sum is zero"; This comment needs updating. > return 0; > } > - double Y_sum = R_sum * awb.gain_r * .299 + > - G_sum * awb.gain_g * .587 + > - B_sum * awb.gain_b * .114; > - return Y_sum / pixel_sum / (1 << PIPELINE_BITS); > + double ySum = rSum * awb.gainR * .299 + > + gSum * awb.gainG * .587 + > + bSum * awb.gainB * .114; > + return ySum / pixelSum / (1 << PIPELINE_BITS); > } > > // We handle extra gain through EV by adjusting our Y targets. However, you > @@ -542,108 +533,102 @@ static double compute_initial_Y(bcm2835_isp_stats *stats, AwbStatus const &awb, > > #define EV_GAIN_Y_TARGET_LIMIT 0.9 > > -static double constraint_compute_gain(AgcConstraint &c, Histogram &h, > - double lux, double ev_gain, > - double &target_Y) > +static double constraintComputeGain(AgcConstraint &c, Histogram &h, double lux, > + double evGain, double &targetY) > { > - target_Y = c.Y_target.Eval(c.Y_target.Domain().Clip(lux)); > - target_Y = std::min(EV_GAIN_Y_TARGET_LIMIT, target_Y * ev_gain); > - double iqm = h.InterQuantileMean(c.q_lo, c.q_hi); > - return (target_Y * NUM_HISTOGRAM_BINS) / iqm; > + targetY = c.yTarget.eval(c.yTarget.domain().clip(lux)); > + targetY = std::min(EV_GAIN_Y_TARGET_LIMIT, targetY * evGain); > + double iqm = h.interQuantileMean(c.qLo, c.qHi); > + return (targetY * NUM_HISTOGRAM_BINS) / iqm; > } > > -void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata, > - double &gain, double &target_Y) > +void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *imageMetadata, > + double &gain, double &targetY) > { > struct LuxStatus lux = {}; > lux.lux = 400; // default lux level to 400 in case no metadata found > - if (image_metadata->Get("lux.status", lux) != 0) > + if (imageMetadata->get("lux.status", lux) != 0) > LOG(RPiAgc, Warning) << "Agc: no lux level found"; > Histogram h(statistics->hist[0].g_hist, NUM_HISTOGRAM_BINS); > - double ev_gain = status_.ev * config_.base_ev; > + double evGain = status_.ev * config_.baseEv; > // The initial gain and target_Y come from some of the regions. After > // that we consider the histogram constraints. > - target_Y = > - config_.Y_target.Eval(config_.Y_target.Domain().Clip(lux.lux)); > - target_Y = std::min(EV_GAIN_Y_TARGET_LIMIT, target_Y * ev_gain); > + targetY = config_.yTarget.eval(config_.yTarget.domain().clip(lux.lux)); > + targetY = std::min(EV_GAIN_Y_TARGET_LIMIT, targetY * evGain); > > // Do this calculation a few times as brightness increase can be > // non-linear when there are saturated regions. > gain = 1.0; > for (int i = 0; i < 8; i++) { > - double initial_Y = compute_initial_Y(statistics, awb_, > - metering_mode_->weights, gain); > - double extra_gain = std::min(10.0, target_Y / (initial_Y + .001)); > - gain *= extra_gain; > - LOG(RPiAgc, Debug) << "Initial Y " << initial_Y << " target " << target_Y > + double initialY = computeInitialY(statistics, awb_, meteringMode_->weights, gain); > + double extraGain = std::min(10.0, targetY / (initialY + .001)); > + gain *= extraGain; > + LOG(RPiAgc, Debug) << "Initial Y " << initialY << " target " << targetY > << " gives gain " << gain; > - if (extra_gain < 1.01) // close enough > + if (extraGain < 1.01) // close enough > break; > } > > - for (auto &c : *constraint_mode_) { > - double new_target_Y; > - double new_gain = > - constraint_compute_gain(c, h, lux.lux, ev_gain, > - new_target_Y); > + for (auto &c : *constraintMode_) { > + double newTargetY; > + double newGain = constraintComputeGain(c, h, lux.lux, evGain, newTargetY); > LOG(RPiAgc, Debug) << "Constraint has target_Y " > - << new_target_Y << " giving gain " << new_gain; > - if (c.bound == AgcConstraint::Bound::LOWER && > - new_gain > gain) { > + << newTargetY << " giving gain " << newGain; > + if (c.bound == AgcConstraint::Bound::LOWER && newGain > gain) { > LOG(RPiAgc, Debug) << "Lower bound constraint adopted"; > - gain = new_gain, target_Y = new_target_Y; > - } else if (c.bound == AgcConstraint::Bound::UPPER && > - new_gain < gain) { > + gain = newGain; > + targetY = newTargetY; > + } else if (c.bound == AgcConstraint::Bound::UPPER && newGain < gain) { > LOG(RPiAgc, Debug) << "Upper bound constraint adopted"; > - gain = new_gain, target_Y = new_target_Y; > + gain = newGain; > + targetY = newTargetY; > } > } > - LOG(RPiAgc, Debug) << "Final gain " << gain << " (target_Y " << target_Y << " ev " > - << status_.ev << " base_ev " << config_.base_ev > + LOG(RPiAgc, Debug) << "Final gain " << gain << " (target_Y " << targetY << " ev " > + << status_.ev << " base_ev " << config_.baseEv > << ")"; > } > > void Agc::computeTargetExposure(double gain) > { > - if (status_.fixed_shutter && status_.fixed_analogue_gain) { > + if (status_.fixedShutter && status_.fixedAnalogueGain) { > // When ag and shutter are both fixed, we need to drive the > // total exposure so that we end up with a digital gain of at least > // 1/min_colour_gain. Otherwise we'd desaturate channels causing s/min_colour_gain/minColourGain/ > // white to go cyan or magenta. > - double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 }); > - ASSERT(min_colour_gain != 0.0); > - target_.total_exposure = > - status_.fixed_shutter * status_.fixed_analogue_gain / min_colour_gain; > + double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 }); > + ASSERT(minColourGain != 0.0); > + target_.totalExposure = > + status_.fixedShutter * status_.fixedAnalogueGain / minColourGain; > } else { > // The statistics reflect the image without digital gain, so the final > // total exposure we're aiming for is: > - target_.total_exposure = current_.total_exposure_no_dg * gain; > + target_.totalExposure = current_.totalExposureNoDG * gain; > // The final target exposure is also limited to what the exposure > // mode allows. > - Duration max_shutter = status_.fixed_shutter > - ? status_.fixed_shutter > - : exposure_mode_->shutter.back(); > - max_shutter = clipShutter(max_shutter); > - Duration max_total_exposure = > - max_shutter * > - (status_.fixed_analogue_gain != 0.0 > - ? status_.fixed_analogue_gain > - : exposure_mode_->gain.back()); > - target_.total_exposure = std::min(target_.total_exposure, > - max_total_exposure); > + Duration maxShutter = status_.fixedShutter > + ? status_.fixedShutter > + : exposureMode_->shutter.back(); > + maxShutter = clipShutter(maxShutter); > + Duration maxTotalExposure = > + maxShutter * > + (status_.fixedAnalogueGain != 0.0 > + ? status_.fixedAnalogueGain > + : exposureMode_->gain.back()); > + target_.totalExposure = std::min(target_.totalExposure, maxTotalExposure); > } > - LOG(RPiAgc, Debug) << "Target total_exposure " << target_.total_exposure; > + LOG(RPiAgc, Debug) << "Target totalExposure " << target_.totalExposure; > } > > -bool Agc::applyDigitalGain(double gain, double target_Y) > +bool Agc::applyDigitalGain(double gain, double targetY) > { > - double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 }); > - ASSERT(min_colour_gain != 0.0); > - double dg = 1.0 / min_colour_gain; > + double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 }); > + ASSERT(minColourGain != 0.0); > + double dg = 1.0 / minColourGain; > // I think this pipeline subtracts black level and rescales before we > // get the stats, so no need to worry about it. > LOG(RPiAgc, Debug) << "after AWB, target dg " << dg << " gain " << gain > - << " target_Y " << target_Y; > + << " target_Y " << targetY; > // Finally, if we're trying to reduce exposure but the target_Y is > // "close" to 1.0, then the gain computed for that constraint will be > // only slightly less than one, because the measured Y can never be > @@ -651,13 +636,13 @@ bool Agc::applyDigitalGain(double gain, double target_Y) > // that the exposure can be reduced, de-saturating the image much more > // quickly (and we then approach the correct value more quickly from > // below). > - bool desaturate = target_Y > config_.fast_reduce_threshold && > - gain < sqrt(target_Y); > + bool desaturate = targetY > config_.fastReduceThreshold && > + gain < sqrt(targetY); > if (desaturate) > - dg /= config_.fast_reduce_threshold; > + dg /= config_.fastReduceThreshold; > LOG(RPiAgc, Debug) << "Digital gain " << dg << " desaturate? " << desaturate; > - target_.total_exposure_no_dg = target_.total_exposure / dg; > - LOG(RPiAgc, Debug) << "Target total_exposure_no_dg " << target_.total_exposure_no_dg; > + target_.totalExposureNoDG = target_.totalExposure / dg; > + LOG(RPiAgc, Debug) << "Target totalExposureNoDG " << target_.totalExposureNoDG; > return desaturate; > } > > @@ -666,39 +651,38 @@ void Agc::filterExposure(bool desaturate) > double speed = config_.speed; > // AGC adapts instantly if both shutter and gain are directly specified > // or we're in the startup phase. > - if ((status_.fixed_shutter && status_.fixed_analogue_gain) || > - frame_count_ <= config_.startup_frames) > + if ((status_.fixedShutter && status_.fixedAnalogueGain) || > + frameCount_ <= config_.startupFrames) > speed = 1.0; > - if (!filtered_.total_exposure) { > - filtered_.total_exposure = target_.total_exposure; > - filtered_.total_exposure_no_dg = target_.total_exposure_no_dg; > + if (!filtered_.totalExposure) { > + filtered_.totalExposure = target_.totalExposure; > + filtered_.totalExposureNoDG = target_.totalExposureNoDG; > } else { > // If close to the result go faster, to save making so many > // micro-adjustments on the way. (Make this customisable?) > - if (filtered_.total_exposure < 1.2 * target_.total_exposure && > - filtered_.total_exposure > 0.8 * target_.total_exposure) > + if (filtered_.totalExposure < 1.2 * target_.totalExposure && > + filtered_.totalExposure > 0.8 * target_.totalExposure) > speed = sqrt(speed); > - filtered_.total_exposure = speed * target_.total_exposure + > - filtered_.total_exposure * (1.0 - speed); > + filtered_.totalExposure = speed * target_.totalExposure + > + filtered_.totalExposure * (1.0 - speed); > // When desaturing, take a big jump down in exposure_no_dg, s/exposure_no_dg/totalExposureNoDG/ > // which we'll hide with digital gain. > if (desaturate) > - filtered_.total_exposure_no_dg = > - target_.total_exposure_no_dg; > + filtered_.totalExposureNoDG = > + target_.totalExposureNoDG; > else > - filtered_.total_exposure_no_dg = > - speed * target_.total_exposure_no_dg + > - filtered_.total_exposure_no_dg * (1.0 - speed); > + filtered_.totalExposureNoDG = > + speed * target_.totalExposureNoDG + > + filtered_.totalExposureNoDG * (1.0 - speed); > } > // We can't let the no_dg exposure deviate too far below the Maybe an update here too. > // total exposure, as there might not be enough digital gain available > // in the ISP to hide it (which will cause nasty oscillation). > - if (filtered_.total_exposure_no_dg < > - filtered_.total_exposure * config_.fast_reduce_threshold) > - filtered_.total_exposure_no_dg = filtered_.total_exposure * > - config_.fast_reduce_threshold; > - LOG(RPiAgc, Debug) << "After filtering, total_exposure " << filtered_.total_exposure > - << " no dg " << filtered_.total_exposure_no_dg; > + if (filtered_.totalExposureNoDG < > + filtered_.totalExposure * config_.fastReduceThreshold) > + filtered_.totalExposureNoDG = filtered_.totalExposure * config_.fastReduceThreshold; > + LOG(RPiAgc, Debug) << "After filtering, totalExposure " << filtered_.totalExposure > + << " no dg " << filtered_.totalExposureNoDG; > } > > void Agc::divideUpExposure() > @@ -706,92 +690,84 @@ void Agc::divideUpExposure() > // Sending the fixed shutter/gain cases through the same code may seem > // unnecessary, but it will make more sense when extend this to cover > // variable aperture. > - Duration exposure_value = filtered_.total_exposure_no_dg; > - Duration shutter_time; > - double analogue_gain; > - shutter_time = status_.fixed_shutter > - ? status_.fixed_shutter > - : exposure_mode_->shutter[0]; > - shutter_time = clipShutter(shutter_time); > - analogue_gain = status_.fixed_analogue_gain != 0.0 > - ? status_.fixed_analogue_gain > - : exposure_mode_->gain[0]; > - if (shutter_time * analogue_gain < exposure_value) { > + Duration exposureValue = filtered_.totalExposureNoDG; > + Duration shutterTime; > + double analogueGain; > + shutterTime = status_.fixedShutter ? status_.fixedShutter > + : exposureMode_->shutter[0]; > + shutterTime = clipShutter(shutterTime); > + analogueGain = status_.fixedAnalogueGain != 0.0 ? status_.fixedAnalogueGain > + : exposureMode_->gain[0]; > + if (shutterTime * analogueGain < exposureValue) { > for (unsigned int stage = 1; > - stage < exposure_mode_->gain.size(); stage++) { > - if (!status_.fixed_shutter) { > + stage < exposureMode_->gain.size(); stage++) { > + if (!status_.fixedShutter) { > Duration stage_shutter = This variable also needs to be renamed. > - clipShutter(exposure_mode_->shutter[stage]); > - if (stage_shutter * analogue_gain >= > - exposure_value) { > - shutter_time = > - exposure_value / analogue_gain; > + clipShutter(exposureMode_->shutter[stage]); > + if (stage_shutter * analogueGain >= exposureValue) { > + shutterTime = exposureValue / analogueGain; > break; > } > - shutter_time = stage_shutter; > + shutterTime = stage_shutter; > } > - if (status_.fixed_analogue_gain == 0.0) { > - if (exposure_mode_->gain[stage] * > - shutter_time >= > - exposure_value) { > - analogue_gain = > - exposure_value / shutter_time; > + if (status_.fixedAnalogueGain == 0.0) { > + if (exposureMode_->gain[stage] * shutterTime >= exposureValue) { > + analogueGain = exposureValue / shutterTime; > break; > } > - analogue_gain = exposure_mode_->gain[stage]; > + analogueGain = exposureMode_->gain[stage]; > } > } > } > - LOG(RPiAgc, Debug) << "Divided up shutter and gain are " << shutter_time << " and " > - << analogue_gain; > + LOG(RPiAgc, Debug) << "Divided up shutter and gain are " << shutterTime << " and " > + << analogueGain; > // Finally adjust shutter time for flicker avoidance (require both > // shutter and gain not to be fixed). > - if (!status_.fixed_shutter && !status_.fixed_analogue_gain && > - status_.flicker_period) { > - int flicker_periods = shutter_time / status_.flicker_period; > - if (flicker_periods) { > - Duration new_shutter_time = flicker_periods * status_.flicker_period; > - analogue_gain *= shutter_time / new_shutter_time; > + if (!status_.fixedShutter && !status_.fixedAnalogueGain && > + status_.flickerPeriod) { > + int flickerPeriods = shutterTime / status_.flickerPeriod; > + if (flickerPeriods) { > + Duration newShutterTime = flickerPeriods * status_.flickerPeriod; > + analogueGain *= shutterTime / newShutterTime; > // We should still not allow the ag to go over the > // largest value in the exposure mode. Note that this > // may force more of the total exposure into the digital > // gain as a side-effect. > - analogue_gain = std::min(analogue_gain, > - exposure_mode_->gain.back()); > - shutter_time = new_shutter_time; > + analogueGain = std::min(analogueGain, exposureMode_->gain.back()); > + shutterTime = newShutterTime; > } > LOG(RPiAgc, Debug) << "After flicker avoidance, shutter " > - << shutter_time << " gain " << analogue_gain; > + << shutterTime << " gain " << analogueGain; > } > - filtered_.shutter = shutter_time; > - filtered_.analogue_gain = analogue_gain; > + filtered_.shutter = shutterTime; > + filtered_.analogueGain = analogueGain; > } > > -void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate) > +void Agc::writeAndFinish(Metadata *imageMetadata, bool desaturate) > { > - status_.total_exposure_value = filtered_.total_exposure; > - status_.target_exposure_value = desaturate ? 0s : target_.total_exposure_no_dg; > - status_.shutter_time = filtered_.shutter; > - status_.analogue_gain = filtered_.analogue_gain; > + status_.totalExposureValue = filtered_.totalExposure; > + status_.targetExposureValue = desaturate ? 0s : target_.totalExposureNoDG; > + status_.shutterTime = filtered_.shutter; > + status_.analogueGain = filtered_.analogueGain; > // Write to metadata as well, in case anyone wants to update the camera > // immediately. > - image_metadata->Set("agc.status", status_); > + imageMetadata->set("agc.status", status_); > LOG(RPiAgc, Debug) << "Output written, total exposure requested is " > - << filtered_.total_exposure; > + << filtered_.totalExposure; > LOG(RPiAgc, Debug) << "Camera exposure update: shutter time " << filtered_.shutter > - << " analogue gain " << filtered_.analogue_gain; > + << " analogue gain " << filtered_.analogueGain; > } > > Duration Agc::clipShutter(Duration shutter) > { > - if (max_shutter_) > - shutter = std::min(shutter, max_shutter_); > + if (maxShutter_) > + shutter = std::min(shutter, maxShutter_); > return shutter; > } > > // Register algorithm with the system. > -static Algorithm *Create(Controller *controller) > +static Algorithm *create(Controller *controller) > { > return (Algorithm *)new Agc(controller); > } > -static RegisterAlgorithm reg(NAME, &Create); > +static RegisterAlgorithm reg(NAME, &create); > diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp > index c100d3128c90..4ed7293bce97 100644 > --- a/src/ipa/raspberrypi/controller/rpi/agc.hpp > +++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp > @@ -26,114 +26,114 @@ namespace RPiController { > > struct AgcMeteringMode { > double weights[AGC_STATS_SIZE]; > - void Read(boost::property_tree::ptree const ¶ms); > + void read(boost::property_tree::ptree const ¶ms); > }; > > struct AgcExposureMode { > std::vector<libcamera::utils::Duration> shutter; > std::vector<double> gain; > - void Read(boost::property_tree::ptree const ¶ms); > + void read(boost::property_tree::ptree const ¶ms); > }; > > struct AgcConstraint { > enum class Bound { LOWER = 0, UPPER = 1 }; > Bound bound; > - double q_lo; > - double q_hi; > - Pwl Y_target; > - void Read(boost::property_tree::ptree const ¶ms); > + double qLo; > + double qHi; > + Pwl yTarget; > + void read(boost::property_tree::ptree const ¶ms); > }; > > typedef std::vector<AgcConstraint> AgcConstraintMode; > > struct AgcConfig { > - void Read(boost::property_tree::ptree const ¶ms); > - std::map<std::string, AgcMeteringMode> metering_modes; > - std::map<std::string, AgcExposureMode> exposure_modes; > - std::map<std::string, AgcConstraintMode> constraint_modes; > - Pwl Y_target; > + void read(boost::property_tree::ptree const ¶ms); > + std::map<std::string, AgcMeteringMode> meteringModes; > + std::map<std::string, AgcExposureMode> exposureModes; > + std::map<std::string, AgcConstraintMode> constraintModes; > + Pwl yTarget; > double speed; > - uint16_t startup_frames; > - unsigned int convergence_frames; > - double max_change; > - double min_change; > - double fast_reduce_threshold; > - double speed_up_threshold; > - std::string default_metering_mode; > - std::string default_exposure_mode; > - std::string default_constraint_mode; > - double base_ev; > - libcamera::utils::Duration default_exposure_time; > - double default_analogue_gain; > + uint16_t startupFrames; > + unsigned int convergenceFrames; > + double maxChange; > + double minChange; > + double fastReduceThreshold; > + double speedUpThreshold; > + std::string defaultMeteringMode; > + std::string defaultExposureMode; > + std::string defaultConstraintMode; > + double baseEv; > + libcamera::utils::Duration defaultExposureTime; > + double defaultAnalogueGain; > }; > > class Agc : public AgcAlgorithm > { > public: > Agc(Controller *controller); > - char const *Name() const override; > - void Read(boost::property_tree::ptree const ¶ms) override; > + char const *name() const override; > + void read(boost::property_tree::ptree const ¶ms) override; > // AGC handles "pausing" for itself. > - bool IsPaused() const override; > - void Pause() override; > - void Resume() override; > - unsigned int GetConvergenceFrames() const override; > - void SetEv(double ev) override; > - void SetFlickerPeriod(libcamera::utils::Duration flicker_period) override; > - void SetMaxShutter(libcamera::utils::Duration max_shutter) override; > - void SetFixedShutter(libcamera::utils::Duration fixed_shutter) override; > - void SetFixedAnalogueGain(double fixed_analogue_gain) override; > - void SetMeteringMode(std::string const &metering_mode_name) override; > - void SetExposureMode(std::string const &exposure_mode_name) override; > - void SetConstraintMode(std::string const &contraint_mode_name) override; > - void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override; > - void Prepare(Metadata *image_metadata) override; > - void Process(StatisticsPtr &stats, Metadata *image_metadata) override; > + bool isPaused() const override; > + void pause() override; > + void resume() override; > + unsigned int getConvergenceFrames() const override; > + void setEv(double ev) override; > + void setFlickerPeriod(libcamera::utils::Duration flickerPeriod) override; > + void setMaxShutter(libcamera::utils::Duration maxShutter) override; > + void setFixedShutter(libcamera::utils::Duration fixedShutter) override; > + void setFixedAnalogueGain(double fixedAnalogueGain) override; > + void setMeteringMode(std::string const &meteringModeName) override; > + void setExposureMode(std::string const &exposureModeName) override; > + void setConstraintMode(std::string const &contraintModeName) override; > + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; > + void prepare(Metadata *imageMetadata) override; > + void process(StatisticsPtr &stats, Metadata *imageMetadata) override; > > private: > - void updateLockStatus(DeviceStatus const &device_status); > + void updateLockStatus(DeviceStatus const &deviceStatus); > AgcConfig config_; > void housekeepConfig(); > - void fetchCurrentExposure(Metadata *image_metadata); > - void fetchAwbStatus(Metadata *image_metadata); > - void computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata, > - double &gain, double &target_Y); > + void fetchCurrentExposure(Metadata *imageMetadata); > + void fetchAwbStatus(Metadata *imageMetadata); > + void computeGain(bcm2835_isp_stats *statistics, Metadata *imageMetadata, > + double &gain, double &targetY); > void computeTargetExposure(double gain); > - bool applyDigitalGain(double gain, double target_Y); > + bool applyDigitalGain(double gain, double targetY); > void filterExposure(bool desaturate); > void divideUpExposure(); > - void writeAndFinish(Metadata *image_metadata, bool desaturate); > + void writeAndFinish(Metadata *imageMetadata, bool desaturate); > libcamera::utils::Duration clipShutter(libcamera::utils::Duration shutter); > - AgcMeteringMode *metering_mode_; > - AgcExposureMode *exposure_mode_; > - AgcConstraintMode *constraint_mode_; > - uint64_t frame_count_; > + AgcMeteringMode *meteringMode_; > + AgcExposureMode *exposureMode_; > + AgcConstraintMode *constraintMode_; > + uint64_t frameCount_; > AwbStatus awb_; > struct ExposureValues { > ExposureValues(); > > libcamera::utils::Duration shutter; > - double analogue_gain; > - libcamera::utils::Duration total_exposure; > - libcamera::utils::Duration total_exposure_no_dg; // without digital gain > + double analogueGain; > + libcamera::utils::Duration totalExposure; > + libcamera::utils::Duration totalExposureNoDG; // without digital gain > }; > ExposureValues current_; // values for the current frame > ExposureValues target_; // calculate the values we want here > ExposureValues filtered_; // these values are filtered towards target > AgcStatus status_; > - int lock_count_; > - DeviceStatus last_device_status_; > - libcamera::utils::Duration last_target_exposure_; > - double last_sensitivity_; // sensitivity of the previous camera mode > + int lockCount_; > + DeviceStatus lastDeviceStatus_; > + libcamera::utils::Duration lastTargetExposure_; > + double lastSensitivity_; // sensitivity of the previous camera mode > // Below here the "settings" that applications can change. > - std::string metering_mode_name_; > - std::string exposure_mode_name_; > - std::string constraint_mode_name_; > + std::string meteringModeName_; > + std::string exposureModeName_; > + std::string constraintModeName_; > double ev_; > - libcamera::utils::Duration flicker_period_; > - libcamera::utils::Duration max_shutter_; > - libcamera::utils::Duration fixed_shutter_; > - double fixed_analogue_gain_; > + libcamera::utils::Duration flickerPeriod_; > + libcamera::utils::Duration maxShutter_; > + libcamera::utils::Duration fixedShutter_; > + double fixedAnalogueGain_; > }; > > } // namespace RPiController > diff --git a/src/ipa/raspberrypi/controller/rpi/alsc.cpp b/src/ipa/raspberrypi/controller/rpi/alsc.cpp > index e575c14a92db..4929abc5b360 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 ¶ms) > +static void generateLut(double *lut, boost::property_tree::ptree const ¶ms) > { > 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 ¶ms) > } > } > > -static void read_lut(double *lut, boost::property_tree::ptree const ¶ms) > +static void readLut(double *lut, boost::property_tree::ptree const ¶ms) > { > 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 ¶ms, > - std::string const &name) > +static void readCalibrations(std::vector<AlscCalibration> &calibrations, > + boost::property_tree::ptree const ¶ms, > + 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 ¶ms) > +void Alsc::read(boost::property_tree::ptree const ¶ms) > { > - 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 " s/max_diff/maxDiff/ > - << last_max_diff << " to " << max_diff; > - last_max_diff = max_diff; > + << 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); > diff --git a/src/ipa/raspberrypi/controller/rpi/alsc.hpp b/src/ipa/raspberrypi/controller/rpi/alsc.hpp > index d1dbe0d1d22d..7a0949d1ccc5 100644 > --- a/src/ipa/raspberrypi/controller/rpi/alsc.hpp > +++ b/src/ipa/raspberrypi/controller/rpi/alsc.hpp > @@ -24,24 +24,24 @@ struct AlscCalibration { > > struct AlscConfig { > // Only repeat the ALSC calculation every "this many" frames > - uint16_t frame_period; > + uint16_t framePeriod; > // number of initial frames for which speed taken as 1.0 (maximum) > - uint16_t startup_frames; > + uint16_t startupFrames; > // IIR filter speed applied to algorithm results > double speed; > - double sigma_Cr; > - double sigma_Cb; > - double min_count; > - uint16_t min_G; > + double sigmaCr; > + double sigmaCb; > + double minCount; > + uint16_t minG; > double omega; > - uint32_t n_iter; > - double luminance_lut[ALSC_CELLS_X * ALSC_CELLS_Y]; > - double luminance_strength; > - std::vector<AlscCalibration> calibrations_Cr; > - std::vector<AlscCalibration> calibrations_Cb; > - double default_ct; // colour temperature if no metadata found > + uint32_t nIter; > + double luminanceLut[ALSC_CELLS_X * ALSC_CELLS_Y]; > + double luminanceStrength; > + std::vector<AlscCalibration> calibrationsCr; > + std::vector<AlscCalibration> calibrationsCb; > + double defaultCt; // colour temperature if no metadata found > double threshold; // iteration termination threshold > - double lambda_bound; // upper/lower bound for lambda from a value of 1 > + double lambdaBound; // upper/lower bound for lambda from a value of 1 > }; > > class Alsc : public Algorithm > @@ -49,58 +49,58 @@ class Alsc : public Algorithm > public: > Alsc(Controller *controller = NULL); > ~Alsc(); > - char const *Name() const override; > - void Initialise() override; > - void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override; > - void Read(boost::property_tree::ptree const ¶ms) override; > - void Prepare(Metadata *image_metadata) override; > - void Process(StatisticsPtr &stats, Metadata *image_metadata) override; > + char const *name() const override; > + void initialise() override; > + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; > + void read(boost::property_tree::ptree const ¶ms) override; > + void prepare(Metadata *imageMetadata) override; > + void process(StatisticsPtr &stats, Metadata *imageMetadata) override; > > private: > // configuration is read-only, and available to both threads > AlscConfig config_; > - bool first_time_; > - CameraMode camera_mode_; > - double luminance_table_[ALSC_CELLS_X * ALSC_CELLS_Y]; > - std::thread async_thread_; > + bool firstTime_; > + CameraMode cameraMode_; > + double luminanceTable_[ALSC_CELLS_X * ALSC_CELLS_Y]; > + std::thread asyncThread_; > void asyncFunc(); // asynchronous thread function > std::mutex mutex_; > // condvar for async thread to wait on > - std::condition_variable async_signal_; > + std::condition_variable asyncSignal_; > // condvar for synchronous thread to wait on > - std::condition_variable sync_signal_; > + std::condition_variable syncSignal_; > // for sync thread to check if async thread finished (requires mutex) > - bool async_finished_; > + bool asyncFinished_; > // for async thread to check if it's been told to run (requires mutex) > - bool async_start_; > + bool asyncStart_; > // for async thread to check if it's been told to quit (requires mutex) > - bool async_abort_; > + bool asyncAbort_; > > // The following are only for the synchronous thread to use: > // for sync thread to note its has asked async thread to run > - bool async_started_; > - // counts up to frame_period before restarting the async thread > - int frame_phase_; > - // counts up to startup_frames > - int frame_count_; > - // counts up to startup_frames for Process function > - int frame_count2_; > - double sync_results_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; > - double prev_sync_results_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; > + bool asyncStarted_; > + // counts up to framePeriod before restarting the async thread > + int framePhase_; > + // counts up to startupFrames > + int frameCount_; > + // counts up to startupFrames for Process function > + int frameCount2_; > + double syncResults_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; > + double prevSyncResults_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; > void waitForAysncThread(); > // The following are for the asynchronous thread to use, though the main > // thread can set/reset them if the async thread is known to be idle: > - void restartAsync(StatisticsPtr &stats, Metadata *image_metadata); > + void restartAsync(StatisticsPtr &stats, Metadata *imageMetadata); > // copy out the results from the async thread so that it can be restarted > void fetchAsyncResults(); > double ct_; > bcm2835_isp_stats_region statistics_[ALSC_CELLS_Y * ALSC_CELLS_X]; > - double async_results_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; > - double async_lambda_r_[ALSC_CELLS_X * ALSC_CELLS_Y]; > - double async_lambda_b_[ALSC_CELLS_X * ALSC_CELLS_Y]; > + double asyncResults_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; > + double asyncLambdaR_[ALSC_CELLS_X * ALSC_CELLS_Y]; > + double asyncLambdaB_[ALSC_CELLS_X * ALSC_CELLS_Y]; > void doAlsc(); > - double lambda_r_[ALSC_CELLS_X * ALSC_CELLS_Y]; > - double lambda_b_[ALSC_CELLS_X * ALSC_CELLS_Y]; > + double lambdaR_[ALSC_CELLS_X * ALSC_CELLS_Y]; > + double lambdaB_[ALSC_CELLS_X * ALSC_CELLS_Y]; > }; > > } // namespace RPiController > diff --git a/src/ipa/raspberrypi/controller/rpi/awb.cpp b/src/ipa/raspberrypi/controller/rpi/awb.cpp > index d4c934473832..74449c8c7591 100644 > --- a/src/ipa/raspberrypi/controller/rpi/awb.cpp > +++ b/src/ipa/raspberrypi/controller/rpi/awb.cpp > @@ -24,33 +24,33 @@ LOG_DEFINE_CATEGORY(RPiAwb) > // todo - the locking in this algorithm needs some tidying up as has been done > // elsewhere (ALSC and AGC). > > -void AwbMode::Read(boost::property_tree::ptree const ¶ms) > +void AwbMode::read(boost::property_tree::ptree const ¶ms) > { > - ct_lo = params.get<double>("lo"); > - ct_hi = params.get<double>("hi"); > + ctLo = params.get<double>("lo"); > + ctHi = params.get<double>("hi"); > } > > -void AwbPrior::Read(boost::property_tree::ptree const ¶ms) > +void AwbPrior::read(boost::property_tree::ptree const ¶ms) > { > lux = params.get<double>("lux"); > - prior.Read(params.get_child("prior")); > + prior.read(params.get_child("prior")); > } > > -static void read_ct_curve(Pwl &ct_r, Pwl &ct_b, > - boost::property_tree::ptree const ¶ms) > +static void readCtCurve(Pwl &ctR, Pwl &ctB, > + boost::property_tree::ptree const ¶ms) > { > int num = 0; > for (auto it = params.begin(); it != params.end(); it++) { > double ct = it->second.get_value<double>(); > - assert(it == params.begin() || ct != ct_r.Domain().end); > + assert(it == params.begin() || ct != ctR.domain().end); > if (++it == params.end()) > throw std::runtime_error( > "AwbConfig: incomplete CT curve entry"); > - ct_r.Append(ct, it->second.get_value<double>()); > + ctR.append(ct, it->second.get_value<double>()); > if (++it == params.end()) > throw std::runtime_error( > "AwbConfig: incomplete CT curve entry"); > - ct_b.Append(ct, it->second.get_value<double>()); > + ctB.append(ct, it->second.get_value<double>()); > num++; > } > if (num < 2) > @@ -58,22 +58,21 @@ static void read_ct_curve(Pwl &ct_r, Pwl &ct_b, > "AwbConfig: insufficient points in CT curve"); > } > > -void AwbConfig::Read(boost::property_tree::ptree const ¶ms) > +void AwbConfig::read(boost::property_tree::ptree const ¶ms) > { > bayes = params.get<int>("bayes", 1); > - frame_period = params.get<uint16_t>("frame_period", 10); > - startup_frames = params.get<uint16_t>("startup_frames", 10); > - convergence_frames = params.get<unsigned int>("convergence_frames", 3); > + framePeriod = params.get<uint16_t>("framePeriod", 10); > + startupFrames = params.get<uint16_t>("startupFrames", 10); > + convergenceFrames = params.get<unsigned int>("convergence_frames", 3); > speed = params.get<double>("speed", 0.05); > if (params.get_child_optional("ct_curve")) > - read_ct_curve(ct_r, ct_b, params.get_child("ct_curve")); > + readCtCurve(ctR, ctB, params.get_child("ct_curve")); > if (params.get_child_optional("priors")) { > for (auto &p : params.get_child("priors")) { > AwbPrior prior; > - prior.Read(p.second); > + prior.read(p.second); > if (!priors.empty() && prior.lux <= priors.back().lux) > - throw std::runtime_error( > - "AwbConfig: Prior must be ordered in increasing lux value"); > + throw std::runtime_error("AwbConfig: Prior must be ordered in increasing lux value"); > priors.push_back(prior); > } > if (priors.empty()) > @@ -82,177 +81,170 @@ void AwbConfig::Read(boost::property_tree::ptree const ¶ms) > } > if (params.get_child_optional("modes")) { > for (auto &p : params.get_child("modes")) { > - modes[p.first].Read(p.second); > - if (default_mode == nullptr) > - default_mode = &modes[p.first]; > + modes[p.first].read(p.second); > + if (defaultMode == nullptr) > + defaultMode = &modes[p.first]; > } > - if (default_mode == nullptr) > - throw std::runtime_error( > - "AwbConfig: no AWB modes configured"); > + if (defaultMode == nullptr) > + throw std::runtime_error("AwbConfig: no AWB modes configured"); > } > - min_pixels = params.get<double>("min_pixels", 16.0); > - min_G = params.get<uint16_t>("min_G", 32); > - min_regions = params.get<uint32_t>("min_regions", 10); > - delta_limit = params.get<double>("delta_limit", 0.2); > - coarse_step = params.get<double>("coarse_step", 0.2); > - transverse_pos = params.get<double>("transverse_pos", 0.01); > - transverse_neg = params.get<double>("transverse_neg", 0.01); > - if (transverse_pos <= 0 || transverse_neg <= 0) > - throw std::runtime_error( > - "AwbConfig: transverse_pos/neg must be > 0"); > - sensitivity_r = params.get<double>("sensitivity_r", 1.0); > - sensitivity_b = params.get<double>("sensitivity_b", 1.0); > + minPixels = params.get<double>("min_pixels", 16.0); > + minG = params.get<uint16_t>("min_G", 32); > + minRegions = params.get<uint32_t>("min_regions", 10); > + deltaLimit = params.get<double>("delta_limit", 0.2); > + coarseStep = params.get<double>("coarse_step", 0.2); > + transversePos = params.get<double>("transverse_pos", 0.01); > + transverseNeg = params.get<double>("transverse_neg", 0.01); > + if (transversePos <= 0 || transverseNeg <= 0) > + throw std::runtime_error("AwbConfig: transverse_pos/neg must be > 0"); > + sensitivityR = params.get<double>("sensitivity_r", 1.0); > + sensitivityB = params.get<double>("sensitivity_b", 1.0); > if (bayes) { > - if (ct_r.Empty() || ct_b.Empty() || priors.empty() || > - default_mode == nullptr) { > + if (ctR.empty() || ctB.empty() || priors.empty() || > + defaultMode == nullptr) { > LOG(RPiAwb, Warning) > << "Bayesian AWB mis-configured - switch to Grey method"; > bayes = false; > } > } > - fast = params.get<int>( > - "fast", bayes); // default to fast for Bayesian, otherwise slow > - whitepoint_r = params.get<double>("whitepoint_r", 0.0); > - whitepoint_b = params.get<double>("whitepoint_b", 0.0); > + fast = params.get<int>("fast", bayes); // default to fast for Bayesian, otherwise slow > + whitepointR = params.get<double>("whitepoint_r", 0.0); > + whitepointB = params.get<double>("whitepoint_b", 0.0); > if (bayes == false) > - sensitivity_r = sensitivity_b = > - 1.0; // nor do sensitivities make any sense > + sensitivityR = sensitivityB = 1.0; // nor do sensitivities make any sense > } > > Awb::Awb(Controller *controller) > : AwbAlgorithm(controller) > { > - async_abort_ = async_start_ = async_started_ = async_finished_ = false; > + asyncAbort_ = asyncStart_ = asyncStarted_ = asyncFinished_ = false; > mode_ = nullptr; > - manual_r_ = manual_b_ = 0.0; > - first_switch_mode_ = true; > - async_thread_ = std::thread(std::bind(&Awb::asyncFunc, this)); > + manualR_ = manualB_ = 0.0; > + firstSwitchMode_ = true; > + asyncThread_ = std::thread(std::bind(&Awb::asyncFunc, this)); > } > > Awb::~Awb() > { > { > 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 *Awb::Name() const > +char const *Awb::name() const > { > return NAME; > } > > -void Awb::Read(boost::property_tree::ptree const ¶ms) > +void Awb::read(boost::property_tree::ptree const ¶ms) > { > - config_.Read(params); > + config_.read(params); > } > > -void Awb::Initialise() > +void Awb::initialise() > { > - frame_count_ = frame_phase_ = 0; > + frameCount_ = framePhase_ = 0; > // Put something sane into the status that we are filtering towards, > // just in case the first few frames don't have anything meaningful in > // them. > - if (!config_.ct_r.Empty() && !config_.ct_b.Empty()) { > - sync_results_.temperature_K = config_.ct_r.Domain().Clip(4000); > - sync_results_.gain_r = > - 1.0 / config_.ct_r.Eval(sync_results_.temperature_K); > - sync_results_.gain_g = 1.0; > - sync_results_.gain_b = > - 1.0 / config_.ct_b.Eval(sync_results_.temperature_K); > + if (!config_.ctR.empty() && !config_.ctB.empty()) { > + syncResults_.temperatureK = config_.ctR.domain().clip(4000); > + syncResults_.gainR = 1.0 / config_.ctR.eval(syncResults_.temperatureK); > + syncResults_.gainG = 1.0; > + syncResults_.gainB = 1.0 / config_.ctB.eval(syncResults_.temperatureK); > } else { > // random values just to stop the world blowing up > - sync_results_.temperature_K = 4500; > - sync_results_.gain_r = sync_results_.gain_g = > - sync_results_.gain_b = 1.0; > + syncResults_.temperatureK = 4500; > + syncResults_.gainR = syncResults_.gainG = syncResults_.gainB = 1.0; > } > - prev_sync_results_ = sync_results_; > - async_results_ = sync_results_; > + prevSyncResults_ = syncResults_; > + asyncResults_ = syncResults_; > } > > -bool Awb::IsPaused() const > +bool Awb::isPaused() const > { > return false; > } > > -void Awb::Pause() > +void Awb::pause() > { > // "Pause" by fixing everything to the most recent values. > - manual_r_ = sync_results_.gain_r = prev_sync_results_.gain_r; > - manual_b_ = sync_results_.gain_b = prev_sync_results_.gain_b; > - sync_results_.gain_g = prev_sync_results_.gain_g; > - sync_results_.temperature_K = prev_sync_results_.temperature_K; > + manualR_ = syncResults_.gainR = prevSyncResults_.gainR; > + manualB_ = syncResults_.gainB = prevSyncResults_.gainB; > + syncResults_.gainG = prevSyncResults_.gainG; > + syncResults_.temperatureK = prevSyncResults_.temperatureK; > } > > -void Awb::Resume() > +void Awb::resume() > { > - manual_r_ = 0.0; > - manual_b_ = 0.0; > + manualR_ = 0.0; > + manualB_ = 0.0; > } > > -unsigned int Awb::GetConvergenceFrames() const > +unsigned int Awb::getConvergenceFrames() const > { > // If not in auto mode, there is no convergence > // to happen, so no need to drop any frames - return zero. > if (!isAutoEnabled()) > return 0; > else > - return config_.convergence_frames; > + return config_.convergenceFrames; > } > > -void Awb::SetMode(std::string const &mode_name) > +void Awb::setMode(std::string const &modeName) > { > - mode_name_ = mode_name; > + modeName_ = modeName; > } > > -void Awb::SetManualGains(double manual_r, double manual_b) > +void Awb::setManualGains(double manualR, double manualB) > { > // If any of these are 0.0, we swich back to auto. > - manual_r_ = manual_r; > - manual_b_ = manual_b; > + manualR_ = manualR; > + manualB_ = manualB; > // If not in auto mode, set these values into the sync_results which s/sync_results/syncResults/ > // means that Prepare() will adopt them immediately. > if (!isAutoEnabled()) { > - sync_results_.gain_r = prev_sync_results_.gain_r = manual_r_; > - sync_results_.gain_g = prev_sync_results_.gain_g = 1.0; > - sync_results_.gain_b = prev_sync_results_.gain_b = manual_b_; > + syncResults_.gainR = prevSyncResults_.gainR = manualR_; > + syncResults_.gainG = prevSyncResults_.gainG = 1.0; > + syncResults_.gainB = prevSyncResults_.gainB = manualB_; > } > } > > -void Awb::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, > +void Awb::switchMode([[maybe_unused]] CameraMode const &cameraMode, > Metadata *metadata) > { > // On the first mode switch we'll have no meaningful colour > // temperature, so try to dead reckon one if in manual mode. > - if (!isAutoEnabled() && first_switch_mode_ && config_.bayes) { > - Pwl ct_r_inverse = config_.ct_r.Inverse(); > - Pwl ct_b_inverse = config_.ct_b.Inverse(); > - double ct_r = ct_r_inverse.Eval(ct_r_inverse.Domain().Clip(1 / manual_r_)); > - double ct_b = ct_b_inverse.Eval(ct_b_inverse.Domain().Clip(1 / manual_b_)); > - prev_sync_results_.temperature_K = (ct_r + ct_b) / 2; > - sync_results_.temperature_K = prev_sync_results_.temperature_K; > + if (!isAutoEnabled() && firstSwitchMode_ && config_.bayes) { > + Pwl ctRInverse = config_.ctR.inverse(); > + Pwl ctBInverse = config_.ctB.inverse(); > + double ctR = ctRInverse.eval(ctRInverse.domain().clip(1 / manualR_)); > + double ctB = ctBInverse.eval(ctBInverse.domain().clip(1 / manualB_)); > + prevSyncResults_.temperatureK = (ctR + ctB) / 2; > + syncResults_.temperatureK = prevSyncResults_.temperatureK; > } > // Let other algorithms know the current white balance values. > - metadata->Set("awb.status", prev_sync_results_); > - first_switch_mode_ = false; > + metadata->set("awb.status", prevSyncResults_); > + firstSwitchMode_ = false; > } > > bool Awb::isAutoEnabled() const > { > - return manual_r_ == 0.0 || manual_b_ == 0.0; > + return manualR_ == 0.0 || manualB_ == 0.0; > } > > void Awb::fetchAsyncResults() > { > LOG(RPiAwb, Debug) << "Fetch AWB results"; > - async_finished_ = false; > - async_started_ = false; > + asyncFinished_ = false; > + asyncStarted_ = false; > // It's possible manual gains could be set even while the async > // thread was running, so only copy the results if still in auto mode. > if (isAutoEnabled()) > - sync_results_ = async_results_; > + syncResults_ = asyncResults_; > } > > void Awb::restartAsync(StatisticsPtr &stats, double lux) > @@ -261,75 +253,74 @@ void Awb::restartAsync(StatisticsPtr &stats, double lux) > // this makes a new reference which belongs to the asynchronous thread > statistics_ = stats; > // store the mode as it could technically change > - auto m = config_.modes.find(mode_name_); > + auto m = config_.modes.find(modeName_); > mode_ = m != config_.modes.end() > ? &m->second > - : (mode_ == nullptr ? config_.default_mode : mode_); > + : (mode_ == nullptr ? config_.defaultMode : mode_); > lux_ = lux; > - frame_phase_ = 0; > - async_started_ = true; > - size_t len = mode_name_.copy(async_results_.mode, > - sizeof(async_results_.mode) - 1); > - async_results_.mode[len] = '\0'; > + framePhase_ = 0; > + asyncStarted_ = true; > + size_t len = modeName_.copy(asyncResults_.mode, > + sizeof(asyncResults_.mode) - 1); > + asyncResults_.mode[len] = '\0'; > { > std::lock_guard<std::mutex> lock(mutex_); > - async_start_ = true; > + asyncStart_ = true; > } > - async_signal_.notify_one(); > + asyncSignal_.notify_one(); > } > > -void Awb::Prepare(Metadata *image_metadata) > +void Awb::prepare(Metadata *imageMetadata) > { > - 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(RPiAwb, 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(); > } > // Finally apply IIR filter to results and put into metadata. > - memcpy(prev_sync_results_.mode, sync_results_.mode, > - sizeof(prev_sync_results_.mode)); > - prev_sync_results_.temperature_K = > - speed * sync_results_.temperature_K + > - (1.0 - speed) * prev_sync_results_.temperature_K; > - prev_sync_results_.gain_r = speed * sync_results_.gain_r + > - (1.0 - speed) * prev_sync_results_.gain_r; > - prev_sync_results_.gain_g = speed * sync_results_.gain_g + > - (1.0 - speed) * prev_sync_results_.gain_g; > - prev_sync_results_.gain_b = speed * sync_results_.gain_b + > - (1.0 - speed) * prev_sync_results_.gain_b; > - image_metadata->Set("awb.status", prev_sync_results_); > + memcpy(prevSyncResults_.mode, syncResults_.mode, > + sizeof(prevSyncResults_.mode)); > + prevSyncResults_.temperatureK = speed * syncResults_.temperatureK + > + (1.0 - speed) * prevSyncResults_.temperatureK; > + prevSyncResults_.gainR = speed * syncResults_.gainR + > + (1.0 - speed) * prevSyncResults_.gainR; > + prevSyncResults_.gainG = speed * syncResults_.gainG + > + (1.0 - speed) * prevSyncResults_.gainG; > + prevSyncResults_.gainB = speed * syncResults_.gainB + > + (1.0 - speed) * prevSyncResults_.gainB; > + imageMetadata->set("awb.status", prevSyncResults_); > LOG(RPiAwb, Debug) > - << "Using AWB gains r " << prev_sync_results_.gain_r << " g " > - << prev_sync_results_.gain_g << " b " > - << prev_sync_results_.gain_b; > + << "Using AWB gains r " << prevSyncResults_.gainR << " g " > + << prevSyncResults_.gainG << " b " > + << prevSyncResults_.gainB; > } > > -void Awb::Process(StatisticsPtr &stats, Metadata *image_metadata) > +void Awb::process(StatisticsPtr &stats, Metadata *imageMetadata) > { > // Count frames since we last poked the async thread. > - if (frame_phase_ < (int)config_.frame_period) > - frame_phase_++; > - LOG(RPiAwb, Debug) << "frame_phase " << frame_phase_; > + if (framePhase_ < (int)config_.framePeriod) > + framePhase_++; > + LOG(RPiAwb, Debug) << "frame_phase " << framePhase_; > // We do not restart the async thread if we're not in auto mode. > if (isAutoEnabled() && > - (frame_phase_ >= (int)config_.frame_period || > - frame_count_ < (int)config_.startup_frames)) { > + (framePhase_ >= (int)config_.framePeriod || > + frameCount_ < (int)config_.startupFrames)) { > // Update any settings and any image metadata that we need. > - struct LuxStatus lux_status = {}; > - lux_status.lux = 400; // in case no metadata > - if (image_metadata->Get("lux.status", lux_status) != 0) > + struct LuxStatus luxStatus = {}; > + luxStatus.lux = 400; // in case no metadata > + if (imageMetadata->get("lux.status", luxStatus) != 0) > LOG(RPiAwb, Debug) << "No lux metadata found"; > - LOG(RPiAwb, Debug) << "Awb lux value is " << lux_status.lux; > + LOG(RPiAwb, Debug) << "Awb lux value is " << luxStatus.lux; > > - if (async_started_ == false) > - restartAsync(stats, lux_status.lux); > + if (asyncStarted_ == false) > + restartAsync(stats, luxStatus.lux); > } > } > > @@ -338,32 +329,32 @@ void Awb::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; > } > doAwb(); > { > std::lock_guard<std::mutex> lock(mutex_); > - async_finished_ = true; > + asyncFinished_ = true; > } > - sync_signal_.notify_one(); > + syncSignal_.notify_one(); > } > } > > -static void generate_stats(std::vector<Awb::RGB> &zones, > - bcm2835_isp_stats_region *stats, double min_pixels, > - double min_G) > +static void generateStats(std::vector<Awb::RGB> &zones, > + bcm2835_isp_stats_region *stats, double minPixels, > + double minG) > { > for (int i = 0; i < AWB_STATS_SIZE_X * AWB_STATS_SIZE_Y; i++) { > Awb::RGB zone; > double counted = stats[i].counted; > - if (counted >= min_pixels) { > + if (counted >= minPixels) { > zone.G = stats[i].g_sum / counted; > - if (zone.G >= min_G) { > + if (zone.G >= minG) { > zone.R = stats[i].r_sum / counted; > zone.B = stats[i].b_sum / counted; > zones.push_back(zone); > @@ -377,32 +368,33 @@ void Awb::prepareStats() > zones_.clear(); > // LSC has already been applied to the stats in this pipeline, so stop > // any LSC compensation. We also ignore config_.fast in this version. > - generate_stats(zones_, statistics_->awb_stats, config_.min_pixels, > - config_.min_G); > + generateStats(zones_, statistics_->awb_stats, config_.minPixels, > + config_.minG); > // we're done with these; we may as well relinquish our hold on the > // pointer. > statistics_.reset(); > // apply sensitivities, so values appear to come from our "canonical" > // sensor. > - for (auto &zone : zones_) > - zone.R *= config_.sensitivity_r, > - zone.B *= config_.sensitivity_b; > + for (auto &zone : zones_) { > + zone.R *= config_.sensitivityR; > + zone.B *= config_.sensitivityB; > + } > } > > -double Awb::computeDelta2Sum(double gain_r, double gain_b) > +double Awb::computeDelta2Sum(double gainR, double gainB) > { > // Compute the sum of the squared colour error (non-greyness) as it > // appears in the log likelihood equation. > - double delta2_sum = 0; > + double delta2Sum = 0; > for (auto &z : zones_) { > - double delta_r = gain_r * z.R - 1 - config_.whitepoint_r; > - double delta_b = gain_b * z.B - 1 - config_.whitepoint_b; > - double delta2 = delta_r * delta_r + delta_b * delta_b; > + double deltaR = gainR * z.R - 1 - config_.whitepointR; > + double deltaB = gainB * z.B - 1 - config_.whitepointB; > + double delta2 = deltaR * deltaR + deltaB * deltaB; > //LOG(RPiAwb, Debug) << "delta_r " << delta_r << " delta_b " << delta_b << " delta2 " << delta2; > - delta2 = std::min(delta2, config_.delta_limit); > - delta2_sum += delta2; > + delta2 = std::min(delta2, config_.deltaLimit); > + delta2Sum += delta2; > } > - return delta2_sum; > + return delta2Sum; > } > > Pwl Awb::interpolatePrior() > @@ -420,7 +412,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 Pwl::combine(config_.priors[idx].prior, > config_.priors[idx + 1].prior, > [&](double /*x*/, double y0, double y1) { > return y0 + (y1 - y0) * > @@ -429,62 +421,60 @@ Pwl Awb::interpolatePrior() > } > } > > -static double interpolate_quadatric(Pwl::Point const &A, Pwl::Point const &B, > - Pwl::Point const &C) > +static double interpolateQuadatric(Pwl::Point const &a, Pwl::Point const &b, > + 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); > + 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) > { > points_.clear(); // assume doesn't deallocate memory > - size_t best_point = 0; > - double t = mode_->ct_lo; > - int span_r = 0, span_b = 0; > + size_t bestPoint = 0; > + double t = mode_->ctLo; > + int spanR = 0, spanB = 0; > // Step down the CT curve evaluating log likelihood. > while (true) { > - double r = config_.ct_r.Eval(t, &span_r); > - double b = config_.ct_b.Eval(t, &span_b); > - double gain_r = 1 / r, gain_b = 1 / b; > - double delta2_sum = computeDelta2Sum(gain_r, gain_b); > - double prior_log_likelihood = > - prior.Eval(prior.Domain().Clip(t)); > - double final_log_likelihood = delta2_sum - prior_log_likelihood; > + double r = config_.ctR.eval(t, &spanR); > + 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 finalLogLikelihood = delta2Sum - priorLogLikelihood; > LOG(RPiAwb, Debug) > - << "t: " << t << " gain_r " << gain_r << " gain_b " > - << gain_b << " delta2_sum " << delta2_sum > - << " prior " << prior_log_likelihood << " final " > - << final_log_likelihood; > - points_.push_back(Pwl::Point(t, final_log_likelihood)); > - if (points_.back().y < points_[best_point].y) > - best_point = points_.size() - 1; > - if (t == mode_->ct_hi) > + << "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) > + 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_.coarse_step, > - mode_->ct_hi); > + t = std::min(t + t / 10 * config_.coarseStep, mode_->ctHi); > } > - t = points_[best_point].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 > // interpolation around its neighbours. > if (points_.size() > 2) { > - unsigned long bp = std::min(best_point, points_.size() - 2); > - best_point = std::max(1UL, bp); > - t = interpolate_quadatric(points_[best_point - 1], > - points_[best_point], > - points_[best_point + 1]); > + unsigned long bp = std::min(bestPoint, points_.size() - 2); > + bestPoint = std::max(1UL, bp); > + t = interpolateQuadatric(points_[bestPoint - 1], > + points_[bestPoint], > + points_[bestPoint + 1]); > LOG(RPiAwb, Debug) > << "After quadratic refinement, coarse search has CT " > << t; > @@ -494,80 +484,76 @@ double Awb::coarseSearch(Pwl const &prior) > > void Awb::fineSearch(double &t, double &r, double &b, Pwl const &prior) > { > - int span_r = -1, span_b = -1; > - config_.ct_r.Eval(t, &span_r); > - config_.ct_b.Eval(t, &span_b); > - double step = t / 10 * config_.coarse_step * 0.1; > + int spanR = -1, spanB = -1; > + config_.ctR.eval(t, &spanR); > + config_.ctB.eval(t, &spanB); > + double step = t / 10 * config_.coarseStep * 0.1; > int nsteps = 5; > - double r_diff = config_.ct_r.Eval(t + nsteps * step, &span_r) - > - config_.ct_r.Eval(t - nsteps * step, &span_r); > - double b_diff = config_.ct_b.Eval(t + nsteps * step, &span_b) - > - config_.ct_b.Eval(t - nsteps * step, &span_b); > - Pwl::Point transverse(b_diff, -r_diff); > - if (transverse.Len2() < 1e-6) > + double rDiff = config_.ctR.eval(t + nsteps * step, &spanR) - > + 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) > return; > // unit vector orthogonal to the b vs. r function (pointing outwards > // with r and b increasing) > - transverse = transverse / transverse.Len(); > - double best_log_likelihood = 0, best_t = 0, best_r = 0, best_b = 0; > - double transverse_range = > - config_.transverse_neg + config_.transverse_pos; > - const int MAX_NUM_DELTAS = 12; > + transverse = transverse / transverse.len(); > + double bestLogLikelihood = 0, bestT = 0, bestR = 0, bestB = 0; > + double transverseRange = config_.transverseNeg + config_.transversePos; > + const int maxNumDeltas = 12; > // a transverse step approximately every 0.01 r/b units > - int num_deltas = floor(transverse_range * 100 + 0.5) + 1; > - num_deltas = num_deltas < 3 ? 3 : > - (num_deltas > MAX_NUM_DELTAS ? MAX_NUM_DELTAS : num_deltas); > + int numDeltas = floor(transverseRange * 100 + 0.5) + 1; > + numDeltas = numDeltas < 3 ? 3 : (numDeltas > maxNumDeltas ? maxNumDeltas : numDeltas); > // Step down CT curve. March a bit further if the transverse range is > // large. > - nsteps += num_deltas; > + nsteps += numDeltas; > for (int i = -nsteps; i <= nsteps; i++) { > - double t_test = t + i * step; > - double prior_log_likelihood = > - prior.Eval(prior.Domain().Clip(t_test)); > - double r_curve = config_.ct_r.Eval(t_test, &span_r); > - double b_curve = config_.ct_b.Eval(t_test, &span_b); > + double tTest = t + i * step; > + double priorLogLikelihood = > + prior.eval(prior.domain().clip(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[MAX_NUM_DELTAS]; > - int best_point = 0; > + Pwl::Point points[maxNumDeltas]; > + int bestPoint = 0; > // Take some measurements transversely *off* the CT curve. > - for (int j = 0; j < num_deltas; j++) { > - points[j].x = -config_.transverse_neg + > - (transverse_range * j) / (num_deltas - 1); > - Pwl::Point rb_test = Pwl::Point(r_curve, b_curve) + > - transverse * points[j].x; > - double r_test = rb_test.x, b_test = rb_test.y; > - double gain_r = 1 / r_test, gain_b = 1 / b_test; > - double delta2_sum = computeDelta2Sum(gain_r, gain_b); > - points[j].y = delta2_sum - prior_log_likelihood; > + 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; > + double gainR = 1 / rTest, gainB = 1 / bTest; > + double delta2Sum = computeDelta2Sum(gainR, gainB); > + points[j].y = delta2Sum - priorLogLikelihood; > LOG(RPiAwb, Debug) > - << "At t " << t_test << " r " << r_test << " b " > - << b_test << ": " << points[j].y; > - if (points[j].y < points[best_point].y) > - best_point = j; > + << "At t " << tTest << " r " << rTest << " b " > + << bTest << ": " << points[j].y; > + if (points[j].y < points[bestPoint].y) > + bestPoint = j; > } > // We have NUM_DELTAS points transversely across the CT curve, > // now let's do a quadratic interpolation for the best result. > - best_point = std::max(1, std::min(best_point, num_deltas - 2)); > - Pwl::Point rb_test = > - Pwl::Point(r_curve, b_curve) + > - transverse * > - interpolate_quadatric(points[best_point - 1], > - points[best_point], > - points[best_point + 1]); > - double r_test = rb_test.x, b_test = rb_test.y; > - double gain_r = 1 / r_test, gain_b = 1 / b_test; > - double delta2_sum = computeDelta2Sum(gain_r, gain_b); > - double final_log_likelihood = delta2_sum - prior_log_likelihood; > + 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; > + double gainR = 1 / rTest, gainB = 1 / bTest; > + double delta2Sum = computeDelta2Sum(gainR, gainB); > + double finalLogLikelihood = delta2Sum - priorLogLikelihood; > LOG(RPiAwb, Debug) > << "Finally " > - << t_test << " r " << r_test << " b " << b_test << ": " > - << final_log_likelihood > - << (final_log_likelihood < best_log_likelihood ? " BEST" : ""); > - if (best_t == 0 || final_log_likelihood < best_log_likelihood) > - best_log_likelihood = final_log_likelihood, > - best_t = t_test, best_r = r_test, best_b = b_test; > + << tTest << " r " << rTest << " b " << bTest << ": " > + << finalLogLikelihood > + << (finalLogLikelihood < bestLogLikelihood ? " BEST" : ""); > + if (bestT == 0 || finalLogLikelihood < bestLogLikelihood) > + bestLogLikelihood = finalLogLikelihood, > + bestT = tTest, bestR = rTest, bestB = bTest; > } > - t = best_t, r = best_r, b = best_b; > + t = bestT, r = bestR, b = bestB; > LOG(RPiAwb, Debug) > << "Fine search found t " << t << " r " << r << " b " << b; > } > @@ -582,12 +568,12 @@ void Awb::awbBayes() > // valid... not entirely sure about this. > Pwl prior = interpolatePrior(); > prior *= zones_.size() / (double)(AWB_STATS_SIZE_X * AWB_STATS_SIZE_Y); > - prior.Map([](double x, double y) { > + prior.map([](double x, double y) { > LOG(RPiAwb, Debug) << "(" << x << "," << y << ")"; > }); > double t = coarseSearch(prior); > - double r = config_.ct_r.Eval(t); > - double b = config_.ct_b.Eval(t); > + double r = config_.ctR.eval(t); > + double b = config_.ctB.eval(t); > LOG(RPiAwb, Debug) > << "After coarse search: r " << r << " b " << b << " (gains r " > << 1 / r << " b " << 1 / b << ")"; > @@ -604,10 +590,10 @@ void Awb::awbBayes() > // Write results out for the main thread to pick up. Remember to adjust > // the gains from the ones that the "canonical sensor" would require to > // the ones needed by *this* sensor. > - async_results_.temperature_K = t; > - async_results_.gain_r = 1.0 / r * config_.sensitivity_r; > - async_results_.gain_g = 1.0; > - async_results_.gain_b = 1.0 / b * config_.sensitivity_b; > + asyncResults_.temperatureK = t; > + asyncResults_.gainR = 1.0 / r * config_.sensitivityR; > + asyncResults_.gainG = 1.0; > + asyncResults_.gainB = 1.0 / b * config_.sensitivityB; > } > > void Awb::awbGrey() > @@ -617,51 +603,51 @@ void Awb::awbGrey() > // that we can sort them to exclude the extreme gains. We could > // consider some variations, such as normalising all the zones first, or > // doing an L2 average etc. > - std::vector<RGB> &derivs_R(zones_); > - std::vector<RGB> derivs_B(derivs_R); > - std::sort(derivs_R.begin(), derivs_R.end(), > + std::vector<RGB> &derivsR(zones_); > + std::vector<RGB> derivsB(derivsR); > + std::sort(derivsR.begin(), derivsR.end(), > [](RGB const &a, RGB const &b) { > return a.G * b.R < b.G * a.R; > }); > - std::sort(derivs_B.begin(), derivs_B.end(), > + std::sort(derivsB.begin(), derivsB.end(), > [](RGB const &a, RGB const &b) { > return a.G * b.B < b.G * a.B; > }); > // Average the middle half of the values. > - int discard = derivs_R.size() / 4; > - RGB sum_R(0, 0, 0), sum_B(0, 0, 0); > - for (auto ri = derivs_R.begin() + discard, > - bi = derivs_B.begin() + discard; > - ri != derivs_R.end() - discard; ri++, bi++) > - sum_R += *ri, sum_B += *bi; > - double gain_r = sum_R.G / (sum_R.R + 1), > - gain_b = sum_B.G / (sum_B.B + 1); > - async_results_.temperature_K = 4500; // don't know what it is > - async_results_.gain_r = gain_r; > - async_results_.gain_g = 1.0; > - async_results_.gain_b = gain_b; > + int discard = derivsR.size() / 4; > + RGB sumR(0, 0, 0), sumB(0, 0, 0); > + for (auto ri = derivsR.begin() + discard, > + bi = derivsB.begin() + discard; > + ri != derivsR.end() - discard; ri++, bi++) > + sumR += *ri, sumB += *bi; > + double gainR = sumR.G / (sumR.R + 1), > + gainB = sumB.G / (sumB.B + 1); > + asyncResults_.temperatureK = 4500; // don't know what it is > + asyncResults_.gainR = gainR; > + asyncResults_.gainG = 1.0; > + asyncResults_.gainB = gainB; > } > > void Awb::doAwb() > { > prepareStats(); > LOG(RPiAwb, Debug) << "Valid zones: " << zones_.size(); > - if (zones_.size() > config_.min_regions) { > + if (zones_.size() > config_.minRegions) { > if (config_.bayes) > awbBayes(); > else > awbGrey(); > LOG(RPiAwb, Debug) > << "CT found is " > - << async_results_.temperature_K > - << " with gains r " << async_results_.gain_r > - << " and b " << async_results_.gain_b; > + << asyncResults_.temperatureK > + << " with gains r " << asyncResults_.gainR > + << " and b " << asyncResults_.gainB; > } > } > > // Register algorithm with the system. > -static Algorithm *Create(Controller *controller) > +static Algorithm *create(Controller *controller) > { > return (Algorithm *)new Awb(controller); > } > -static RegisterAlgorithm reg(NAME, &Create); > +static RegisterAlgorithm reg(NAME, &create); > diff --git a/src/ipa/raspberrypi/controller/rpi/awb.hpp b/src/ipa/raspberrypi/controller/rpi/awb.hpp > index ac3dca6f42fc..91251d6be2da 100644 > --- a/src/ipa/raspberrypi/controller/rpi/awb.hpp > +++ b/src/ipa/raspberrypi/controller/rpi/awb.hpp > @@ -19,59 +19,59 @@ namespace RPiController { > // Control algorithm to perform AWB calculations. > > struct AwbMode { > - void Read(boost::property_tree::ptree const ¶ms); > - double ct_lo; // low CT value for search > - double ct_hi; // high CT value for search > + void read(boost::property_tree::ptree const ¶ms); > + double ctLo; // low CT value for search > + double ctHi; // high CT value for search > }; > > struct AwbPrior { > - void Read(boost::property_tree::ptree const ¶ms); > + void read(boost::property_tree::ptree const ¶ms); > double lux; // lux level > Pwl prior; // maps CT to prior log likelihood for this lux level > }; > > struct AwbConfig { > - AwbConfig() : default_mode(nullptr) {} > - void Read(boost::property_tree::ptree const ¶ms); > + AwbConfig() : defaultMode(nullptr) {} > + void read(boost::property_tree::ptree const ¶ms); > // Only repeat the AWB calculation every "this many" frames > - uint16_t frame_period; > + uint16_t framePeriod; > // number of initial frames for which speed taken as 1.0 (maximum) > - uint16_t startup_frames; > - unsigned int convergence_frames; // approx number of frames to converge > + uint16_t startupFrames; > + 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 ct_r; // function maps CT to r (= R/G) > - Pwl ct_b; // function maps CT to b (= B/G) > + Pwl ctR; // function maps CT to r (= R/G) > + Pwl ctB; // function maps CT to b (= B/G) > // table of illuminant priors at different lux levels > std::vector<AwbPrior> priors; > // AWB "modes" (determines the search range) > std::map<std::string, AwbMode> modes; > - AwbMode *default_mode; // mode used if no mode selected > + AwbMode *defaultMode; // mode used if no mode selected > // minimum proportion of pixels counted within AWB region for it to be > // "useful" > - double min_pixels; > + double minPixels; > // minimum G value of those pixels, to be regarded a "useful" > - uint16_t min_G; > + uint16_t minG; > // number of AWB regions that must be "useful" in order to do the AWB > // calculation > - uint32_t min_regions; > + uint32_t minRegions; > // clamp on colour error term (so as not to penalise non-grey excessively) > - double delta_limit; > + double deltaLimit; > // step size control in coarse search > - double coarse_step; > + double coarseStep; > // how far to wander off CT curve towards "more purple" > - double transverse_pos; > + double transversePos; > // how far to wander off CT curve towards "more green" > - double transverse_neg; > + double transverseNeg; > // red sensitivity ratio (set to canonical sensor's R/G divided by this > // sensor's R/G) > - double sensitivity_r; > + double sensitivityR; > // blue sensitivity ratio (set to canonical sensor's B/G divided by this > // sensor's B/G) > - double sensitivity_b; > + double sensitivityB; > // The whitepoint (which we normally "aim" for) can be moved. > - double whitepoint_r; > - double whitepoint_b; > + double whitepointR; > + double whitepointB; > bool bayes; // use Bayesian algorithm > }; > > @@ -80,22 +80,22 @@ class Awb : public AwbAlgorithm > public: > Awb(Controller *controller = NULL); > ~Awb(); > - char const *Name() const override; > - void Initialise() override; > - void Read(boost::property_tree::ptree const ¶ms) override; > + char const *name() const override; > + void initialise() override; > + void read(boost::property_tree::ptree const ¶ms) override; > // AWB handles "pausing" for itself. > - bool IsPaused() const override; > - void Pause() override; > - void Resume() override; > - unsigned int GetConvergenceFrames() const override; > - void SetMode(std::string const &name) override; > - void SetManualGains(double manual_r, double manual_b) override; > - void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override; > - void Prepare(Metadata *image_metadata) override; > - void Process(StatisticsPtr &stats, Metadata *image_metadata) override; > + bool isPaused() const override; > + void pause() override; > + void resume() override; > + unsigned int getConvergenceFrames() const override; > + void setMode(std::string const &name) override; > + void setManualGains(double manualR, double manualB) override; > + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; > + void prepare(Metadata *imageMetadata) override; > + void process(StatisticsPtr &stats, Metadata *imageMetadata) override; > struct RGB { > - RGB(double _R = 0, double _G = 0, double _B = 0) > - : R(_R), G(_G), B(_B) > + RGB(double r = 0, double g = 0, double b = 0) > + : R(r), G(g), B(b) > { > } > double R, G, B; > @@ -110,29 +110,29 @@ private: > bool isAutoEnabled() const; > // configuration is read-only, and available to both threads > AwbConfig config_; > - std::thread async_thread_; > + std::thread asyncThread_; > void asyncFunc(); // asynchronous thread function > std::mutex mutex_; > // condvar for async thread to wait on > - std::condition_variable async_signal_; > + std::condition_variable asyncSignal_; > // condvar for synchronous thread to wait on > - std::condition_variable sync_signal_; > + std::condition_variable syncSignal_; > // for sync thread to check if async thread finished (requires mutex) > - bool async_finished_; > + bool asyncFinished_; > // for async thread to check if it's been told to run (requires mutex) > - bool async_start_; > + bool asyncStart_; > // for async thread to check if it's been told to quit (requires mutex) > - bool async_abort_; > + bool asyncAbort_; > > // The following are only for the synchronous thread to use: > // for sync thread to note its has asked async thread to run > - bool async_started_; > - // counts up to frame_period before restarting the async thread > - int frame_phase_; > - int frame_count_; // counts up to startup_frames > - AwbStatus sync_results_; > - AwbStatus prev_sync_results_; > - std::string mode_name_; > + bool asyncStarted_; > + // counts up to framePeriod before restarting the async thread > + int framePhase_; > + int frameCount_; // counts up to startup_frames > + AwbStatus syncResults_; > + AwbStatus prevSyncResults_; > + std::string modeName_; > // The following are for the asynchronous thread to use, though the main > // thread can set/reset them if the async thread is known to be idle: > void restartAsync(StatisticsPtr &stats, double lux); > @@ -141,22 +141,22 @@ private: > StatisticsPtr statistics_; > AwbMode *mode_; > double lux_; > - AwbStatus async_results_; > + AwbStatus asyncResults_; > void doAwb(); > void awbBayes(); > void awbGrey(); > void prepareStats(); > - double computeDelta2Sum(double gain_r, double gain_b); > + double computeDelta2Sum(double gain_r, double gainB); > Pwl interpolatePrior(); > double coarseSearch(Pwl const &prior); > void fineSearch(double &t, double &r, double &b, Pwl const &prior); > std::vector<RGB> zones_; > std::vector<Pwl::Point> points_; > // manual r setting > - double manual_r_; > + double manualR_; > // manual b setting > - double manual_b_; > - bool first_switch_mode_; // is this the first call to SwitchMode? > + double manualB_; > + bool firstSwitchMode_; // is this the first call to SwitchMode? > }; > > static inline Awb::RGB operator+(Awb::RGB const &a, Awb::RGB const &b)
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp index f6a9cb0a2cd8..738cf56c6be0 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp @@ -30,7 +30,7 @@ LOG_DEFINE_CATEGORY(RPiAgc) #define PIPELINE_BITS 13 // seems to be a 13-bit pipeline -void AgcMeteringMode::Read(boost::property_tree::ptree const ¶ms) +void AgcMeteringMode::read(boost::property_tree::ptree const ¶ms) { int num = 0; for (auto &p : params.get_child("weights")) { @@ -43,265 +43,260 @@ void AgcMeteringMode::Read(boost::property_tree::ptree const ¶ms) } static std::string -read_metering_modes(std::map<std::string, AgcMeteringMode> &metering_modes, - boost::property_tree::ptree const ¶ms) +readMeteringModes(std::map<std::string, AgcMeteringMode> &meteringModes, + boost::property_tree::ptree const ¶ms) { std::string first; for (auto &p : params) { - AgcMeteringMode metering_mode; - metering_mode.Read(p.second); - metering_modes[p.first] = std::move(metering_mode); + AgcMeteringMode meteringMode; + meteringMode.read(p.second); + meteringModes[p.first] = std::move(meteringMode); if (first.empty()) first = p.first; } return first; } -static int read_list(std::vector<double> &list, - boost::property_tree::ptree const ¶ms) +static int readList(std::vector<double> &list, + boost::property_tree::ptree const ¶ms) { for (auto &p : params) list.push_back(p.second.get_value<double>()); return list.size(); } -static int read_list(std::vector<Duration> &list, - boost::property_tree::ptree const ¶ms) +static int readList(std::vector<Duration> &list, + boost::property_tree::ptree const ¶ms) { for (auto &p : params) list.push_back(p.second.get_value<double>() * 1us); return list.size(); } -void AgcExposureMode::Read(boost::property_tree::ptree const ¶ms) +void AgcExposureMode::read(boost::property_tree::ptree const ¶ms) { - int num_shutters = read_list(shutter, params.get_child("shutter")); - int num_ags = read_list(gain, params.get_child("gain")); - if (num_shutters < 2 || num_ags < 2) + int numShutters = readList(shutter, params.get_child("shutter")); + int numAgs = readList(gain, params.get_child("gain")); + if (numShutters < 2 || numAgs < 2) throw std::runtime_error( "AgcConfig: must have at least two entries in exposure profile"); - if (num_shutters != num_ags) + if (numShutters != numAgs) throw std::runtime_error( "AgcConfig: expect same number of exposure and gain entries in exposure profile"); } static std::string -read_exposure_modes(std::map<std::string, AgcExposureMode> &exposure_modes, - boost::property_tree::ptree const ¶ms) +readExposureModes(std::map<std::string, AgcExposureMode> &exposureModes, + boost::property_tree::ptree const ¶ms) { std::string first; for (auto &p : params) { - AgcExposureMode exposure_mode; - exposure_mode.Read(p.second); - exposure_modes[p.first] = std::move(exposure_mode); + AgcExposureMode exposureMode; + exposureMode.read(p.second); + exposureModes[p.first] = std::move(exposureMode); if (first.empty()) first = p.first; } return first; } -void AgcConstraint::Read(boost::property_tree::ptree const ¶ms) +void AgcConstraint::read(boost::property_tree::ptree const ¶ms) { - std::string bound_string = params.get<std::string>("bound", ""); - transform(bound_string.begin(), bound_string.end(), - bound_string.begin(), ::toupper); - if (bound_string != "UPPER" && bound_string != "LOWER") + std::string boundString = params.get<std::string>("bound", ""); + transform(boundString.begin(), boundString.end(), + boundString.begin(), ::toupper); + if (boundString != "UPPER" && boundString != "LOWER") throw std::runtime_error( "AGC constraint type should be UPPER or LOWER"); - bound = bound_string == "UPPER" ? Bound::UPPER : Bound::LOWER; - q_lo = params.get<double>("q_lo"); - q_hi = params.get<double>("q_hi"); - Y_target.Read(params.get_child("y_target")); + bound = boundString == "UPPER" ? Bound::UPPER : Bound::LOWER; + qLo = params.get<double>("q_lo"); + qHi = params.get<double>("q_hi"); + yTarget.read(params.get_child("y_target")); } static AgcConstraintMode -read_constraint_mode(boost::property_tree::ptree const ¶ms) +readConstraintMode(boost::property_tree::ptree const ¶ms) { AgcConstraintMode mode; for (auto &p : params) { AgcConstraint constraint; - constraint.Read(p.second); + constraint.read(p.second); mode.push_back(std::move(constraint)); } return mode; } -static std::string read_constraint_modes( - std::map<std::string, AgcConstraintMode> &constraint_modes, - boost::property_tree::ptree const ¶ms) +static std::string readConstraintModes(std::map<std::string, AgcConstraintMode> &constraintModes, + boost::property_tree::ptree const ¶ms) { std::string first; for (auto &p : params) { - constraint_modes[p.first] = read_constraint_mode(p.second); + constraintModes[p.first] = readConstraintMode(p.second); if (first.empty()) first = p.first; } return first; } -void AgcConfig::Read(boost::property_tree::ptree const ¶ms) +void AgcConfig::read(boost::property_tree::ptree const ¶ms) { LOG(RPiAgc, Debug) << "AgcConfig"; - default_metering_mode = read_metering_modes( - metering_modes, params.get_child("metering_modes")); - default_exposure_mode = read_exposure_modes( - exposure_modes, params.get_child("exposure_modes")); - default_constraint_mode = read_constraint_modes( - constraint_modes, params.get_child("constraint_modes")); - Y_target.Read(params.get_child("y_target")); + defaultMeteringMode = readMeteringModes(meteringModes, params.get_child("metering_modes")); + defaultExposureMode = readExposureModes(exposureModes, params.get_child("exposure_modes")); + defaultConstraintMode = readConstraintModes(constraintModes, params.get_child("constraint_modes")); + yTarget.read(params.get_child("y_target")); speed = params.get<double>("speed", 0.2); - startup_frames = params.get<uint16_t>("startup_frames", 10); - convergence_frames = params.get<unsigned int>("convergence_frames", 6); - fast_reduce_threshold = - params.get<double>("fast_reduce_threshold", 0.4); - base_ev = params.get<double>("base_ev", 1.0); + startupFrames = params.get<uint16_t>("startup_frames", 10); + convergenceFrames = params.get<unsigned int>("convergence_frames", 6); + fastReduceThreshold = params.get<double>("fast_reduce_threshold", 0.4); + baseEv = params.get<double>("base_ev", 1.0); // Start with quite a low value as ramping up is easier than ramping down. - default_exposure_time = params.get<double>("default_exposure_time", 1000) * 1us; - default_analogue_gain = params.get<double>("default_analogue_gain", 1.0); + defaultExposureTime = params.get<double>("default_exposure_time", 1000) * 1us; + defaultAnalogueGain = params.get<double>("default_analogueGain", 1.0); } Agc::ExposureValues::ExposureValues() - : shutter(0s), analogue_gain(0), - total_exposure(0s), total_exposure_no_dg(0s) + : shutter(0s), analogueGain(0), + totalExposure(0s), totalExposureNoDG(0s) { } Agc::Agc(Controller *controller) - : AgcAlgorithm(controller), metering_mode_(nullptr), - exposure_mode_(nullptr), constraint_mode_(nullptr), - frame_count_(0), lock_count_(0), - last_target_exposure_(0s), last_sensitivity_(0.0), - ev_(1.0), flicker_period_(0s), - max_shutter_(0s), fixed_shutter_(0s), fixed_analogue_gain_(0.0) + : AgcAlgorithm(controller), meteringMode_(nullptr), + exposureMode_(nullptr), constraintMode_(nullptr), + frameCount_(0), lockCount_(0), + lastTargetExposure_(0s), lastSensitivity_(0.0), + ev_(1.0), flickerPeriod_(0s), + maxShutter_(0s), fixedShutter_(0s), fixedAnalogueGain_(0.0) { memset(&awb_, 0, sizeof(awb_)); - // Setting status_.total_exposure_value_ to zero initially tells us + // Setting status_.totalExposureValue_ to zero initially tells us // it's not been calculated yet (i.e. Process hasn't yet run). memset(&status_, 0, sizeof(status_)); status_.ev = ev_; } -char const *Agc::Name() const +char const *Agc::name() const { return NAME; } -void Agc::Read(boost::property_tree::ptree const ¶ms) +void Agc::read(boost::property_tree::ptree const ¶ms) { LOG(RPiAgc, Debug) << "Agc"; - config_.Read(params); + config_.read(params); // Set the config's defaults (which are the first ones it read) as our // current modes, until someone changes them. (they're all known to // exist at this point) - metering_mode_name_ = config_.default_metering_mode; - metering_mode_ = &config_.metering_modes[metering_mode_name_]; - exposure_mode_name_ = config_.default_exposure_mode; - exposure_mode_ = &config_.exposure_modes[exposure_mode_name_]; - constraint_mode_name_ = config_.default_constraint_mode; - constraint_mode_ = &config_.constraint_modes[constraint_mode_name_]; + meteringModeName_ = config_.defaultMeteringMode; + meteringMode_ = &config_.meteringModes[meteringModeName_]; + exposureModeName_ = config_.defaultExposureMode; + exposureMode_ = &config_.exposureModes[exposureModeName_]; + constraintModeName_ = config_.defaultConstraintMode; + constraintMode_ = &config_.constraintModes[constraintModeName_]; // Set up the "last shutter/gain" values, in case AGC starts "disabled". - status_.shutter_time = config_.default_exposure_time; - status_.analogue_gain = config_.default_analogue_gain; + status_.shutterTime = config_.defaultExposureTime; + status_.analogueGain = config_.defaultAnalogueGain; } -bool Agc::IsPaused() const +bool Agc::isPaused() const { return false; } -void Agc::Pause() +void Agc::pause() { - fixed_shutter_ = status_.shutter_time; - fixed_analogue_gain_ = status_.analogue_gain; + fixedShutter_ = status_.shutterTime; + fixedAnalogueGain_ = status_.analogueGain; } -void Agc::Resume() +void Agc::resume() { - fixed_shutter_ = 0s; - fixed_analogue_gain_ = 0; + fixedShutter_ = 0s; + fixedAnalogueGain_ = 0; } -unsigned int Agc::GetConvergenceFrames() const +unsigned int Agc::getConvergenceFrames() const { // If shutter and gain have been explicitly set, there is no // convergence to happen, so no need to drop any frames - return zero. - if (fixed_shutter_ && fixed_analogue_gain_) + if (fixedShutter_ && fixedAnalogueGain_) return 0; else - return config_.convergence_frames; + return config_.convergenceFrames; } -void Agc::SetEv(double ev) +void Agc::setEv(double ev) { ev_ = ev; } -void Agc::SetFlickerPeriod(Duration flicker_period) +void Agc::setFlickerPeriod(Duration flickerPeriod) { - flicker_period_ = flicker_period; + flickerPeriod_ = flickerPeriod; } -void Agc::SetMaxShutter(Duration max_shutter) +void Agc::setMaxShutter(Duration maxShutter) { - max_shutter_ = max_shutter; + maxShutter_ = maxShutter; } -void Agc::SetFixedShutter(Duration fixed_shutter) +void Agc::setFixedShutter(Duration fixedShutter) { - fixed_shutter_ = fixed_shutter; + fixedShutter_ = fixedShutter; // Set this in case someone calls Pause() straight after. - status_.shutter_time = clipShutter(fixed_shutter_); + status_.shutterTime = clipShutter(fixedShutter_); } -void Agc::SetFixedAnalogueGain(double fixed_analogue_gain) +void Agc::setFixedAnalogueGain(double fixedAnalogueGain) { - fixed_analogue_gain_ = fixed_analogue_gain; + fixedAnalogueGain_ = fixedAnalogueGain_; // Set this in case someone calls Pause() straight after. - status_.analogue_gain = fixed_analogue_gain; + status_.analogueGain = fixedAnalogueGain; } -void Agc::SetMeteringMode(std::string const &metering_mode_name) +void Agc::setMeteringMode(std::string const &meteringModeName) { - metering_mode_name_ = metering_mode_name; + meteringModeName_ = meteringModeName; } -void Agc::SetExposureMode(std::string const &exposure_mode_name) +void Agc::setExposureMode(std::string const &exposureModeName) { - exposure_mode_name_ = exposure_mode_name; + exposureModeName_ = exposureModeName; } -void Agc::SetConstraintMode(std::string const &constraint_mode_name) +void Agc::setConstraintMode(std::string const &constraintModeName) { - constraint_mode_name_ = constraint_mode_name; + constraintModeName_ = constraintModeName; } -void Agc::SwitchMode(CameraMode const &camera_mode, +void Agc::switchMode(CameraMode const &cameraMode, Metadata *metadata) { /* AGC expects the mode sensitivity always to be non-zero. */ - ASSERT(camera_mode.sensitivity); + ASSERT(cameraMode.sensitivity); housekeepConfig(); - Duration fixed_shutter = clipShutter(fixed_shutter_); - if (fixed_shutter && fixed_analogue_gain_) { + Duration fixedShutter = clipShutter(fixedShutter_); + if (fixedShutter && fixedAnalogueGain_) { // We're going to reset the algorithm here with these fixed values. fetchAwbStatus(metadata); - double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 }); - ASSERT(min_colour_gain != 0.0); + double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 }); + ASSERT(minColourGain != 0.0); // This is the equivalent of computeTargetExposure and applyDigitalGain. - target_.total_exposure_no_dg = fixed_shutter * fixed_analogue_gain_; - target_.total_exposure = target_.total_exposure_no_dg / min_colour_gain; + target_.totalExposureNoDG = fixedShutter_ * fixedAnalogueGain_; + target_.totalExposure = target_.totalExposureNoDG / minColourGain; // Equivalent of filterExposure. This resets any "history". filtered_ = target_; // Equivalent of divideUpExposure. - filtered_.shutter = fixed_shutter; - filtered_.analogue_gain = fixed_analogue_gain_; - } else if (status_.total_exposure_value) { + filtered_.shutter = fixedShutter; + filtered_.analogueGain = fixedAnalogueGain_; + } else if (status_.totalExposureValue) { // On a mode switch, various things could happen: // - the exposure profile might change // - a fixed exposure or gain might be set @@ -310,11 +305,11 @@ void Agc::SwitchMode(CameraMode const &camera_mode, // that we just need to re-divide the exposure/gain according to the // current exposure profile, which takes care of everything else. - double ratio = last_sensitivity_ / camera_mode.sensitivity; - target_.total_exposure_no_dg *= ratio; - target_.total_exposure *= ratio; - filtered_.total_exposure_no_dg *= ratio; - filtered_.total_exposure *= ratio; + double ratio = lastSensitivity_ / cameraMode.sensitivity; + target_.totalExposureNoDG *= ratio; + target_.totalExposure *= ratio; + filtered_.totalExposureNoDG *= ratio; + filtered_.totalExposure *= ratio; divideUpExposure(); } else { @@ -324,114 +319,110 @@ void Agc::SwitchMode(CameraMode const &camera_mode, // for any that weren't set. // Equivalent of divideUpExposure. - filtered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time; - filtered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain; + filtered_.shutter = fixedShutter ? fixedShutter : config_.defaultExposureTime; + filtered_.analogueGain = fixedAnalogueGain_ ? fixedAnalogueGain_ : config_.defaultAnalogueGain; } writeAndFinish(metadata, false); // We must remember the sensitivity of this mode for the next SwitchMode. - last_sensitivity_ = camera_mode.sensitivity; + lastSensitivity_ = cameraMode.sensitivity; } -void Agc::Prepare(Metadata *image_metadata) +void Agc::prepare(Metadata *imageMetadata) { - status_.digital_gain = 1.0; - fetchAwbStatus(image_metadata); // always fetch it so that Process knows it's been done + status_.digitalGain = 1.0; + fetchAwbStatus(imageMetadata); // always fetch it so that Process knows it's been done - if (status_.total_exposure_value) { + if (status_.totalExposureValue) { // Process has run, so we have meaningful values. - DeviceStatus device_status; - if (image_metadata->Get("device.status", device_status) == 0) { - Duration actual_exposure = device_status.shutter_speed * - device_status.analogue_gain; - if (actual_exposure) { - status_.digital_gain = - status_.total_exposure_value / - actual_exposure; - LOG(RPiAgc, Debug) << "Want total exposure " << status_.total_exposure_value; + DeviceStatus deviceStatus; + if (imageMetadata->get("device.status", deviceStatus) == 0) { + Duration actualExposure = deviceStatus.shutterSpeed * + deviceStatus.analogueGain; + if (actualExposure) { + status_.digitalGain = status_.totalExposureValue / actualExposure; + LOG(RPiAgc, Debug) << "Want total exposure " << status_.totalExposureValue; // Never ask for a gain < 1.0, and also impose // some upper limit. Make it customisable? - status_.digital_gain = std::max( - 1.0, - std::min(status_.digital_gain, 4.0)); - LOG(RPiAgc, Debug) << "Actual exposure " << actual_exposure; - LOG(RPiAgc, Debug) << "Use digital_gain " << status_.digital_gain; + status_.digitalGain = std::max(1.0, std::min(status_.digitalGain, 4.0)); + LOG(RPiAgc, Debug) << "Actual exposure " << actualExposure; + LOG(RPiAgc, Debug) << "Use digital_gain " << status_.digitalGain; LOG(RPiAgc, Debug) << "Effective exposure " - << actual_exposure * status_.digital_gain; + << actualExposure * status_.digitalGain; // Decide whether AEC/AGC has converged. - updateLockStatus(device_status); + updateLockStatus(deviceStatus); } } else - LOG(RPiAgc, Warning) << Name() << ": no device metadata"; - image_metadata->Set("agc.status", status_); + LOG(RPiAgc, Warning) << name() << ": no device metadata"; + imageMetadata->set("agc.status", status_); } } -void Agc::Process(StatisticsPtr &stats, Metadata *image_metadata) +void Agc::process(StatisticsPtr &stats, Metadata *imageMetadata) { - frame_count_++; + frameCount_++; // First a little bit of housekeeping, fetching up-to-date settings and // configuration, that kind of thing. housekeepConfig(); // Get the current exposure values for the frame that's just arrived. - fetchCurrentExposure(image_metadata); + fetchCurrentExposure(imageMetadata); // Compute the total gain we require relative to the current exposure. - double gain, target_Y; - computeGain(stats.get(), image_metadata, gain, target_Y); + double gain, targetY; + computeGain(stats.get(), imageMetadata, gain, targetY); // Now compute the target (final) exposure which we think we want. computeTargetExposure(gain); // Some of the exposure has to be applied as digital gain, so work out // what that is. This function also tells us whether it's decided to // "desaturate" the image more quickly. - bool desaturate = applyDigitalGain(gain, target_Y); + bool desaturate = applyDigitalGain(gain, targetY); // The results have to be filtered so as not to change too rapidly. filterExposure(desaturate); // The last thing is to divide up the exposure value into a shutter time - // and analogue_gain, according to the current exposure mode. + // and analogue gain, according to the current exposure mode. divideUpExposure(); // Finally advertise what we've done. - writeAndFinish(image_metadata, desaturate); + writeAndFinish(imageMetadata, desaturate); } -void Agc::updateLockStatus(DeviceStatus const &device_status) +void Agc::updateLockStatus(DeviceStatus const &deviceStatus) { - const double ERROR_FACTOR = 0.10; // make these customisable? - const int MAX_LOCK_COUNT = 5; - // Reset "lock count" when we exceed this multiple of ERROR_FACTOR - const double RESET_MARGIN = 1.5; + const double errorFactor = 0.10; // make these customisable? + const int maxLockCount = 5; + // Reset "lock count" when we exceed this multiple of errorFactor + const double resetMargin = 1.5; // Add 200us to the exposure time error to allow for line quantisation. - Duration exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200us; - double gain_error = last_device_status_.analogue_gain * ERROR_FACTOR; - Duration target_error = last_target_exposure_ * ERROR_FACTOR; + Duration exposureError = lastDeviceStatus_.shutterSpeed * errorFactor + 200us; + double gainError = lastDeviceStatus_.analogueGain * errorFactor; + Duration targetError = lastTargetExposure_ * errorFactor; // Note that we don't know the exposure/gain limits of the sensor, so // the values we keep requesting may be unachievable. For this reason // we only insist that we're close to values in the past few frames. - if (device_status.shutter_speed > last_device_status_.shutter_speed - exposure_error && - device_status.shutter_speed < last_device_status_.shutter_speed + exposure_error && - device_status.analogue_gain > last_device_status_.analogue_gain - gain_error && - device_status.analogue_gain < last_device_status_.analogue_gain + gain_error && - status_.target_exposure_value > last_target_exposure_ - target_error && - status_.target_exposure_value < last_target_exposure_ + target_error) - lock_count_ = std::min(lock_count_ + 1, MAX_LOCK_COUNT); - else if (device_status.shutter_speed < last_device_status_.shutter_speed - RESET_MARGIN * exposure_error || - device_status.shutter_speed > last_device_status_.shutter_speed + RESET_MARGIN * exposure_error || - device_status.analogue_gain < last_device_status_.analogue_gain - RESET_MARGIN * gain_error || - device_status.analogue_gain > last_device_status_.analogue_gain + RESET_MARGIN * gain_error || - status_.target_exposure_value < last_target_exposure_ - RESET_MARGIN * target_error || - status_.target_exposure_value > last_target_exposure_ + RESET_MARGIN * target_error) - lock_count_ = 0; - - last_device_status_ = device_status; - last_target_exposure_ = status_.target_exposure_value; - - LOG(RPiAgc, Debug) << "Lock count updated to " << lock_count_; - status_.locked = lock_count_ == MAX_LOCK_COUNT; -} - -static void copy_string(std::string const &s, char *d, size_t size) + if (deviceStatus.shutterSpeed > lastDeviceStatus_.shutterSpeed - exposureError && + deviceStatus.shutterSpeed < lastDeviceStatus_.shutterSpeed + exposureError && + deviceStatus.analogueGain > lastDeviceStatus_.analogueGain - gainError && + deviceStatus.analogueGain < lastDeviceStatus_.analogueGain + gainError && + status_.targetExposureValue > lastTargetExposure_ - targetError && + status_.targetExposureValue < lastTargetExposure_ + targetError) + lockCount_ = std::min(lockCount_ + 1, maxLockCount); + else if (deviceStatus.shutterSpeed < lastDeviceStatus_.shutterSpeed - resetMargin * exposureError || + deviceStatus.shutterSpeed > lastDeviceStatus_.shutterSpeed + resetMargin * exposureError || + deviceStatus.analogueGain < lastDeviceStatus_.analogueGain - resetMargin * gainError || + deviceStatus.analogueGain > lastDeviceStatus_.analogueGain + resetMargin * gainError || + status_.targetExposureValue < lastTargetExposure_ - resetMargin * targetError || + status_.targetExposureValue > lastTargetExposure_ + resetMargin * targetError) + lockCount_ = 0; + + lastDeviceStatus_ = deviceStatus; + lastTargetExposure_ = status_.targetExposureValue; + + LOG(RPiAgc, Debug) << "Lock count updated to " << lockCount_; + status_.locked = lockCount_ == maxLockCount; +} + +static void copyString(std::string const &s, char *d, size_t size) { size_t length = s.copy(d, size - 1); d[length] = '\0'; @@ -441,97 +432,97 @@ void Agc::housekeepConfig() { // First fetch all the up-to-date settings, so no one else has to do it. status_.ev = ev_; - status_.fixed_shutter = clipShutter(fixed_shutter_); - status_.fixed_analogue_gain = fixed_analogue_gain_; - status_.flicker_period = flicker_period_; - LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixed_shutter " - << status_.fixed_shutter << " fixed_analogue_gain " - << status_.fixed_analogue_gain; + status_.fixedShutter = clipShutter(fixedShutter_); + status_.fixedAnalogueGain = fixedAnalogueGain_; + status_.flickerPeriod = flickerPeriod_; + LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixedShutter " + << status_.fixedShutter << " fixedAnalogueGain " + << status_.fixedAnalogueGain; // Make sure the "mode" pointers point to the up-to-date things, if // they've changed. - if (strcmp(metering_mode_name_.c_str(), status_.metering_mode)) { - auto it = config_.metering_modes.find(metering_mode_name_); - if (it == config_.metering_modes.end()) + if (strcmp(meteringModeName_.c_str(), status_.meteringMode)) { + auto it = config_.meteringModes.find(meteringModeName_); + if (it == config_.meteringModes.end()) throw std::runtime_error("Agc: no metering mode " + - metering_mode_name_); - metering_mode_ = &it->second; - copy_string(metering_mode_name_, status_.metering_mode, - sizeof(status_.metering_mode)); + meteringModeName_); + meteringMode_ = &it->second; + copyString(meteringModeName_, status_.meteringMode, + sizeof(status_.meteringMode)); } - if (strcmp(exposure_mode_name_.c_str(), status_.exposure_mode)) { - auto it = config_.exposure_modes.find(exposure_mode_name_); - if (it == config_.exposure_modes.end()) + if (strcmp(exposureModeName_.c_str(), status_.exposureMode)) { + auto it = config_.exposureModes.find(exposureModeName_); + if (it == config_.exposureModes.end()) throw std::runtime_error("Agc: no exposure profile " + - exposure_mode_name_); - exposure_mode_ = &it->second; - copy_string(exposure_mode_name_, status_.exposure_mode, - sizeof(status_.exposure_mode)); + exposureModeName_); + exposureMode_ = &it->second; + copyString(exposureModeName_, status_.exposureMode, + sizeof(status_.exposureMode)); } - if (strcmp(constraint_mode_name_.c_str(), status_.constraint_mode)) { + if (strcmp(constraintModeName_.c_str(), status_.constraint_mode)) { auto it = - config_.constraint_modes.find(constraint_mode_name_); - if (it == config_.constraint_modes.end()) + config_.constraintModes.find(constraintModeName_); + if (it == config_.constraintModes.end()) throw std::runtime_error("Agc: no constraint list " + - constraint_mode_name_); - constraint_mode_ = &it->second; - copy_string(constraint_mode_name_, status_.constraint_mode, - sizeof(status_.constraint_mode)); + constraintModeName_); + constraintMode_ = &it->second; + copyString(constraintModeName_, status_.constraint_mode, + sizeof(status_.constraint_mode)); } - LOG(RPiAgc, Debug) << "exposure_mode " - << exposure_mode_name_ << " constraint_mode " - << constraint_mode_name_ << " metering_mode " - << metering_mode_name_; + LOG(RPiAgc, Debug) << "exposureMode " + << exposureModeName_ << " constraint_mode " + << constraintModeName_ << " meteringMode " + << meteringModeName_; } -void Agc::fetchCurrentExposure(Metadata *image_metadata) +void Agc::fetchCurrentExposure(Metadata *imageMetadata) { - std::unique_lock<Metadata> lock(*image_metadata); - DeviceStatus *device_status = - image_metadata->GetLocked<DeviceStatus>("device.status"); - if (!device_status) + std::unique_lock<Metadata> lock(*imageMetadata); + DeviceStatus *deviceStatus = + imageMetadata->getLocked<DeviceStatus>("device.status"); + if (!deviceStatus) throw std::runtime_error("Agc: no device metadata"); - current_.shutter = device_status->shutter_speed; - current_.analogue_gain = device_status->analogue_gain; - AgcStatus *agc_status = - image_metadata->GetLocked<AgcStatus>("agc.status"); - current_.total_exposure = agc_status ? agc_status->total_exposure_value : 0s; - current_.total_exposure_no_dg = current_.shutter * current_.analogue_gain; + current_.shutter = deviceStatus->shutterSpeed; + current_.analogueGain = deviceStatus->analogueGain; + AgcStatus *agcStatus = + imageMetadata->getLocked<AgcStatus>("agc.status"); + current_.totalExposure = agcStatus ? agcStatus->totalExposureValue : 0s; + current_.totalExposureNoDG = current_.shutter * current_.analogueGain; } -void Agc::fetchAwbStatus(Metadata *image_metadata) +void Agc::fetchAwbStatus(Metadata *imageMetadata) { - awb_.gain_r = 1.0; // in case not found in metadata - awb_.gain_g = 1.0; - awb_.gain_b = 1.0; - if (image_metadata->Get("awb.status", awb_) != 0) + awb_.gainR = 1.0; // in case not found in metadata + awb_.gainG = 1.0; + awb_.gainB = 1.0; + if (imageMetadata->get("awb.status", awb_) != 0) LOG(RPiAgc, Debug) << "Agc: no AWB status found"; } -static double compute_initial_Y(bcm2835_isp_stats *stats, AwbStatus const &awb, - double weights[], double gain) +static double computeInitialY(bcm2835_isp_stats *stats, AwbStatus const &awb, + double weights[], double gain) { bcm2835_isp_stats_region *regions = stats->agc_stats; // Note how the calculation below means that equal weights give you // "average" metering (i.e. all pixels equally important). - double R_sum = 0, G_sum = 0, B_sum = 0, pixel_sum = 0; + double rSum = 0, gSum = 0, bSum = 0, pixelSum = 0; for (int i = 0; i < AGC_STATS_SIZE; i++) { double counted = regions[i].counted; - double r_sum = std::min(regions[i].r_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); - double g_sum = std::min(regions[i].g_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); - double b_sum = std::min(regions[i].b_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); - R_sum += r_sum * weights[i]; - G_sum += g_sum * weights[i]; - B_sum += b_sum * weights[i]; - pixel_sum += counted * weights[i]; + double rAcc = std::min(regions[i].r_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); + double gAcc = std::min(regions[i].g_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); + double bAcc = std::min(regions[i].b_sum * gain, ((1 << PIPELINE_BITS) - 1) * counted); + rSum += rAcc * weights[i]; + gSum += gAcc * weights[i]; + bSum += bAcc * weights[i]; + pixelSum += counted * weights[i]; } - if (pixel_sum == 0.0) { + if (pixelSum == 0.0) { LOG(RPiAgc, Warning) << "compute_initial_Y: pixel_sum is zero"; return 0; } - double Y_sum = R_sum * awb.gain_r * .299 + - G_sum * awb.gain_g * .587 + - B_sum * awb.gain_b * .114; - return Y_sum / pixel_sum / (1 << PIPELINE_BITS); + double ySum = rSum * awb.gainR * .299 + + gSum * awb.gainG * .587 + + bSum * awb.gainB * .114; + return ySum / pixelSum / (1 << PIPELINE_BITS); } // We handle extra gain through EV by adjusting our Y targets. However, you @@ -542,108 +533,102 @@ static double compute_initial_Y(bcm2835_isp_stats *stats, AwbStatus const &awb, #define EV_GAIN_Y_TARGET_LIMIT 0.9 -static double constraint_compute_gain(AgcConstraint &c, Histogram &h, - double lux, double ev_gain, - double &target_Y) +static double constraintComputeGain(AgcConstraint &c, Histogram &h, double lux, + double evGain, double &targetY) { - target_Y = c.Y_target.Eval(c.Y_target.Domain().Clip(lux)); - target_Y = std::min(EV_GAIN_Y_TARGET_LIMIT, target_Y * ev_gain); - double iqm = h.InterQuantileMean(c.q_lo, c.q_hi); - return (target_Y * NUM_HISTOGRAM_BINS) / iqm; + targetY = c.yTarget.eval(c.yTarget.domain().clip(lux)); + targetY = std::min(EV_GAIN_Y_TARGET_LIMIT, targetY * evGain); + double iqm = h.interQuantileMean(c.qLo, c.qHi); + return (targetY * NUM_HISTOGRAM_BINS) / iqm; } -void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata, - double &gain, double &target_Y) +void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *imageMetadata, + double &gain, double &targetY) { struct LuxStatus lux = {}; lux.lux = 400; // default lux level to 400 in case no metadata found - if (image_metadata->Get("lux.status", lux) != 0) + if (imageMetadata->get("lux.status", lux) != 0) LOG(RPiAgc, Warning) << "Agc: no lux level found"; Histogram h(statistics->hist[0].g_hist, NUM_HISTOGRAM_BINS); - double ev_gain = status_.ev * config_.base_ev; + double evGain = status_.ev * config_.baseEv; // The initial gain and target_Y come from some of the regions. After // that we consider the histogram constraints. - target_Y = - config_.Y_target.Eval(config_.Y_target.Domain().Clip(lux.lux)); - target_Y = std::min(EV_GAIN_Y_TARGET_LIMIT, target_Y * ev_gain); + targetY = config_.yTarget.eval(config_.yTarget.domain().clip(lux.lux)); + targetY = std::min(EV_GAIN_Y_TARGET_LIMIT, targetY * evGain); // Do this calculation a few times as brightness increase can be // non-linear when there are saturated regions. gain = 1.0; for (int i = 0; i < 8; i++) { - double initial_Y = compute_initial_Y(statistics, awb_, - metering_mode_->weights, gain); - double extra_gain = std::min(10.0, target_Y / (initial_Y + .001)); - gain *= extra_gain; - LOG(RPiAgc, Debug) << "Initial Y " << initial_Y << " target " << target_Y + double initialY = computeInitialY(statistics, awb_, meteringMode_->weights, gain); + double extraGain = std::min(10.0, targetY / (initialY + .001)); + gain *= extraGain; + LOG(RPiAgc, Debug) << "Initial Y " << initialY << " target " << targetY << " gives gain " << gain; - if (extra_gain < 1.01) // close enough + if (extraGain < 1.01) // close enough break; } - for (auto &c : *constraint_mode_) { - double new_target_Y; - double new_gain = - constraint_compute_gain(c, h, lux.lux, ev_gain, - new_target_Y); + for (auto &c : *constraintMode_) { + double newTargetY; + double newGain = constraintComputeGain(c, h, lux.lux, evGain, newTargetY); LOG(RPiAgc, Debug) << "Constraint has target_Y " - << new_target_Y << " giving gain " << new_gain; - if (c.bound == AgcConstraint::Bound::LOWER && - new_gain > gain) { + << newTargetY << " giving gain " << newGain; + if (c.bound == AgcConstraint::Bound::LOWER && newGain > gain) { LOG(RPiAgc, Debug) << "Lower bound constraint adopted"; - gain = new_gain, target_Y = new_target_Y; - } else if (c.bound == AgcConstraint::Bound::UPPER && - new_gain < gain) { + gain = newGain; + targetY = newTargetY; + } else if (c.bound == AgcConstraint::Bound::UPPER && newGain < gain) { LOG(RPiAgc, Debug) << "Upper bound constraint adopted"; - gain = new_gain, target_Y = new_target_Y; + gain = newGain; + targetY = newTargetY; } } - LOG(RPiAgc, Debug) << "Final gain " << gain << " (target_Y " << target_Y << " ev " - << status_.ev << " base_ev " << config_.base_ev + LOG(RPiAgc, Debug) << "Final gain " << gain << " (target_Y " << targetY << " ev " + << status_.ev << " base_ev " << config_.baseEv << ")"; } void Agc::computeTargetExposure(double gain) { - if (status_.fixed_shutter && status_.fixed_analogue_gain) { + if (status_.fixedShutter && status_.fixedAnalogueGain) { // When ag and shutter are both fixed, we need to drive the // total exposure so that we end up with a digital gain of at least // 1/min_colour_gain. Otherwise we'd desaturate channels causing // white to go cyan or magenta. - double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 }); - ASSERT(min_colour_gain != 0.0); - target_.total_exposure = - status_.fixed_shutter * status_.fixed_analogue_gain / min_colour_gain; + double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 }); + ASSERT(minColourGain != 0.0); + target_.totalExposure = + status_.fixedShutter * status_.fixedAnalogueGain / minColourGain; } else { // The statistics reflect the image without digital gain, so the final // total exposure we're aiming for is: - target_.total_exposure = current_.total_exposure_no_dg * gain; + target_.totalExposure = current_.totalExposureNoDG * gain; // The final target exposure is also limited to what the exposure // mode allows. - Duration max_shutter = status_.fixed_shutter - ? status_.fixed_shutter - : exposure_mode_->shutter.back(); - max_shutter = clipShutter(max_shutter); - Duration max_total_exposure = - max_shutter * - (status_.fixed_analogue_gain != 0.0 - ? status_.fixed_analogue_gain - : exposure_mode_->gain.back()); - target_.total_exposure = std::min(target_.total_exposure, - max_total_exposure); + Duration maxShutter = status_.fixedShutter + ? status_.fixedShutter + : exposureMode_->shutter.back(); + maxShutter = clipShutter(maxShutter); + Duration maxTotalExposure = + maxShutter * + (status_.fixedAnalogueGain != 0.0 + ? status_.fixedAnalogueGain + : exposureMode_->gain.back()); + target_.totalExposure = std::min(target_.totalExposure, maxTotalExposure); } - LOG(RPiAgc, Debug) << "Target total_exposure " << target_.total_exposure; + LOG(RPiAgc, Debug) << "Target totalExposure " << target_.totalExposure; } -bool Agc::applyDigitalGain(double gain, double target_Y) +bool Agc::applyDigitalGain(double gain, double targetY) { - double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 }); - ASSERT(min_colour_gain != 0.0); - double dg = 1.0 / min_colour_gain; + double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 }); + ASSERT(minColourGain != 0.0); + double dg = 1.0 / minColourGain; // I think this pipeline subtracts black level and rescales before we // get the stats, so no need to worry about it. LOG(RPiAgc, Debug) << "after AWB, target dg " << dg << " gain " << gain - << " target_Y " << target_Y; + << " target_Y " << targetY; // Finally, if we're trying to reduce exposure but the target_Y is // "close" to 1.0, then the gain computed for that constraint will be // only slightly less than one, because the measured Y can never be @@ -651,13 +636,13 @@ bool Agc::applyDigitalGain(double gain, double target_Y) // that the exposure can be reduced, de-saturating the image much more // quickly (and we then approach the correct value more quickly from // below). - bool desaturate = target_Y > config_.fast_reduce_threshold && - gain < sqrt(target_Y); + bool desaturate = targetY > config_.fastReduceThreshold && + gain < sqrt(targetY); if (desaturate) - dg /= config_.fast_reduce_threshold; + dg /= config_.fastReduceThreshold; LOG(RPiAgc, Debug) << "Digital gain " << dg << " desaturate? " << desaturate; - target_.total_exposure_no_dg = target_.total_exposure / dg; - LOG(RPiAgc, Debug) << "Target total_exposure_no_dg " << target_.total_exposure_no_dg; + target_.totalExposureNoDG = target_.totalExposure / dg; + LOG(RPiAgc, Debug) << "Target totalExposureNoDG " << target_.totalExposureNoDG; return desaturate; } @@ -666,39 +651,38 @@ void Agc::filterExposure(bool desaturate) double speed = config_.speed; // AGC adapts instantly if both shutter and gain are directly specified // or we're in the startup phase. - if ((status_.fixed_shutter && status_.fixed_analogue_gain) || - frame_count_ <= config_.startup_frames) + if ((status_.fixedShutter && status_.fixedAnalogueGain) || + frameCount_ <= config_.startupFrames) speed = 1.0; - if (!filtered_.total_exposure) { - filtered_.total_exposure = target_.total_exposure; - filtered_.total_exposure_no_dg = target_.total_exposure_no_dg; + if (!filtered_.totalExposure) { + filtered_.totalExposure = target_.totalExposure; + filtered_.totalExposureNoDG = target_.totalExposureNoDG; } else { // If close to the result go faster, to save making so many // micro-adjustments on the way. (Make this customisable?) - if (filtered_.total_exposure < 1.2 * target_.total_exposure && - filtered_.total_exposure > 0.8 * target_.total_exposure) + if (filtered_.totalExposure < 1.2 * target_.totalExposure && + filtered_.totalExposure > 0.8 * target_.totalExposure) speed = sqrt(speed); - filtered_.total_exposure = speed * target_.total_exposure + - filtered_.total_exposure * (1.0 - speed); + filtered_.totalExposure = speed * target_.totalExposure + + filtered_.totalExposure * (1.0 - speed); // When desaturing, take a big jump down in exposure_no_dg, // which we'll hide with digital gain. if (desaturate) - filtered_.total_exposure_no_dg = - target_.total_exposure_no_dg; + filtered_.totalExposureNoDG = + target_.totalExposureNoDG; else - filtered_.total_exposure_no_dg = - speed * target_.total_exposure_no_dg + - filtered_.total_exposure_no_dg * (1.0 - speed); + filtered_.totalExposureNoDG = + speed * target_.totalExposureNoDG + + filtered_.totalExposureNoDG * (1.0 - speed); } // We can't let the no_dg exposure deviate too far below the // total exposure, as there might not be enough digital gain available // in the ISP to hide it (which will cause nasty oscillation). - if (filtered_.total_exposure_no_dg < - filtered_.total_exposure * config_.fast_reduce_threshold) - filtered_.total_exposure_no_dg = filtered_.total_exposure * - config_.fast_reduce_threshold; - LOG(RPiAgc, Debug) << "After filtering, total_exposure " << filtered_.total_exposure - << " no dg " << filtered_.total_exposure_no_dg; + if (filtered_.totalExposureNoDG < + filtered_.totalExposure * config_.fastReduceThreshold) + filtered_.totalExposureNoDG = filtered_.totalExposure * config_.fastReduceThreshold; + LOG(RPiAgc, Debug) << "After filtering, totalExposure " << filtered_.totalExposure + << " no dg " << filtered_.totalExposureNoDG; } void Agc::divideUpExposure() @@ -706,92 +690,84 @@ void Agc::divideUpExposure() // Sending the fixed shutter/gain cases through the same code may seem // unnecessary, but it will make more sense when extend this to cover // variable aperture. - Duration exposure_value = filtered_.total_exposure_no_dg; - Duration shutter_time; - double analogue_gain; - shutter_time = status_.fixed_shutter - ? status_.fixed_shutter - : exposure_mode_->shutter[0]; - shutter_time = clipShutter(shutter_time); - analogue_gain = status_.fixed_analogue_gain != 0.0 - ? status_.fixed_analogue_gain - : exposure_mode_->gain[0]; - if (shutter_time * analogue_gain < exposure_value) { + Duration exposureValue = filtered_.totalExposureNoDG; + Duration shutterTime; + double analogueGain; + shutterTime = status_.fixedShutter ? status_.fixedShutter + : exposureMode_->shutter[0]; + shutterTime = clipShutter(shutterTime); + analogueGain = status_.fixedAnalogueGain != 0.0 ? status_.fixedAnalogueGain + : exposureMode_->gain[0]; + if (shutterTime * analogueGain < exposureValue) { for (unsigned int stage = 1; - stage < exposure_mode_->gain.size(); stage++) { - if (!status_.fixed_shutter) { + stage < exposureMode_->gain.size(); stage++) { + if (!status_.fixedShutter) { Duration stage_shutter = - clipShutter(exposure_mode_->shutter[stage]); - if (stage_shutter * analogue_gain >= - exposure_value) { - shutter_time = - exposure_value / analogue_gain; + clipShutter(exposureMode_->shutter[stage]); + if (stage_shutter * analogueGain >= exposureValue) { + shutterTime = exposureValue / analogueGain; break; } - shutter_time = stage_shutter; + shutterTime = stage_shutter; } - if (status_.fixed_analogue_gain == 0.0) { - if (exposure_mode_->gain[stage] * - shutter_time >= - exposure_value) { - analogue_gain = - exposure_value / shutter_time; + if (status_.fixedAnalogueGain == 0.0) { + if (exposureMode_->gain[stage] * shutterTime >= exposureValue) { + analogueGain = exposureValue / shutterTime; break; } - analogue_gain = exposure_mode_->gain[stage]; + analogueGain = exposureMode_->gain[stage]; } } } - LOG(RPiAgc, Debug) << "Divided up shutter and gain are " << shutter_time << " and " - << analogue_gain; + LOG(RPiAgc, Debug) << "Divided up shutter and gain are " << shutterTime << " and " + << analogueGain; // Finally adjust shutter time for flicker avoidance (require both // shutter and gain not to be fixed). - if (!status_.fixed_shutter && !status_.fixed_analogue_gain && - status_.flicker_period) { - int flicker_periods = shutter_time / status_.flicker_period; - if (flicker_periods) { - Duration new_shutter_time = flicker_periods * status_.flicker_period; - analogue_gain *= shutter_time / new_shutter_time; + if (!status_.fixedShutter && !status_.fixedAnalogueGain && + status_.flickerPeriod) { + int flickerPeriods = shutterTime / status_.flickerPeriod; + if (flickerPeriods) { + Duration newShutterTime = flickerPeriods * status_.flickerPeriod; + analogueGain *= shutterTime / newShutterTime; // We should still not allow the ag to go over the // largest value in the exposure mode. Note that this // may force more of the total exposure into the digital // gain as a side-effect. - analogue_gain = std::min(analogue_gain, - exposure_mode_->gain.back()); - shutter_time = new_shutter_time; + analogueGain = std::min(analogueGain, exposureMode_->gain.back()); + shutterTime = newShutterTime; } LOG(RPiAgc, Debug) << "After flicker avoidance, shutter " - << shutter_time << " gain " << analogue_gain; + << shutterTime << " gain " << analogueGain; } - filtered_.shutter = shutter_time; - filtered_.analogue_gain = analogue_gain; + filtered_.shutter = shutterTime; + filtered_.analogueGain = analogueGain; } -void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate) +void Agc::writeAndFinish(Metadata *imageMetadata, bool desaturate) { - status_.total_exposure_value = filtered_.total_exposure; - status_.target_exposure_value = desaturate ? 0s : target_.total_exposure_no_dg; - status_.shutter_time = filtered_.shutter; - status_.analogue_gain = filtered_.analogue_gain; + status_.totalExposureValue = filtered_.totalExposure; + status_.targetExposureValue = desaturate ? 0s : target_.totalExposureNoDG; + status_.shutterTime = filtered_.shutter; + status_.analogueGain = filtered_.analogueGain; // Write to metadata as well, in case anyone wants to update the camera // immediately. - image_metadata->Set("agc.status", status_); + imageMetadata->set("agc.status", status_); LOG(RPiAgc, Debug) << "Output written, total exposure requested is " - << filtered_.total_exposure; + << filtered_.totalExposure; LOG(RPiAgc, Debug) << "Camera exposure update: shutter time " << filtered_.shutter - << " analogue gain " << filtered_.analogue_gain; + << " analogue gain " << filtered_.analogueGain; } Duration Agc::clipShutter(Duration shutter) { - if (max_shutter_) - shutter = std::min(shutter, max_shutter_); + if (maxShutter_) + shutter = std::min(shutter, maxShutter_); return shutter; } // Register algorithm with the system. -static Algorithm *Create(Controller *controller) +static Algorithm *create(Controller *controller) { return (Algorithm *)new Agc(controller); } -static RegisterAlgorithm reg(NAME, &Create); +static RegisterAlgorithm reg(NAME, &create); diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp index c100d3128c90..4ed7293bce97 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.hpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp @@ -26,114 +26,114 @@ namespace RPiController { struct AgcMeteringMode { double weights[AGC_STATS_SIZE]; - void Read(boost::property_tree::ptree const ¶ms); + void read(boost::property_tree::ptree const ¶ms); }; struct AgcExposureMode { std::vector<libcamera::utils::Duration> shutter; std::vector<double> gain; - void Read(boost::property_tree::ptree const ¶ms); + void read(boost::property_tree::ptree const ¶ms); }; struct AgcConstraint { enum class Bound { LOWER = 0, UPPER = 1 }; Bound bound; - double q_lo; - double q_hi; - Pwl Y_target; - void Read(boost::property_tree::ptree const ¶ms); + double qLo; + double qHi; + Pwl yTarget; + void read(boost::property_tree::ptree const ¶ms); }; typedef std::vector<AgcConstraint> AgcConstraintMode; struct AgcConfig { - void Read(boost::property_tree::ptree const ¶ms); - std::map<std::string, AgcMeteringMode> metering_modes; - std::map<std::string, AgcExposureMode> exposure_modes; - std::map<std::string, AgcConstraintMode> constraint_modes; - Pwl Y_target; + void read(boost::property_tree::ptree const ¶ms); + std::map<std::string, AgcMeteringMode> meteringModes; + std::map<std::string, AgcExposureMode> exposureModes; + std::map<std::string, AgcConstraintMode> constraintModes; + Pwl yTarget; double speed; - uint16_t startup_frames; - unsigned int convergence_frames; - double max_change; - double min_change; - double fast_reduce_threshold; - double speed_up_threshold; - std::string default_metering_mode; - std::string default_exposure_mode; - std::string default_constraint_mode; - double base_ev; - libcamera::utils::Duration default_exposure_time; - double default_analogue_gain; + uint16_t startupFrames; + unsigned int convergenceFrames; + double maxChange; + double minChange; + double fastReduceThreshold; + double speedUpThreshold; + std::string defaultMeteringMode; + std::string defaultExposureMode; + std::string defaultConstraintMode; + double baseEv; + libcamera::utils::Duration defaultExposureTime; + double defaultAnalogueGain; }; class Agc : public AgcAlgorithm { public: Agc(Controller *controller); - char const *Name() const override; - void Read(boost::property_tree::ptree const ¶ms) override; + char const *name() const override; + void read(boost::property_tree::ptree const ¶ms) override; // AGC handles "pausing" for itself. - bool IsPaused() const override; - void Pause() override; - void Resume() override; - unsigned int GetConvergenceFrames() const override; - void SetEv(double ev) override; - void SetFlickerPeriod(libcamera::utils::Duration flicker_period) override; - void SetMaxShutter(libcamera::utils::Duration max_shutter) override; - void SetFixedShutter(libcamera::utils::Duration fixed_shutter) override; - void SetFixedAnalogueGain(double fixed_analogue_gain) override; - void SetMeteringMode(std::string const &metering_mode_name) override; - void SetExposureMode(std::string const &exposure_mode_name) override; - void SetConstraintMode(std::string const &contraint_mode_name) override; - void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override; - void Prepare(Metadata *image_metadata) override; - void Process(StatisticsPtr &stats, Metadata *image_metadata) override; + bool isPaused() const override; + void pause() override; + void resume() override; + unsigned int getConvergenceFrames() const override; + void setEv(double ev) override; + void setFlickerPeriod(libcamera::utils::Duration flickerPeriod) override; + void setMaxShutter(libcamera::utils::Duration maxShutter) override; + void setFixedShutter(libcamera::utils::Duration fixedShutter) override; + void setFixedAnalogueGain(double fixedAnalogueGain) override; + void setMeteringMode(std::string const &meteringModeName) override; + void setExposureMode(std::string const &exposureModeName) override; + void setConstraintMode(std::string const &contraintModeName) override; + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; + void prepare(Metadata *imageMetadata) override; + void process(StatisticsPtr &stats, Metadata *imageMetadata) override; private: - void updateLockStatus(DeviceStatus const &device_status); + void updateLockStatus(DeviceStatus const &deviceStatus); AgcConfig config_; void housekeepConfig(); - void fetchCurrentExposure(Metadata *image_metadata); - void fetchAwbStatus(Metadata *image_metadata); - void computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata, - double &gain, double &target_Y); + void fetchCurrentExposure(Metadata *imageMetadata); + void fetchAwbStatus(Metadata *imageMetadata); + void computeGain(bcm2835_isp_stats *statistics, Metadata *imageMetadata, + double &gain, double &targetY); void computeTargetExposure(double gain); - bool applyDigitalGain(double gain, double target_Y); + bool applyDigitalGain(double gain, double targetY); void filterExposure(bool desaturate); void divideUpExposure(); - void writeAndFinish(Metadata *image_metadata, bool desaturate); + void writeAndFinish(Metadata *imageMetadata, bool desaturate); libcamera::utils::Duration clipShutter(libcamera::utils::Duration shutter); - AgcMeteringMode *metering_mode_; - AgcExposureMode *exposure_mode_; - AgcConstraintMode *constraint_mode_; - uint64_t frame_count_; + AgcMeteringMode *meteringMode_; + AgcExposureMode *exposureMode_; + AgcConstraintMode *constraintMode_; + uint64_t frameCount_; AwbStatus awb_; struct ExposureValues { ExposureValues(); libcamera::utils::Duration shutter; - double analogue_gain; - libcamera::utils::Duration total_exposure; - libcamera::utils::Duration total_exposure_no_dg; // without digital gain + double analogueGain; + libcamera::utils::Duration totalExposure; + libcamera::utils::Duration totalExposureNoDG; // without digital gain }; ExposureValues current_; // values for the current frame ExposureValues target_; // calculate the values we want here ExposureValues filtered_; // these values are filtered towards target AgcStatus status_; - int lock_count_; - DeviceStatus last_device_status_; - libcamera::utils::Duration last_target_exposure_; - double last_sensitivity_; // sensitivity of the previous camera mode + int lockCount_; + DeviceStatus lastDeviceStatus_; + libcamera::utils::Duration lastTargetExposure_; + double lastSensitivity_; // sensitivity of the previous camera mode // Below here the "settings" that applications can change. - std::string metering_mode_name_; - std::string exposure_mode_name_; - std::string constraint_mode_name_; + std::string meteringModeName_; + std::string exposureModeName_; + std::string constraintModeName_; double ev_; - libcamera::utils::Duration flicker_period_; - libcamera::utils::Duration max_shutter_; - libcamera::utils::Duration fixed_shutter_; - double fixed_analogue_gain_; + libcamera::utils::Duration flickerPeriod_; + libcamera::utils::Duration maxShutter_; + libcamera::utils::Duration fixedShutter_; + double fixedAnalogueGain_; }; } // namespace RPiController diff --git a/src/ipa/raspberrypi/controller/rpi/alsc.cpp b/src/ipa/raspberrypi/controller/rpi/alsc.cpp index e575c14a92db..4929abc5b360 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 ¶ms) +static void generateLut(double *lut, boost::property_tree::ptree const ¶ms) { 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 ¶ms) } } -static void read_lut(double *lut, boost::property_tree::ptree const ¶ms) +static void readLut(double *lut, boost::property_tree::ptree const ¶ms) { 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 ¶ms, - std::string const &name) +static void readCalibrations(std::vector<AlscCalibration> &calibrations, + boost::property_tree::ptree const ¶ms, + 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 ¶ms) +void Alsc::read(boost::property_tree::ptree const ¶ms) { - 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; + << 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); diff --git a/src/ipa/raspberrypi/controller/rpi/alsc.hpp b/src/ipa/raspberrypi/controller/rpi/alsc.hpp index d1dbe0d1d22d..7a0949d1ccc5 100644 --- a/src/ipa/raspberrypi/controller/rpi/alsc.hpp +++ b/src/ipa/raspberrypi/controller/rpi/alsc.hpp @@ -24,24 +24,24 @@ struct AlscCalibration { struct AlscConfig { // Only repeat the ALSC calculation every "this many" frames - uint16_t frame_period; + uint16_t framePeriod; // number of initial frames for which speed taken as 1.0 (maximum) - uint16_t startup_frames; + uint16_t startupFrames; // IIR filter speed applied to algorithm results double speed; - double sigma_Cr; - double sigma_Cb; - double min_count; - uint16_t min_G; + double sigmaCr; + double sigmaCb; + double minCount; + uint16_t minG; double omega; - uint32_t n_iter; - double luminance_lut[ALSC_CELLS_X * ALSC_CELLS_Y]; - double luminance_strength; - std::vector<AlscCalibration> calibrations_Cr; - std::vector<AlscCalibration> calibrations_Cb; - double default_ct; // colour temperature if no metadata found + uint32_t nIter; + double luminanceLut[ALSC_CELLS_X * ALSC_CELLS_Y]; + double luminanceStrength; + std::vector<AlscCalibration> calibrationsCr; + std::vector<AlscCalibration> calibrationsCb; + double defaultCt; // colour temperature if no metadata found double threshold; // iteration termination threshold - double lambda_bound; // upper/lower bound for lambda from a value of 1 + double lambdaBound; // upper/lower bound for lambda from a value of 1 }; class Alsc : public Algorithm @@ -49,58 +49,58 @@ class Alsc : public Algorithm public: Alsc(Controller *controller = NULL); ~Alsc(); - char const *Name() const override; - void Initialise() override; - void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override; - void Read(boost::property_tree::ptree const ¶ms) override; - void Prepare(Metadata *image_metadata) override; - void Process(StatisticsPtr &stats, Metadata *image_metadata) override; + char const *name() const override; + void initialise() override; + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; + void read(boost::property_tree::ptree const ¶ms) override; + void prepare(Metadata *imageMetadata) override; + void process(StatisticsPtr &stats, Metadata *imageMetadata) override; private: // configuration is read-only, and available to both threads AlscConfig config_; - bool first_time_; - CameraMode camera_mode_; - double luminance_table_[ALSC_CELLS_X * ALSC_CELLS_Y]; - std::thread async_thread_; + bool firstTime_; + CameraMode cameraMode_; + double luminanceTable_[ALSC_CELLS_X * ALSC_CELLS_Y]; + std::thread asyncThread_; void asyncFunc(); // asynchronous thread function std::mutex mutex_; // condvar for async thread to wait on - std::condition_variable async_signal_; + std::condition_variable asyncSignal_; // condvar for synchronous thread to wait on - std::condition_variable sync_signal_; + std::condition_variable syncSignal_; // for sync thread to check if async thread finished (requires mutex) - bool async_finished_; + bool asyncFinished_; // for async thread to check if it's been told to run (requires mutex) - bool async_start_; + bool asyncStart_; // for async thread to check if it's been told to quit (requires mutex) - bool async_abort_; + bool asyncAbort_; // The following are only for the synchronous thread to use: // for sync thread to note its has asked async thread to run - bool async_started_; - // counts up to frame_period before restarting the async thread - int frame_phase_; - // counts up to startup_frames - int frame_count_; - // counts up to startup_frames for Process function - int frame_count2_; - double sync_results_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; - double prev_sync_results_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; + bool asyncStarted_; + // counts up to framePeriod before restarting the async thread + int framePhase_; + // counts up to startupFrames + int frameCount_; + // counts up to startupFrames for Process function + int frameCount2_; + double syncResults_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; + double prevSyncResults_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; void waitForAysncThread(); // The following are for the asynchronous thread to use, though the main // thread can set/reset them if the async thread is known to be idle: - void restartAsync(StatisticsPtr &stats, Metadata *image_metadata); + void restartAsync(StatisticsPtr &stats, Metadata *imageMetadata); // copy out the results from the async thread so that it can be restarted void fetchAsyncResults(); double ct_; bcm2835_isp_stats_region statistics_[ALSC_CELLS_Y * ALSC_CELLS_X]; - double async_results_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; - double async_lambda_r_[ALSC_CELLS_X * ALSC_CELLS_Y]; - double async_lambda_b_[ALSC_CELLS_X * ALSC_CELLS_Y]; + double asyncResults_[3][ALSC_CELLS_Y][ALSC_CELLS_X]; + double asyncLambdaR_[ALSC_CELLS_X * ALSC_CELLS_Y]; + double asyncLambdaB_[ALSC_CELLS_X * ALSC_CELLS_Y]; void doAlsc(); - double lambda_r_[ALSC_CELLS_X * ALSC_CELLS_Y]; - double lambda_b_[ALSC_CELLS_X * ALSC_CELLS_Y]; + double lambdaR_[ALSC_CELLS_X * ALSC_CELLS_Y]; + double lambdaB_[ALSC_CELLS_X * ALSC_CELLS_Y]; }; } // namespace RPiController diff --git a/src/ipa/raspberrypi/controller/rpi/awb.cpp b/src/ipa/raspberrypi/controller/rpi/awb.cpp index d4c934473832..74449c8c7591 100644 --- a/src/ipa/raspberrypi/controller/rpi/awb.cpp +++ b/src/ipa/raspberrypi/controller/rpi/awb.cpp @@ -24,33 +24,33 @@ LOG_DEFINE_CATEGORY(RPiAwb) // todo - the locking in this algorithm needs some tidying up as has been done // elsewhere (ALSC and AGC). -void AwbMode::Read(boost::property_tree::ptree const ¶ms) +void AwbMode::read(boost::property_tree::ptree const ¶ms) { - ct_lo = params.get<double>("lo"); - ct_hi = params.get<double>("hi"); + ctLo = params.get<double>("lo"); + ctHi = params.get<double>("hi"); } -void AwbPrior::Read(boost::property_tree::ptree const ¶ms) +void AwbPrior::read(boost::property_tree::ptree const ¶ms) { lux = params.get<double>("lux"); - prior.Read(params.get_child("prior")); + prior.read(params.get_child("prior")); } -static void read_ct_curve(Pwl &ct_r, Pwl &ct_b, - boost::property_tree::ptree const ¶ms) +static void readCtCurve(Pwl &ctR, Pwl &ctB, + boost::property_tree::ptree const ¶ms) { int num = 0; for (auto it = params.begin(); it != params.end(); it++) { double ct = it->second.get_value<double>(); - assert(it == params.begin() || ct != ct_r.Domain().end); + assert(it == params.begin() || ct != ctR.domain().end); if (++it == params.end()) throw std::runtime_error( "AwbConfig: incomplete CT curve entry"); - ct_r.Append(ct, it->second.get_value<double>()); + ctR.append(ct, it->second.get_value<double>()); if (++it == params.end()) throw std::runtime_error( "AwbConfig: incomplete CT curve entry"); - ct_b.Append(ct, it->second.get_value<double>()); + ctB.append(ct, it->second.get_value<double>()); num++; } if (num < 2) @@ -58,22 +58,21 @@ static void read_ct_curve(Pwl &ct_r, Pwl &ct_b, "AwbConfig: insufficient points in CT curve"); } -void AwbConfig::Read(boost::property_tree::ptree const ¶ms) +void AwbConfig::read(boost::property_tree::ptree const ¶ms) { bayes = params.get<int>("bayes", 1); - frame_period = params.get<uint16_t>("frame_period", 10); - startup_frames = params.get<uint16_t>("startup_frames", 10); - convergence_frames = params.get<unsigned int>("convergence_frames", 3); + framePeriod = params.get<uint16_t>("framePeriod", 10); + startupFrames = params.get<uint16_t>("startupFrames", 10); + convergenceFrames = params.get<unsigned int>("convergence_frames", 3); speed = params.get<double>("speed", 0.05); if (params.get_child_optional("ct_curve")) - read_ct_curve(ct_r, ct_b, params.get_child("ct_curve")); + readCtCurve(ctR, ctB, params.get_child("ct_curve")); if (params.get_child_optional("priors")) { for (auto &p : params.get_child("priors")) { AwbPrior prior; - prior.Read(p.second); + prior.read(p.second); if (!priors.empty() && prior.lux <= priors.back().lux) - throw std::runtime_error( - "AwbConfig: Prior must be ordered in increasing lux value"); + throw std::runtime_error("AwbConfig: Prior must be ordered in increasing lux value"); priors.push_back(prior); } if (priors.empty()) @@ -82,177 +81,170 @@ void AwbConfig::Read(boost::property_tree::ptree const ¶ms) } if (params.get_child_optional("modes")) { for (auto &p : params.get_child("modes")) { - modes[p.first].Read(p.second); - if (default_mode == nullptr) - default_mode = &modes[p.first]; + modes[p.first].read(p.second); + if (defaultMode == nullptr) + defaultMode = &modes[p.first]; } - if (default_mode == nullptr) - throw std::runtime_error( - "AwbConfig: no AWB modes configured"); + if (defaultMode == nullptr) + throw std::runtime_error("AwbConfig: no AWB modes configured"); } - min_pixels = params.get<double>("min_pixels", 16.0); - min_G = params.get<uint16_t>("min_G", 32); - min_regions = params.get<uint32_t>("min_regions", 10); - delta_limit = params.get<double>("delta_limit", 0.2); - coarse_step = params.get<double>("coarse_step", 0.2); - transverse_pos = params.get<double>("transverse_pos", 0.01); - transverse_neg = params.get<double>("transverse_neg", 0.01); - if (transverse_pos <= 0 || transverse_neg <= 0) - throw std::runtime_error( - "AwbConfig: transverse_pos/neg must be > 0"); - sensitivity_r = params.get<double>("sensitivity_r", 1.0); - sensitivity_b = params.get<double>("sensitivity_b", 1.0); + minPixels = params.get<double>("min_pixels", 16.0); + minG = params.get<uint16_t>("min_G", 32); + minRegions = params.get<uint32_t>("min_regions", 10); + deltaLimit = params.get<double>("delta_limit", 0.2); + coarseStep = params.get<double>("coarse_step", 0.2); + transversePos = params.get<double>("transverse_pos", 0.01); + transverseNeg = params.get<double>("transverse_neg", 0.01); + if (transversePos <= 0 || transverseNeg <= 0) + throw std::runtime_error("AwbConfig: transverse_pos/neg must be > 0"); + sensitivityR = params.get<double>("sensitivity_r", 1.0); + sensitivityB = params.get<double>("sensitivity_b", 1.0); if (bayes) { - if (ct_r.Empty() || ct_b.Empty() || priors.empty() || - default_mode == nullptr) { + if (ctR.empty() || ctB.empty() || priors.empty() || + defaultMode == nullptr) { LOG(RPiAwb, Warning) << "Bayesian AWB mis-configured - switch to Grey method"; bayes = false; } } - fast = params.get<int>( - "fast", bayes); // default to fast for Bayesian, otherwise slow - whitepoint_r = params.get<double>("whitepoint_r", 0.0); - whitepoint_b = params.get<double>("whitepoint_b", 0.0); + fast = params.get<int>("fast", bayes); // default to fast for Bayesian, otherwise slow + whitepointR = params.get<double>("whitepoint_r", 0.0); + whitepointB = params.get<double>("whitepoint_b", 0.0); if (bayes == false) - sensitivity_r = sensitivity_b = - 1.0; // nor do sensitivities make any sense + sensitivityR = sensitivityB = 1.0; // nor do sensitivities make any sense } Awb::Awb(Controller *controller) : AwbAlgorithm(controller) { - async_abort_ = async_start_ = async_started_ = async_finished_ = false; + asyncAbort_ = asyncStart_ = asyncStarted_ = asyncFinished_ = false; mode_ = nullptr; - manual_r_ = manual_b_ = 0.0; - first_switch_mode_ = true; - async_thread_ = std::thread(std::bind(&Awb::asyncFunc, this)); + manualR_ = manualB_ = 0.0; + firstSwitchMode_ = true; + asyncThread_ = std::thread(std::bind(&Awb::asyncFunc, this)); } Awb::~Awb() { { 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 *Awb::Name() const +char const *Awb::name() const { return NAME; } -void Awb::Read(boost::property_tree::ptree const ¶ms) +void Awb::read(boost::property_tree::ptree const ¶ms) { - config_.Read(params); + config_.read(params); } -void Awb::Initialise() +void Awb::initialise() { - frame_count_ = frame_phase_ = 0; + frameCount_ = framePhase_ = 0; // Put something sane into the status that we are filtering towards, // just in case the first few frames don't have anything meaningful in // them. - if (!config_.ct_r.Empty() && !config_.ct_b.Empty()) { - sync_results_.temperature_K = config_.ct_r.Domain().Clip(4000); - sync_results_.gain_r = - 1.0 / config_.ct_r.Eval(sync_results_.temperature_K); - sync_results_.gain_g = 1.0; - sync_results_.gain_b = - 1.0 / config_.ct_b.Eval(sync_results_.temperature_K); + if (!config_.ctR.empty() && !config_.ctB.empty()) { + syncResults_.temperatureK = config_.ctR.domain().clip(4000); + syncResults_.gainR = 1.0 / config_.ctR.eval(syncResults_.temperatureK); + syncResults_.gainG = 1.0; + syncResults_.gainB = 1.0 / config_.ctB.eval(syncResults_.temperatureK); } else { // random values just to stop the world blowing up - sync_results_.temperature_K = 4500; - sync_results_.gain_r = sync_results_.gain_g = - sync_results_.gain_b = 1.0; + syncResults_.temperatureK = 4500; + syncResults_.gainR = syncResults_.gainG = syncResults_.gainB = 1.0; } - prev_sync_results_ = sync_results_; - async_results_ = sync_results_; + prevSyncResults_ = syncResults_; + asyncResults_ = syncResults_; } -bool Awb::IsPaused() const +bool Awb::isPaused() const { return false; } -void Awb::Pause() +void Awb::pause() { // "Pause" by fixing everything to the most recent values. - manual_r_ = sync_results_.gain_r = prev_sync_results_.gain_r; - manual_b_ = sync_results_.gain_b = prev_sync_results_.gain_b; - sync_results_.gain_g = prev_sync_results_.gain_g; - sync_results_.temperature_K = prev_sync_results_.temperature_K; + manualR_ = syncResults_.gainR = prevSyncResults_.gainR; + manualB_ = syncResults_.gainB = prevSyncResults_.gainB; + syncResults_.gainG = prevSyncResults_.gainG; + syncResults_.temperatureK = prevSyncResults_.temperatureK; } -void Awb::Resume() +void Awb::resume() { - manual_r_ = 0.0; - manual_b_ = 0.0; + manualR_ = 0.0; + manualB_ = 0.0; } -unsigned int Awb::GetConvergenceFrames() const +unsigned int Awb::getConvergenceFrames() const { // If not in auto mode, there is no convergence // to happen, so no need to drop any frames - return zero. if (!isAutoEnabled()) return 0; else - return config_.convergence_frames; + return config_.convergenceFrames; } -void Awb::SetMode(std::string const &mode_name) +void Awb::setMode(std::string const &modeName) { - mode_name_ = mode_name; + modeName_ = modeName; } -void Awb::SetManualGains(double manual_r, double manual_b) +void Awb::setManualGains(double manualR, double manualB) { // If any of these are 0.0, we swich back to auto. - manual_r_ = manual_r; - manual_b_ = manual_b; + manualR_ = manualR; + manualB_ = manualB; // If not in auto mode, set these values into the sync_results which // means that Prepare() will adopt them immediately. if (!isAutoEnabled()) { - sync_results_.gain_r = prev_sync_results_.gain_r = manual_r_; - sync_results_.gain_g = prev_sync_results_.gain_g = 1.0; - sync_results_.gain_b = prev_sync_results_.gain_b = manual_b_; + syncResults_.gainR = prevSyncResults_.gainR = manualR_; + syncResults_.gainG = prevSyncResults_.gainG = 1.0; + syncResults_.gainB = prevSyncResults_.gainB = manualB_; } } -void Awb::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, +void Awb::switchMode([[maybe_unused]] CameraMode const &cameraMode, Metadata *metadata) { // On the first mode switch we'll have no meaningful colour // temperature, so try to dead reckon one if in manual mode. - if (!isAutoEnabled() && first_switch_mode_ && config_.bayes) { - Pwl ct_r_inverse = config_.ct_r.Inverse(); - Pwl ct_b_inverse = config_.ct_b.Inverse(); - double ct_r = ct_r_inverse.Eval(ct_r_inverse.Domain().Clip(1 / manual_r_)); - double ct_b = ct_b_inverse.Eval(ct_b_inverse.Domain().Clip(1 / manual_b_)); - prev_sync_results_.temperature_K = (ct_r + ct_b) / 2; - sync_results_.temperature_K = prev_sync_results_.temperature_K; + if (!isAutoEnabled() && firstSwitchMode_ && config_.bayes) { + Pwl ctRInverse = config_.ctR.inverse(); + Pwl ctBInverse = config_.ctB.inverse(); + double ctR = ctRInverse.eval(ctRInverse.domain().clip(1 / manualR_)); + double ctB = ctBInverse.eval(ctBInverse.domain().clip(1 / manualB_)); + prevSyncResults_.temperatureK = (ctR + ctB) / 2; + syncResults_.temperatureK = prevSyncResults_.temperatureK; } // Let other algorithms know the current white balance values. - metadata->Set("awb.status", prev_sync_results_); - first_switch_mode_ = false; + metadata->set("awb.status", prevSyncResults_); + firstSwitchMode_ = false; } bool Awb::isAutoEnabled() const { - return manual_r_ == 0.0 || manual_b_ == 0.0; + return manualR_ == 0.0 || manualB_ == 0.0; } void Awb::fetchAsyncResults() { LOG(RPiAwb, Debug) << "Fetch AWB results"; - async_finished_ = false; - async_started_ = false; + asyncFinished_ = false; + asyncStarted_ = false; // It's possible manual gains could be set even while the async // thread was running, so only copy the results if still in auto mode. if (isAutoEnabled()) - sync_results_ = async_results_; + syncResults_ = asyncResults_; } void Awb::restartAsync(StatisticsPtr &stats, double lux) @@ -261,75 +253,74 @@ void Awb::restartAsync(StatisticsPtr &stats, double lux) // this makes a new reference which belongs to the asynchronous thread statistics_ = stats; // store the mode as it could technically change - auto m = config_.modes.find(mode_name_); + auto m = config_.modes.find(modeName_); mode_ = m != config_.modes.end() ? &m->second - : (mode_ == nullptr ? config_.default_mode : mode_); + : (mode_ == nullptr ? config_.defaultMode : mode_); lux_ = lux; - frame_phase_ = 0; - async_started_ = true; - size_t len = mode_name_.copy(async_results_.mode, - sizeof(async_results_.mode) - 1); - async_results_.mode[len] = '\0'; + framePhase_ = 0; + asyncStarted_ = true; + size_t len = modeName_.copy(asyncResults_.mode, + sizeof(asyncResults_.mode) - 1); + asyncResults_.mode[len] = '\0'; { std::lock_guard<std::mutex> lock(mutex_); - async_start_ = true; + asyncStart_ = true; } - async_signal_.notify_one(); + asyncSignal_.notify_one(); } -void Awb::Prepare(Metadata *image_metadata) +void Awb::prepare(Metadata *imageMetadata) { - 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(RPiAwb, 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(); } // Finally apply IIR filter to results and put into metadata. - memcpy(prev_sync_results_.mode, sync_results_.mode, - sizeof(prev_sync_results_.mode)); - prev_sync_results_.temperature_K = - speed * sync_results_.temperature_K + - (1.0 - speed) * prev_sync_results_.temperature_K; - prev_sync_results_.gain_r = speed * sync_results_.gain_r + - (1.0 - speed) * prev_sync_results_.gain_r; - prev_sync_results_.gain_g = speed * sync_results_.gain_g + - (1.0 - speed) * prev_sync_results_.gain_g; - prev_sync_results_.gain_b = speed * sync_results_.gain_b + - (1.0 - speed) * prev_sync_results_.gain_b; - image_metadata->Set("awb.status", prev_sync_results_); + memcpy(prevSyncResults_.mode, syncResults_.mode, + sizeof(prevSyncResults_.mode)); + prevSyncResults_.temperatureK = speed * syncResults_.temperatureK + + (1.0 - speed) * prevSyncResults_.temperatureK; + prevSyncResults_.gainR = speed * syncResults_.gainR + + (1.0 - speed) * prevSyncResults_.gainR; + prevSyncResults_.gainG = speed * syncResults_.gainG + + (1.0 - speed) * prevSyncResults_.gainG; + prevSyncResults_.gainB = speed * syncResults_.gainB + + (1.0 - speed) * prevSyncResults_.gainB; + imageMetadata->set("awb.status", prevSyncResults_); LOG(RPiAwb, Debug) - << "Using AWB gains r " << prev_sync_results_.gain_r << " g " - << prev_sync_results_.gain_g << " b " - << prev_sync_results_.gain_b; + << "Using AWB gains r " << prevSyncResults_.gainR << " g " + << prevSyncResults_.gainG << " b " + << prevSyncResults_.gainB; } -void Awb::Process(StatisticsPtr &stats, Metadata *image_metadata) +void Awb::process(StatisticsPtr &stats, Metadata *imageMetadata) { // Count frames since we last poked the async thread. - if (frame_phase_ < (int)config_.frame_period) - frame_phase_++; - LOG(RPiAwb, Debug) << "frame_phase " << frame_phase_; + if (framePhase_ < (int)config_.framePeriod) + framePhase_++; + LOG(RPiAwb, Debug) << "frame_phase " << framePhase_; // We do not restart the async thread if we're not in auto mode. if (isAutoEnabled() && - (frame_phase_ >= (int)config_.frame_period || - frame_count_ < (int)config_.startup_frames)) { + (framePhase_ >= (int)config_.framePeriod || + frameCount_ < (int)config_.startupFrames)) { // Update any settings and any image metadata that we need. - struct LuxStatus lux_status = {}; - lux_status.lux = 400; // in case no metadata - if (image_metadata->Get("lux.status", lux_status) != 0) + struct LuxStatus luxStatus = {}; + luxStatus.lux = 400; // in case no metadata + if (imageMetadata->get("lux.status", luxStatus) != 0) LOG(RPiAwb, Debug) << "No lux metadata found"; - LOG(RPiAwb, Debug) << "Awb lux value is " << lux_status.lux; + LOG(RPiAwb, Debug) << "Awb lux value is " << luxStatus.lux; - if (async_started_ == false) - restartAsync(stats, lux_status.lux); + if (asyncStarted_ == false) + restartAsync(stats, luxStatus.lux); } } @@ -338,32 +329,32 @@ void Awb::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; } doAwb(); { std::lock_guard<std::mutex> lock(mutex_); - async_finished_ = true; + asyncFinished_ = true; } - sync_signal_.notify_one(); + syncSignal_.notify_one(); } } -static void generate_stats(std::vector<Awb::RGB> &zones, - bcm2835_isp_stats_region *stats, double min_pixels, - double min_G) +static void generateStats(std::vector<Awb::RGB> &zones, + bcm2835_isp_stats_region *stats, double minPixels, + double minG) { for (int i = 0; i < AWB_STATS_SIZE_X * AWB_STATS_SIZE_Y; i++) { Awb::RGB zone; double counted = stats[i].counted; - if (counted >= min_pixels) { + if (counted >= minPixels) { zone.G = stats[i].g_sum / counted; - if (zone.G >= min_G) { + if (zone.G >= minG) { zone.R = stats[i].r_sum / counted; zone.B = stats[i].b_sum / counted; zones.push_back(zone); @@ -377,32 +368,33 @@ void Awb::prepareStats() zones_.clear(); // LSC has already been applied to the stats in this pipeline, so stop // any LSC compensation. We also ignore config_.fast in this version. - generate_stats(zones_, statistics_->awb_stats, config_.min_pixels, - config_.min_G); + generateStats(zones_, statistics_->awb_stats, config_.minPixels, + config_.minG); // we're done with these; we may as well relinquish our hold on the // pointer. statistics_.reset(); // apply sensitivities, so values appear to come from our "canonical" // sensor. - for (auto &zone : zones_) - zone.R *= config_.sensitivity_r, - zone.B *= config_.sensitivity_b; + for (auto &zone : zones_) { + zone.R *= config_.sensitivityR; + zone.B *= config_.sensitivityB; + } } -double Awb::computeDelta2Sum(double gain_r, double gain_b) +double Awb::computeDelta2Sum(double gainR, double gainB) { // Compute the sum of the squared colour error (non-greyness) as it // appears in the log likelihood equation. - double delta2_sum = 0; + double delta2Sum = 0; for (auto &z : zones_) { - double delta_r = gain_r * z.R - 1 - config_.whitepoint_r; - double delta_b = gain_b * z.B - 1 - config_.whitepoint_b; - double delta2 = delta_r * delta_r + delta_b * delta_b; + double deltaR = gainR * z.R - 1 - config_.whitepointR; + double deltaB = gainB * z.B - 1 - config_.whitepointB; + double delta2 = deltaR * deltaR + deltaB * deltaB; //LOG(RPiAwb, Debug) << "delta_r " << delta_r << " delta_b " << delta_b << " delta2 " << delta2; - delta2 = std::min(delta2, config_.delta_limit); - delta2_sum += delta2; + delta2 = std::min(delta2, config_.deltaLimit); + delta2Sum += delta2; } - return delta2_sum; + return delta2Sum; } Pwl Awb::interpolatePrior() @@ -420,7 +412,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 Pwl::combine(config_.priors[idx].prior, config_.priors[idx + 1].prior, [&](double /*x*/, double y0, double y1) { return y0 + (y1 - y0) * @@ -429,62 +421,60 @@ Pwl Awb::interpolatePrior() } } -static double interpolate_quadatric(Pwl::Point const &A, Pwl::Point const &B, - Pwl::Point const &C) +static double interpolateQuadatric(Pwl::Point const &a, Pwl::Point const &b, + 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); + 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) { points_.clear(); // assume doesn't deallocate memory - size_t best_point = 0; - double t = mode_->ct_lo; - int span_r = 0, span_b = 0; + size_t bestPoint = 0; + double t = mode_->ctLo; + int spanR = 0, spanB = 0; // Step down the CT curve evaluating log likelihood. while (true) { - double r = config_.ct_r.Eval(t, &span_r); - double b = config_.ct_b.Eval(t, &span_b); - double gain_r = 1 / r, gain_b = 1 / b; - double delta2_sum = computeDelta2Sum(gain_r, gain_b); - double prior_log_likelihood = - prior.Eval(prior.Domain().Clip(t)); - double final_log_likelihood = delta2_sum - prior_log_likelihood; + double r = config_.ctR.eval(t, &spanR); + 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 finalLogLikelihood = delta2Sum - priorLogLikelihood; LOG(RPiAwb, Debug) - << "t: " << t << " gain_r " << gain_r << " gain_b " - << gain_b << " delta2_sum " << delta2_sum - << " prior " << prior_log_likelihood << " final " - << final_log_likelihood; - points_.push_back(Pwl::Point(t, final_log_likelihood)); - if (points_.back().y < points_[best_point].y) - best_point = points_.size() - 1; - if (t == mode_->ct_hi) + << "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) + 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_.coarse_step, - mode_->ct_hi); + t = std::min(t + t / 10 * config_.coarseStep, mode_->ctHi); } - t = points_[best_point].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 // interpolation around its neighbours. if (points_.size() > 2) { - unsigned long bp = std::min(best_point, points_.size() - 2); - best_point = std::max(1UL, bp); - t = interpolate_quadatric(points_[best_point - 1], - points_[best_point], - points_[best_point + 1]); + unsigned long bp = std::min(bestPoint, points_.size() - 2); + bestPoint = std::max(1UL, bp); + t = interpolateQuadatric(points_[bestPoint - 1], + points_[bestPoint], + points_[bestPoint + 1]); LOG(RPiAwb, Debug) << "After quadratic refinement, coarse search has CT " << t; @@ -494,80 +484,76 @@ double Awb::coarseSearch(Pwl const &prior) void Awb::fineSearch(double &t, double &r, double &b, Pwl const &prior) { - int span_r = -1, span_b = -1; - config_.ct_r.Eval(t, &span_r); - config_.ct_b.Eval(t, &span_b); - double step = t / 10 * config_.coarse_step * 0.1; + int spanR = -1, spanB = -1; + config_.ctR.eval(t, &spanR); + config_.ctB.eval(t, &spanB); + double step = t / 10 * config_.coarseStep * 0.1; int nsteps = 5; - double r_diff = config_.ct_r.Eval(t + nsteps * step, &span_r) - - config_.ct_r.Eval(t - nsteps * step, &span_r); - double b_diff = config_.ct_b.Eval(t + nsteps * step, &span_b) - - config_.ct_b.Eval(t - nsteps * step, &span_b); - Pwl::Point transverse(b_diff, -r_diff); - if (transverse.Len2() < 1e-6) + double rDiff = config_.ctR.eval(t + nsteps * step, &spanR) - + 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) return; // unit vector orthogonal to the b vs. r function (pointing outwards // with r and b increasing) - transverse = transverse / transverse.Len(); - double best_log_likelihood = 0, best_t = 0, best_r = 0, best_b = 0; - double transverse_range = - config_.transverse_neg + config_.transverse_pos; - const int MAX_NUM_DELTAS = 12; + transverse = transverse / transverse.len(); + double bestLogLikelihood = 0, bestT = 0, bestR = 0, bestB = 0; + double transverseRange = config_.transverseNeg + config_.transversePos; + const int maxNumDeltas = 12; // a transverse step approximately every 0.01 r/b units - int num_deltas = floor(transverse_range * 100 + 0.5) + 1; - num_deltas = num_deltas < 3 ? 3 : - (num_deltas > MAX_NUM_DELTAS ? MAX_NUM_DELTAS : num_deltas); + int numDeltas = floor(transverseRange * 100 + 0.5) + 1; + numDeltas = numDeltas < 3 ? 3 : (numDeltas > maxNumDeltas ? maxNumDeltas : numDeltas); // Step down CT curve. March a bit further if the transverse range is // large. - nsteps += num_deltas; + nsteps += numDeltas; for (int i = -nsteps; i <= nsteps; i++) { - double t_test = t + i * step; - double prior_log_likelihood = - prior.Eval(prior.Domain().Clip(t_test)); - double r_curve = config_.ct_r.Eval(t_test, &span_r); - double b_curve = config_.ct_b.Eval(t_test, &span_b); + double tTest = t + i * step; + double priorLogLikelihood = + prior.eval(prior.domain().clip(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[MAX_NUM_DELTAS]; - int best_point = 0; + Pwl::Point points[maxNumDeltas]; + int bestPoint = 0; // Take some measurements transversely *off* the CT curve. - for (int j = 0; j < num_deltas; j++) { - points[j].x = -config_.transverse_neg + - (transverse_range * j) / (num_deltas - 1); - Pwl::Point rb_test = Pwl::Point(r_curve, b_curve) + - transverse * points[j].x; - double r_test = rb_test.x, b_test = rb_test.y; - double gain_r = 1 / r_test, gain_b = 1 / b_test; - double delta2_sum = computeDelta2Sum(gain_r, gain_b); - points[j].y = delta2_sum - prior_log_likelihood; + 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; + double gainR = 1 / rTest, gainB = 1 / bTest; + double delta2Sum = computeDelta2Sum(gainR, gainB); + points[j].y = delta2Sum - priorLogLikelihood; LOG(RPiAwb, Debug) - << "At t " << t_test << " r " << r_test << " b " - << b_test << ": " << points[j].y; - if (points[j].y < points[best_point].y) - best_point = j; + << "At t " << tTest << " r " << rTest << " b " + << bTest << ": " << points[j].y; + if (points[j].y < points[bestPoint].y) + bestPoint = j; } // We have NUM_DELTAS points transversely across the CT curve, // now let's do a quadratic interpolation for the best result. - best_point = std::max(1, std::min(best_point, num_deltas - 2)); - Pwl::Point rb_test = - Pwl::Point(r_curve, b_curve) + - transverse * - interpolate_quadatric(points[best_point - 1], - points[best_point], - points[best_point + 1]); - double r_test = rb_test.x, b_test = rb_test.y; - double gain_r = 1 / r_test, gain_b = 1 / b_test; - double delta2_sum = computeDelta2Sum(gain_r, gain_b); - double final_log_likelihood = delta2_sum - prior_log_likelihood; + 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; + double gainR = 1 / rTest, gainB = 1 / bTest; + double delta2Sum = computeDelta2Sum(gainR, gainB); + double finalLogLikelihood = delta2Sum - priorLogLikelihood; LOG(RPiAwb, Debug) << "Finally " - << t_test << " r " << r_test << " b " << b_test << ": " - << final_log_likelihood - << (final_log_likelihood < best_log_likelihood ? " BEST" : ""); - if (best_t == 0 || final_log_likelihood < best_log_likelihood) - best_log_likelihood = final_log_likelihood, - best_t = t_test, best_r = r_test, best_b = b_test; + << tTest << " r " << rTest << " b " << bTest << ": " + << finalLogLikelihood + << (finalLogLikelihood < bestLogLikelihood ? " BEST" : ""); + if (bestT == 0 || finalLogLikelihood < bestLogLikelihood) + bestLogLikelihood = finalLogLikelihood, + bestT = tTest, bestR = rTest, bestB = bTest; } - t = best_t, r = best_r, b = best_b; + t = bestT, r = bestR, b = bestB; LOG(RPiAwb, Debug) << "Fine search found t " << t << " r " << r << " b " << b; } @@ -582,12 +568,12 @@ void Awb::awbBayes() // valid... not entirely sure about this. Pwl prior = interpolatePrior(); prior *= zones_.size() / (double)(AWB_STATS_SIZE_X * AWB_STATS_SIZE_Y); - prior.Map([](double x, double y) { + prior.map([](double x, double y) { LOG(RPiAwb, Debug) << "(" << x << "," << y << ")"; }); double t = coarseSearch(prior); - double r = config_.ct_r.Eval(t); - double b = config_.ct_b.Eval(t); + double r = config_.ctR.eval(t); + double b = config_.ctB.eval(t); LOG(RPiAwb, Debug) << "After coarse search: r " << r << " b " << b << " (gains r " << 1 / r << " b " << 1 / b << ")"; @@ -604,10 +590,10 @@ void Awb::awbBayes() // Write results out for the main thread to pick up. Remember to adjust // the gains from the ones that the "canonical sensor" would require to // the ones needed by *this* sensor. - async_results_.temperature_K = t; - async_results_.gain_r = 1.0 / r * config_.sensitivity_r; - async_results_.gain_g = 1.0; - async_results_.gain_b = 1.0 / b * config_.sensitivity_b; + asyncResults_.temperatureK = t; + asyncResults_.gainR = 1.0 / r * config_.sensitivityR; + asyncResults_.gainG = 1.0; + asyncResults_.gainB = 1.0 / b * config_.sensitivityB; } void Awb::awbGrey() @@ -617,51 +603,51 @@ void Awb::awbGrey() // that we can sort them to exclude the extreme gains. We could // consider some variations, such as normalising all the zones first, or // doing an L2 average etc. - std::vector<RGB> &derivs_R(zones_); - std::vector<RGB> derivs_B(derivs_R); - std::sort(derivs_R.begin(), derivs_R.end(), + std::vector<RGB> &derivsR(zones_); + std::vector<RGB> derivsB(derivsR); + std::sort(derivsR.begin(), derivsR.end(), [](RGB const &a, RGB const &b) { return a.G * b.R < b.G * a.R; }); - std::sort(derivs_B.begin(), derivs_B.end(), + std::sort(derivsB.begin(), derivsB.end(), [](RGB const &a, RGB const &b) { return a.G * b.B < b.G * a.B; }); // Average the middle half of the values. - int discard = derivs_R.size() / 4; - RGB sum_R(0, 0, 0), sum_B(0, 0, 0); - for (auto ri = derivs_R.begin() + discard, - bi = derivs_B.begin() + discard; - ri != derivs_R.end() - discard; ri++, bi++) - sum_R += *ri, sum_B += *bi; - double gain_r = sum_R.G / (sum_R.R + 1), - gain_b = sum_B.G / (sum_B.B + 1); - async_results_.temperature_K = 4500; // don't know what it is - async_results_.gain_r = gain_r; - async_results_.gain_g = 1.0; - async_results_.gain_b = gain_b; + int discard = derivsR.size() / 4; + RGB sumR(0, 0, 0), sumB(0, 0, 0); + for (auto ri = derivsR.begin() + discard, + bi = derivsB.begin() + discard; + ri != derivsR.end() - discard; ri++, bi++) + sumR += *ri, sumB += *bi; + double gainR = sumR.G / (sumR.R + 1), + gainB = sumB.G / (sumB.B + 1); + asyncResults_.temperatureK = 4500; // don't know what it is + asyncResults_.gainR = gainR; + asyncResults_.gainG = 1.0; + asyncResults_.gainB = gainB; } void Awb::doAwb() { prepareStats(); LOG(RPiAwb, Debug) << "Valid zones: " << zones_.size(); - if (zones_.size() > config_.min_regions) { + if (zones_.size() > config_.minRegions) { if (config_.bayes) awbBayes(); else awbGrey(); LOG(RPiAwb, Debug) << "CT found is " - << async_results_.temperature_K - << " with gains r " << async_results_.gain_r - << " and b " << async_results_.gain_b; + << asyncResults_.temperatureK + << " with gains r " << asyncResults_.gainR + << " and b " << asyncResults_.gainB; } } // Register algorithm with the system. -static Algorithm *Create(Controller *controller) +static Algorithm *create(Controller *controller) { return (Algorithm *)new Awb(controller); } -static RegisterAlgorithm reg(NAME, &Create); +static RegisterAlgorithm reg(NAME, &create); diff --git a/src/ipa/raspberrypi/controller/rpi/awb.hpp b/src/ipa/raspberrypi/controller/rpi/awb.hpp index ac3dca6f42fc..91251d6be2da 100644 --- a/src/ipa/raspberrypi/controller/rpi/awb.hpp +++ b/src/ipa/raspberrypi/controller/rpi/awb.hpp @@ -19,59 +19,59 @@ namespace RPiController { // Control algorithm to perform AWB calculations. struct AwbMode { - void Read(boost::property_tree::ptree const ¶ms); - double ct_lo; // low CT value for search - double ct_hi; // high CT value for search + void read(boost::property_tree::ptree const ¶ms); + double ctLo; // low CT value for search + double ctHi; // high CT value for search }; struct AwbPrior { - void Read(boost::property_tree::ptree const ¶ms); + void read(boost::property_tree::ptree const ¶ms); double lux; // lux level Pwl prior; // maps CT to prior log likelihood for this lux level }; struct AwbConfig { - AwbConfig() : default_mode(nullptr) {} - void Read(boost::property_tree::ptree const ¶ms); + AwbConfig() : defaultMode(nullptr) {} + void read(boost::property_tree::ptree const ¶ms); // Only repeat the AWB calculation every "this many" frames - uint16_t frame_period; + uint16_t framePeriod; // number of initial frames for which speed taken as 1.0 (maximum) - uint16_t startup_frames; - unsigned int convergence_frames; // approx number of frames to converge + uint16_t startupFrames; + 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 ct_r; // function maps CT to r (= R/G) - Pwl ct_b; // function maps CT to b (= B/G) + Pwl ctR; // function maps CT to r (= R/G) + Pwl ctB; // function maps CT to b (= B/G) // table of illuminant priors at different lux levels std::vector<AwbPrior> priors; // AWB "modes" (determines the search range) std::map<std::string, AwbMode> modes; - AwbMode *default_mode; // mode used if no mode selected + AwbMode *defaultMode; // mode used if no mode selected // minimum proportion of pixels counted within AWB region for it to be // "useful" - double min_pixels; + double minPixels; // minimum G value of those pixels, to be regarded a "useful" - uint16_t min_G; + uint16_t minG; // number of AWB regions that must be "useful" in order to do the AWB // calculation - uint32_t min_regions; + uint32_t minRegions; // clamp on colour error term (so as not to penalise non-grey excessively) - double delta_limit; + double deltaLimit; // step size control in coarse search - double coarse_step; + double coarseStep; // how far to wander off CT curve towards "more purple" - double transverse_pos; + double transversePos; // how far to wander off CT curve towards "more green" - double transverse_neg; + double transverseNeg; // red sensitivity ratio (set to canonical sensor's R/G divided by this // sensor's R/G) - double sensitivity_r; + double sensitivityR; // blue sensitivity ratio (set to canonical sensor's B/G divided by this // sensor's B/G) - double sensitivity_b; + double sensitivityB; // The whitepoint (which we normally "aim" for) can be moved. - double whitepoint_r; - double whitepoint_b; + double whitepointR; + double whitepointB; bool bayes; // use Bayesian algorithm }; @@ -80,22 +80,22 @@ class Awb : public AwbAlgorithm public: Awb(Controller *controller = NULL); ~Awb(); - char const *Name() const override; - void Initialise() override; - void Read(boost::property_tree::ptree const ¶ms) override; + char const *name() const override; + void initialise() override; + void read(boost::property_tree::ptree const ¶ms) override; // AWB handles "pausing" for itself. - bool IsPaused() const override; - void Pause() override; - void Resume() override; - unsigned int GetConvergenceFrames() const override; - void SetMode(std::string const &name) override; - void SetManualGains(double manual_r, double manual_b) override; - void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override; - void Prepare(Metadata *image_metadata) override; - void Process(StatisticsPtr &stats, Metadata *image_metadata) override; + bool isPaused() const override; + void pause() override; + void resume() override; + unsigned int getConvergenceFrames() const override; + void setMode(std::string const &name) override; + void setManualGains(double manualR, double manualB) override; + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; + void prepare(Metadata *imageMetadata) override; + void process(StatisticsPtr &stats, Metadata *imageMetadata) override; struct RGB { - RGB(double _R = 0, double _G = 0, double _B = 0) - : R(_R), G(_G), B(_B) + RGB(double r = 0, double g = 0, double b = 0) + : R(r), G(g), B(b) { } double R, G, B; @@ -110,29 +110,29 @@ private: bool isAutoEnabled() const; // configuration is read-only, and available to both threads AwbConfig config_; - std::thread async_thread_; + std::thread asyncThread_; void asyncFunc(); // asynchronous thread function std::mutex mutex_; // condvar for async thread to wait on - std::condition_variable async_signal_; + std::condition_variable asyncSignal_; // condvar for synchronous thread to wait on - std::condition_variable sync_signal_; + std::condition_variable syncSignal_; // for sync thread to check if async thread finished (requires mutex) - bool async_finished_; + bool asyncFinished_; // for async thread to check if it's been told to run (requires mutex) - bool async_start_; + bool asyncStart_; // for async thread to check if it's been told to quit (requires mutex) - bool async_abort_; + bool asyncAbort_; // The following are only for the synchronous thread to use: // for sync thread to note its has asked async thread to run - bool async_started_; - // counts up to frame_period before restarting the async thread - int frame_phase_; - int frame_count_; // counts up to startup_frames - AwbStatus sync_results_; - AwbStatus prev_sync_results_; - std::string mode_name_; + bool asyncStarted_; + // counts up to framePeriod before restarting the async thread + int framePhase_; + int frameCount_; // counts up to startup_frames + AwbStatus syncResults_; + AwbStatus prevSyncResults_; + std::string modeName_; // The following are for the asynchronous thread to use, though the main // thread can set/reset them if the async thread is known to be idle: void restartAsync(StatisticsPtr &stats, double lux); @@ -141,22 +141,22 @@ private: StatisticsPtr statistics_; AwbMode *mode_; double lux_; - AwbStatus async_results_; + AwbStatus asyncResults_; void doAwb(); void awbBayes(); void awbGrey(); void prepareStats(); - double computeDelta2Sum(double gain_r, double gain_b); + double computeDelta2Sum(double gain_r, double gainB); Pwl interpolatePrior(); double coarseSearch(Pwl const &prior); void fineSearch(double &t, double &r, double &b, Pwl const &prior); std::vector<RGB> zones_; std::vector<Pwl::Point> points_; // manual r setting - double manual_r_; + double manualR_; // manual b setting - double manual_b_; - bool first_switch_mode_; // is this the first call to SwitchMode? + double manualB_; + bool firstSwitchMode_; // is this the first call to SwitchMode? }; static inline Awb::RGB operator+(Awb::RGB const &a, Awb::RGB const &b)