ipa: raspberrypi: Switch the AGC/Lux code to use utils::Duration
Convert the core AGC and Lux controller code to use utils::Duration for all exposure time related variables and calculations. Convert the exposure/shutter time fields in AgcStatus and DeviceStatus to use utils::Duration. Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
2db8a767ca
commit
6914fc487f
8 changed files with 93 additions and 73 deletions
|
@ -56,19 +56,26 @@ read_metering_modes(std::map<std::string, AgcMeteringMode> &metering_modes,
|
|||
return first;
|
||||
}
|
||||
|
||||
static int read_double_list(std::vector<double> &list,
|
||||
boost::property_tree::ptree const ¶ms)
|
||||
static int read_list(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int num_shutters =
|
||||
read_double_list(shutter, params.get_child("shutter"));
|
||||
int num_ags = read_double_list(gain, params.get_child("gain"));
|
||||
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)
|
||||
throw std::runtime_error(
|
||||
"AgcConfig: must have at least two entries in exposure profile");
|
||||
|
@ -148,7 +155,7 @@ void AgcConfig::Read(boost::property_tree::ptree const ¶ms)
|
|||
params.get<double>("fast_reduce_threshold", 0.4);
|
||||
base_ev = 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);
|
||||
default_exposure_time = params.get<double>("default_exposure_time", 1000) * 1us;
|
||||
default_analogue_gain = params.get<double>("default_analogue_gain", 1.0);
|
||||
}
|
||||
|
||||
|
@ -156,9 +163,9 @@ Agc::Agc(Controller *controller)
|
|||
: AgcAlgorithm(controller), metering_mode_(nullptr),
|
||||
exposure_mode_(nullptr), constraint_mode_(nullptr),
|
||||
frame_count_(0), lock_count_(0),
|
||||
last_target_exposure_(0.0),
|
||||
ev_(1.0), flicker_period_(0.0),
|
||||
max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0)
|
||||
last_target_exposure_(0s),
|
||||
ev_(1.0), flicker_period_(0s),
|
||||
max_shutter_(0s), fixed_shutter_(0s), fixed_analogue_gain_(0.0)
|
||||
{
|
||||
memset(&awb_, 0, sizeof(awb_));
|
||||
// Setting status_.total_exposure_value_ to zero initially tells us
|
||||
|
@ -204,7 +211,7 @@ void Agc::Pause()
|
|||
|
||||
void Agc::Resume()
|
||||
{
|
||||
fixed_shutter_ = 0;
|
||||
fixed_shutter_ = 0s;
|
||||
fixed_analogue_gain_ = 0;
|
||||
}
|
||||
|
||||
|
@ -225,17 +232,17 @@ void Agc::SetEv(double ev)
|
|||
|
||||
void Agc::SetFlickerPeriod(Duration flicker_period)
|
||||
{
|
||||
flicker_period_ = flicker_period.get<std::micro>();
|
||||
flicker_period_ = flicker_period;
|
||||
}
|
||||
|
||||
void Agc::SetMaxShutter(Duration max_shutter)
|
||||
{
|
||||
max_shutter_ = max_shutter.get<std::micro>();
|
||||
max_shutter_ = max_shutter;
|
||||
}
|
||||
|
||||
void Agc::SetFixedShutter(Duration fixed_shutter)
|
||||
{
|
||||
fixed_shutter_ = fixed_shutter.get<std::micro>();
|
||||
fixed_shutter_ = fixed_shutter;
|
||||
// Set this in case someone calls Pause() straight after.
|
||||
status_.shutter_time = clipShutter(fixed_shutter_);
|
||||
}
|
||||
|
@ -267,8 +274,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,
|
|||
{
|
||||
housekeepConfig();
|
||||
|
||||
double fixed_shutter = clipShutter(fixed_shutter_);
|
||||
if (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) {
|
||||
Duration fixed_shutter = clipShutter(fixed_shutter_);
|
||||
if (fixed_shutter && fixed_analogue_gain_) {
|
||||
// We're going to reset the algorithm here with these fixed values.
|
||||
|
||||
fetchAwbStatus(metadata);
|
||||
|
@ -313,8 +320,8 @@ void Agc::Prepare(Metadata *image_metadata)
|
|||
// Process has run, so we have meaningful values.
|
||||
DeviceStatus device_status;
|
||||
if (image_metadata->Get("device.status", device_status) == 0) {
|
||||
double actual_exposure = device_status.shutter_speed *
|
||||
device_status.analogue_gain;
|
||||
Duration actual_exposure = device_status.shutter_speed *
|
||||
device_status.analogue_gain;
|
||||
if (actual_exposure) {
|
||||
status_.digital_gain =
|
||||
status_.total_exposure_value /
|
||||
|
@ -327,7 +334,8 @@ void Agc::Prepare(Metadata *image_metadata)
|
|||
std::min(status_.digital_gain, 4.0));
|
||||
LOG(RPiAgc, Debug) << "Actual exposure " << actual_exposure;
|
||||
LOG(RPiAgc, Debug) << "Use digital_gain " << status_.digital_gain;
|
||||
LOG(RPiAgc, Debug) << "Effective exposure " << actual_exposure * status_.digital_gain;
|
||||
LOG(RPiAgc, Debug) << "Effective exposure "
|
||||
<< actual_exposure * status_.digital_gain;
|
||||
// Decide whether AEC/AGC has converged.
|
||||
updateLockStatus(device_status);
|
||||
}
|
||||
|
@ -371,9 +379,9 @@ void Agc::updateLockStatus(DeviceStatus const &device_status)
|
|||
const double RESET_MARGIN = 1.5;
|
||||
|
||||
// Add 200us to the exposure time error to allow for line quantisation.
|
||||
double exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200;
|
||||
Duration exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200us;
|
||||
double gain_error = last_device_status_.analogue_gain * ERROR_FACTOR;
|
||||
double target_error = last_target_exposure_ * ERROR_FACTOR;
|
||||
Duration target_error = last_target_exposure_ * ERROR_FACTOR;
|
||||
|
||||
// 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
|
||||
|
@ -463,7 +471,7 @@ void Agc::fetchCurrentExposure(Metadata *image_metadata)
|
|||
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 : 0;
|
||||
current_.total_exposure = agc_status ? agc_status->total_exposure_value : 0s;
|
||||
current_.total_exposure_no_dg = current_.shutter * current_.analogue_gain;
|
||||
}
|
||||
|
||||
|
@ -574,7 +582,7 @@ void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata,
|
|||
|
||||
void Agc::computeTargetExposure(double gain)
|
||||
{
|
||||
if (status_.fixed_shutter != 0.0 && status_.fixed_analogue_gain != 0.0) {
|
||||
if (status_.fixed_shutter && status_.fixed_analogue_gain) {
|
||||
// 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
|
||||
|
@ -589,11 +597,11 @@ void Agc::computeTargetExposure(double gain)
|
|||
target_.total_exposure = current_.total_exposure_no_dg * gain;
|
||||
// The final target exposure is also limited to what the exposure
|
||||
// mode allows.
|
||||
double max_shutter = status_.fixed_shutter != 0.0
|
||||
Duration max_shutter = status_.fixed_shutter
|
||||
? status_.fixed_shutter
|
||||
: exposure_mode_->shutter.back();
|
||||
max_shutter = clipShutter(max_shutter);
|
||||
double max_total_exposure =
|
||||
Duration max_total_exposure =
|
||||
max_shutter *
|
||||
(status_.fixed_analogue_gain != 0.0
|
||||
? status_.fixed_analogue_gain
|
||||
|
@ -638,7 +646,7 @@ void Agc::filterExposure(bool desaturate)
|
|||
if ((status_.fixed_shutter && status_.fixed_analogue_gain) ||
|
||||
frame_count_ <= config_.startup_frames)
|
||||
speed = 1.0;
|
||||
if (filtered_.total_exposure == 0.0) {
|
||||
if (!filtered_.total_exposure) {
|
||||
filtered_.total_exposure = target_.total_exposure;
|
||||
filtered_.total_exposure_no_dg = target_.total_exposure_no_dg;
|
||||
} else {
|
||||
|
@ -675,9 +683,10 @@ 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.
|
||||
double exposure_value = filtered_.total_exposure_no_dg;
|
||||
double shutter_time, analogue_gain;
|
||||
shutter_time = status_.fixed_shutter != 0.0
|
||||
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);
|
||||
|
@ -687,8 +696,8 @@ void Agc::divideUpExposure()
|
|||
if (shutter_time * analogue_gain < exposure_value) {
|
||||
for (unsigned int stage = 1;
|
||||
stage < exposure_mode_->gain.size(); stage++) {
|
||||
if (status_.fixed_shutter == 0.0) {
|
||||
double stage_shutter =
|
||||
if (!status_.fixed_shutter) {
|
||||
Duration stage_shutter =
|
||||
clipShutter(exposure_mode_->shutter[stage]);
|
||||
if (stage_shutter * analogue_gain >=
|
||||
exposure_value) {
|
||||
|
@ -714,12 +723,11 @@ void Agc::divideUpExposure()
|
|||
<< analogue_gain;
|
||||
// Finally adjust shutter time for flicker avoidance (require both
|
||||
// shutter and gain not to be fixed).
|
||||
if (status_.fixed_shutter == 0.0 &&
|
||||
status_.fixed_analogue_gain == 0.0 &&
|
||||
status_.flicker_period != 0.0) {
|
||||
if (!status_.fixed_shutter && !status_.fixed_analogue_gain &&
|
||||
status_.flicker_period) {
|
||||
int flicker_periods = shutter_time / status_.flicker_period;
|
||||
if (flicker_periods > 0) {
|
||||
double new_shutter_time = flicker_periods * status_.flicker_period;
|
||||
if (flicker_periods) {
|
||||
Duration new_shutter_time = flicker_periods * status_.flicker_period;
|
||||
analogue_gain *= shutter_time / new_shutter_time;
|
||||
// We should still not allow the ag to go over the
|
||||
// largest value in the exposure mode. Note that this
|
||||
|
@ -739,7 +747,7 @@ void Agc::divideUpExposure()
|
|||
void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)
|
||||
{
|
||||
status_.total_exposure_value = filtered_.total_exposure;
|
||||
status_.target_exposure_value = desaturate ? 0 : target_.total_exposure_no_dg;
|
||||
status_.target_exposure_value = desaturate ? 0s : target_.total_exposure_no_dg;
|
||||
status_.shutter_time = filtered_.shutter;
|
||||
status_.analogue_gain = filtered_.analogue_gain;
|
||||
// Write to metadata as well, in case anyone wants to update the camera
|
||||
|
@ -751,7 +759,7 @@ void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)
|
|||
<< " analogue gain " << filtered_.analogue_gain;
|
||||
}
|
||||
|
||||
double Agc::clipShutter(double shutter)
|
||||
Duration Agc::clipShutter(Duration shutter)
|
||||
{
|
||||
if (max_shutter_)
|
||||
shutter = std::min(shutter, max_shutter_);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue