[libcamera-devel,05/10] libcamera: ipa: raspberrypi: agc: Fetch AWB status only once
diff mbox series

Message ID 20201116164918.2055-6-david.plowman@raspberrypi.com
State Superseded
Headers show
Series
  • Raspberry Pi AGC
Related show

Commit Message

David Plowman Nov. 16, 2020, 4:49 p.m. UTC
Introduce a function to fetch the AwbStatus (fetchAwbStatus), and call
it unconditionally at the top of Prepare so that both Prepare and
Process know thereafter that it's been done.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
---
 src/ipa/raspberrypi/controller/rpi/agc.cpp | 37 ++++++++++++----------
 src/ipa/raspberrypi/controller/rpi/agc.hpp |  5 +--
 2 files changed, 23 insertions(+), 19 deletions(-)

Comments

Naushir Patuck Nov. 17, 2020, 10:45 a.m. UTC | #1
Hi David,


On Mon, 16 Nov 2020 at 16:49, David Plowman <david.plowman@raspberrypi.com>
wrote:

> Introduce a function to fetch the AwbStatus (fetchAwbStatus), and call
> it unconditionally at the top of Prepare so that both Prepare and
> Process know thereafter that it's been done.
>
> Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
> ---
>  src/ipa/raspberrypi/controller/rpi/agc.cpp | 37 ++++++++++++----------
>  src/ipa/raspberrypi/controller/rpi/agc.hpp |  5 +--
>  2 files changed, 23 insertions(+), 19 deletions(-)
>
> diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp
> b/src/ipa/raspberrypi/controller/rpi/agc.cpp
> index ead28398..6de56def 100644
> --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp
> +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp
> @@ -5,6 +5,8 @@
>   * agc.cpp - AGC/AEC control algorithm
>   */
>
> +#include <assert.h>
>

Perhaps you can use the ASSERT() macro defined in libcamera (log.h)?  I
think all code under libcamera is meant to use it instead of the standard
one.


> +
>  #include <map>
>
>  #include "linux/bcm2835-isp.h"
> @@ -235,6 +237,8 @@ void Agc::Prepare(Metadata *image_metadata)
>         int lock_count = lock_count_;
>         lock_count_ = 0;
>         status_.digital_gain = 1.0;
> +       fetchAwbStatus(image_metadata); // always fetch it so that Process
> knows it's been done
> +
>         if (status_.total_exposure_value) {
>                 // Process has run, so we have meaningful values.
>                 DeviceStatus device_status;
> @@ -301,7 +305,7 @@ void Agc::Process(StatisticsPtr &stats, Metadata
> *image_metadata)
>         // 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(image_metadata, gain, target_Y);
> +       bool desaturate = applyDigitalGain(gain, target_Y);
>         // 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
> @@ -378,14 +382,19 @@ void Agc::fetchCurrentExposure(Metadata
> *image_metadata)
>         current_.total_exposure_no_dg = current_.shutter *
> current_.analogue_gain;
>  }
>
> -static double compute_initial_Y(bcm2835_isp_stats *stats, Metadata
> *image_metadata,
> +void Agc::fetchAwbStatus(Metadata *image_metadata)
> +{
> +       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)
> +               LOG(RPiAgc, Warning) << "Agc: no AWB status found";
> +}
> +
> +static double compute_initial_Y(bcm2835_isp_stats *stats, AwbStatus const
> &awb,
>                                 double weights[])
>  {
>         bcm2835_isp_stats_region *regions = stats->agc_stats;
> -       struct AwbStatus awb;
> -       awb.gain_r = awb.gain_g = awb.gain_b = 1.0; // in case no metadata
> -       if (image_metadata->Get("awb.status", awb) != 0)
> -               LOG(RPiAgc, Warning) << "Agc: no AWB status found";
>         // 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;
> @@ -437,7 +446,7 @@ void Agc::computeGain(bcm2835_isp_stats *statistics,
> Metadata *image_metadata,
>         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);
> -       double initial_Y = compute_initial_Y(statistics, image_metadata,
> +       double initial_Y = compute_initial_Y(statistics, awb_,
>                                              metering_mode_->weights);
>         gain = std::min(10.0, target_Y / (initial_Y + .001));
>         LOG(RPiAgc, Debug) << "Initially Y " << initial_Y << " target " <<
> target_Y
> @@ -483,19 +492,13 @@ void Agc::computeTargetExposure(double gain)
>         LOG(RPiAgc, Debug) << "Target total_exposure " <<
> target_.total_exposure;
>  }
>
> -bool Agc::applyDigitalGain(Metadata *image_metadata, double gain,
> -                          double target_Y)
> +bool Agc::applyDigitalGain(double gain, double target_Y)
>  {
> -       double dg = 1.0;
> +       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;
>         // I think this pipeline subtracts black level and rescales before
> we
>         // get the stats, so no need to worry about it.
> -       struct AwbStatus awb;
> -       if (image_metadata->Get("awb.status", awb) == 0) {
> -               double min_gain = std::min(awb.gain_r,
> -                                          std::min(awb.gain_g,
> awb.gain_b));
> -               dg *= std::max(1.0, 1.0 / min_gain);
> -       } else
> -               LOG(RPiAgc, Warning) << "Agc: no AWB status found";
>         LOG(RPiAgc, Debug) << "after AWB, target dg " << dg << " gain " <<
> gain
>                            << " target_Y " << target_Y;
>         // Finally, if we're trying to reduce exposure but the target_Y is
> diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp
> b/src/ipa/raspberrypi/controller/rpi/agc.hpp
> index 2442fc03..e7ac480f 100644
> --- a/src/ipa/raspberrypi/controller/rpi/agc.hpp
> +++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp
> @@ -83,11 +83,11 @@ private:
>         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 computeTargetExposure(double gain);
> -       bool applyDigitalGain(Metadata *image_metadata, double gain,
> -                             double target_Y);
> +       bool applyDigitalGain(double gain, double target_Y);
>         void filterExposure(bool desaturate);
>         void divideUpExposure();
>         void writeAndFinish(Metadata *image_metadata, bool desaturate);
> @@ -95,6 +95,7 @@ private:
>         AgcExposureMode *exposure_mode_;
>         AgcConstraintMode *constraint_mode_;
>         uint64_t frame_count_;
> +       AwbStatus awb_;
>         struct ExposureValues {
>                 ExposureValues() : shutter(0), analogue_gain(0),
>                                    total_exposure(0),
> total_exposure_no_dg(0) {}
>

Aparat from the minor:

Reviewed-by: Naushir Patuck <naush@raspberrypi.com>


> --
> 2.20.1
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
>

Patch
diff mbox series

diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp
index ead28398..6de56def 100644
--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp
@@ -5,6 +5,8 @@ 
  * agc.cpp - AGC/AEC control algorithm
  */
 
+#include <assert.h>
+
 #include <map>
 
 #include "linux/bcm2835-isp.h"
@@ -235,6 +237,8 @@  void Agc::Prepare(Metadata *image_metadata)
 	int lock_count = lock_count_;
 	lock_count_ = 0;
 	status_.digital_gain = 1.0;
+	fetchAwbStatus(image_metadata); // always fetch it so that Process knows it's been done
+
 	if (status_.total_exposure_value) {
 		// Process has run, so we have meaningful values.
 		DeviceStatus device_status;
@@ -301,7 +305,7 @@  void Agc::Process(StatisticsPtr &stats, Metadata *image_metadata)
 	// 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(image_metadata, gain, target_Y);
+	bool desaturate = applyDigitalGain(gain, target_Y);
 	// 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
@@ -378,14 +382,19 @@  void Agc::fetchCurrentExposure(Metadata *image_metadata)
 	current_.total_exposure_no_dg = current_.shutter * current_.analogue_gain;
 }
 
-static double compute_initial_Y(bcm2835_isp_stats *stats, Metadata *image_metadata,
+void Agc::fetchAwbStatus(Metadata *image_metadata)
+{
+	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)
+		LOG(RPiAgc, Warning) << "Agc: no AWB status found";
+}
+
+static double compute_initial_Y(bcm2835_isp_stats *stats, AwbStatus const &awb,
 				double weights[])
 {
 	bcm2835_isp_stats_region *regions = stats->agc_stats;
-	struct AwbStatus awb;
-	awb.gain_r = awb.gain_g = awb.gain_b = 1.0; // in case no metadata
-	if (image_metadata->Get("awb.status", awb) != 0)
-		LOG(RPiAgc, Warning) << "Agc: no AWB status found";
 	// 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;
@@ -437,7 +446,7 @@  void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata,
 	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);
-	double initial_Y = compute_initial_Y(statistics, image_metadata,
+	double initial_Y = compute_initial_Y(statistics, awb_,
 					     metering_mode_->weights);
 	gain = std::min(10.0, target_Y / (initial_Y + .001));
 	LOG(RPiAgc, Debug) << "Initially Y " << initial_Y << " target " << target_Y
@@ -483,19 +492,13 @@  void Agc::computeTargetExposure(double gain)
 	LOG(RPiAgc, Debug) << "Target total_exposure " << target_.total_exposure;
 }
 
-bool Agc::applyDigitalGain(Metadata *image_metadata, double gain,
-			   double target_Y)
+bool Agc::applyDigitalGain(double gain, double target_Y)
 {
-	double dg = 1.0;
+	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;
 	// I think this pipeline subtracts black level and rescales before we
 	// get the stats, so no need to worry about it.
-	struct AwbStatus awb;
-	if (image_metadata->Get("awb.status", awb) == 0) {
-		double min_gain = std::min(awb.gain_r,
-					   std::min(awb.gain_g, awb.gain_b));
-		dg *= std::max(1.0, 1.0 / min_gain);
-	} else
-		LOG(RPiAgc, Warning) << "Agc: no AWB status found";
 	LOG(RPiAgc, Debug) << "after AWB, target dg " << dg << " gain " << gain
 			   << " target_Y " << target_Y;
 	// Finally, if we're trying to reduce exposure but the target_Y is
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp
index 2442fc03..e7ac480f 100644
--- a/src/ipa/raspberrypi/controller/rpi/agc.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp
@@ -83,11 +83,11 @@  private:
 	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 computeTargetExposure(double gain);
-	bool applyDigitalGain(Metadata *image_metadata, double gain,
-			      double target_Y);
+	bool applyDigitalGain(double gain, double target_Y);
 	void filterExposure(bool desaturate);
 	void divideUpExposure();
 	void writeAndFinish(Metadata *image_metadata, bool desaturate);
@@ -95,6 +95,7 @@  private:
 	AgcExposureMode *exposure_mode_;
 	AgcConstraintMode *constraint_mode_;
 	uint64_t frame_count_;
+	AwbStatus awb_;
 	struct ExposureValues {
 		ExposureValues() : shutter(0), analogue_gain(0),
 				   total_exposure(0), total_exposure_no_dg(0) {}