diff options
Diffstat (limited to 'src/ipa/rkisp1/algorithms/agc.cpp')
-rw-r--r-- | src/ipa/rkisp1/algorithms/agc.cpp | 112 |
1 files changed, 74 insertions, 38 deletions
diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 1680669c..b3ac9400 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -149,13 +149,13 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData) return ret; context.ctrlMap[&controls::ExposureTimeMode] = - ControlInfo(static_cast<int32_t>(controls::ExposureTimeModeAuto), - static_cast<int32_t>(controls::ExposureTimeModeManual), - static_cast<int32_t>(controls::ExposureTimeModeAuto)); + ControlInfo({ { ControlValue(controls::ExposureTimeModeAuto), + ControlValue(controls::ExposureTimeModeManual) } }, + ControlValue(controls::ExposureTimeModeAuto)); context.ctrlMap[&controls::AnalogueGainMode] = - ControlInfo(static_cast<int32_t>(controls::AnalogueGainModeAuto), - static_cast<int32_t>(controls::AnalogueGainModeManual), - static_cast<int32_t>(controls::AnalogueGainModeAuto)); + ControlInfo({ { ControlValue(controls::AnalogueGainModeAuto), + ControlValue(controls::AnalogueGainModeManual) } }, + ControlValue(controls::AnalogueGainModeAuto)); /* \todo Move this to the Camera class */ context.ctrlMap[&controls::AeEnable] = ControlInfo(false, true, true); context.ctrlMap.merge(controls()); @@ -188,21 +188,15 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) context.activeState.agc.meteringMode = static_cast<controls::AeMeteringModeEnum>(meteringModes_.begin()->first); - /* - * \todo This should probably come from FrameDurationLimits instead, - * except it's computed in the IPA and not here so we'd have to - * recompute it. - */ - context.activeState.agc.maxFrameDuration = context.configuration.sensor.maxExposureTime; + /* Limit the frame duration to match current initialisation */ + ControlInfo &frameDurationLimits = context.ctrlMap[&controls::FrameDurationLimits]; + context.activeState.agc.minFrameDuration = std::chrono::microseconds(frameDurationLimits.min().get<int64_t>()); + context.activeState.agc.maxFrameDuration = std::chrono::microseconds(frameDurationLimits.max().get<int64_t>()); - /* - * Define the measurement window for AGC as a centered rectangle - * covering 3/4 of the image width and height. - */ - context.configuration.agc.measureWindow.h_offs = configInfo.outputSize.width / 8; - context.configuration.agc.measureWindow.v_offs = configInfo.outputSize.height / 8; - context.configuration.agc.measureWindow.h_size = 3 * configInfo.outputSize.width / 4; - context.configuration.agc.measureWindow.v_size = 3 * configInfo.outputSize.height / 4; + context.configuration.agc.measureWindow.h_offs = 0; + context.configuration.agc.measureWindow.v_offs = 0; + context.configuration.agc.measureWindow.h_size = configInfo.outputSize.width; + context.configuration.agc.measureWindow.v_size = configInfo.outputSize.height; setLimits(context.configuration.sensor.minExposureTime, context.configuration.sensor.maxExposureTime, @@ -310,10 +304,21 @@ void Agc::queueRequest(IPAContext &context, const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits); if (frameDurationLimits) { - utils::Duration maxFrameDuration = - std::chrono::milliseconds((*frameDurationLimits).back()); - agc.maxFrameDuration = maxFrameDuration; + /* Limit the control value to the limits in ControlInfo */ + ControlInfo &limits = context.ctrlMap[&controls::FrameDurationLimits]; + int64_t minFrameDuration = + std::clamp((*frameDurationLimits).front(), + limits.min().get<int64_t>(), + limits.max().get<int64_t>()); + int64_t maxFrameDuration = + std::clamp((*frameDurationLimits).back(), + limits.min().get<int64_t>(), + limits.max().get<int64_t>()); + + agc.minFrameDuration = std::chrono::microseconds(minFrameDuration); + agc.maxFrameDuration = std::chrono::microseconds(maxFrameDuration); } + frameContext.agc.minFrameDuration = agc.minFrameDuration; frameContext.agc.maxFrameDuration = agc.maxFrameDuration; } @@ -390,6 +395,7 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, * frameContext.sensor.exposure; metadata.set(controls::AnalogueGain, frameContext.sensor.gain); metadata.set(controls::ExposureTime, exposureTime.get<std::micro>()); + metadata.set(controls::FrameDuration, frameContext.agc.frameDuration.get<std::micro>()); metadata.set(controls::ExposureTimeMode, frameContext.agc.autoExposureEnabled ? controls::ExposureTimeModeAuto @@ -399,13 +405,6 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, ? controls::AnalogueGainModeAuto : controls::AnalogueGainModeManual); - /* \todo Use VBlank value calculated from each frame exposure. */ - uint32_t vTotal = context.configuration.sensor.size.height - + context.configuration.sensor.defVBlank; - utils::Duration frameDuration = context.configuration.sensor.lineDuration - * vTotal; - metadata.set(controls::FrameDuration, frameDuration.get<std::micro>()); - metadata.set(controls::AeMeteringMode, frameContext.agc.meteringMode); metadata.set(controls::AeExposureMode, frameContext.agc.exposureMode); metadata.set(controls::AeConstraintMode, frameContext.agc.constraintMode); @@ -436,15 +435,41 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, */ double Agc::estimateLuminance(double gain) const { + ASSERT(expMeans_.size() == weights_.size()); double ySum = 0.0; + double wSum = 0.0; /* Sum the averages, saturated to 255. */ - for (uint8_t expMean : expMeans_) - ySum += std::min(expMean * gain, 255.0); + for (unsigned i = 0; i < expMeans_.size(); i++) { + double w = weights_[i]; + ySum += std::min(expMeans_[i] * gain, 255.0) * w; + wSum += w; + } /* \todo Weight with the AWB gains */ - return ySum / expMeans_.size() / 255; + return ySum / wSum / 255; +} + +/** + * \brief Process frame duration and compute vblank + * \param[in] context The shared IPA context + * \param[in] frameContext The current frame context + * \param[in] frameDuration The target frame duration + * + * Compute and populate vblank from the target frame duration. + */ +void Agc::processFrameDuration(IPAContext &context, + IPAFrameContext &frameContext, + utils::Duration frameDuration) +{ + IPACameraSensorInfo &sensorInfo = context.sensorInfo; + utils::Duration lineDuration = context.configuration.sensor.lineDuration; + + frameContext.agc.vblank = (frameDuration / lineDuration) - sensorInfo.outputSize.height; + + /* Update frame duration accounting for line length quantization. */ + frameContext.agc.frameDuration = (sensorInfo.outputSize.height + frameContext.agc.vblank) * lineDuration; } /** @@ -463,16 +488,20 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, ControlList &metadata) { if (!stats) { + processFrameDuration(context, frameContext, + frameContext.agc.minFrameDuration); fillMetadata(context, frameContext, metadata); return; } - + if (!(stats->meas_type & RKISP1_CIF_ISP_STAT_AUTOEXP)) { fillMetadata(context, frameContext, metadata); LOG(RkISP1Agc, Error) << "AUTOEXP data is missing in statistics"; return; } + const utils::Duration &lineDuration = context.configuration.sensor.lineDuration; + /* * \todo Verify that the exposure and gain applied by the sensor for * this frame match what has been requested. This isn't a hard @@ -487,6 +516,8 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, Histogram hist({ params->hist.hist_bins, context.hw->numHistogramBins }, [](uint32_t x) { return x >> 4; }); expMeans_ = { params->ae.exp_mean, context.hw->numAeCells }; + std::vector<uint8_t> &modeWeights = meteringModes_.at(frameContext.agc.meteringMode); + weights_ = { modeWeights.data(), modeWeights.size() }; /* * Set the AGC limits using the fixed exposure time and/or gain in @@ -522,8 +553,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, * The Agc algorithm needs to know the effective exposure value that was * applied to the sensor when the statistics were collected. */ - utils::Duration exposureTime = context.configuration.sensor.lineDuration - * frameContext.sensor.exposure; + utils::Duration exposureTime = lineDuration * frameContext.sensor.exposure; double analogueGain = frameContext.sensor.gain; utils::Duration effectiveExposureValue = exposureTime * analogueGain; @@ -540,10 +570,16 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAActiveState &activeState = context.activeState; /* Update the estimated exposure and gain. */ - activeState.agc.automatic.exposure = newExposureTime - / context.configuration.sensor.lineDuration; + activeState.agc.automatic.exposure = newExposureTime / lineDuration; activeState.agc.automatic.gain = aGain; + /* + * Expand the target frame duration so that we do not run faster than + * the minimum frame duration when we have short exposures. + */ + processFrameDuration(context, frameContext, + std::max(frameContext.agc.minFrameDuration, newExposureTime)); + fillMetadata(context, frameContext, metadata); expMeans_ = {}; } |