Skip to content

Commit 3f50974

Browse files
davidplowmankbingham
authored andcommitted
ipa: rpi: ccm: Implement "manual" CCM mode
The CCM algorithm will now let an explicit colour matrix be set when AWB is in manual mode. We must handle any controls that can cause the AWB to be enabled or disabled first, so that we know the AWB's state correctly when we come to set the CCM. Signed-off-by: David Plowman <[email protected]> Reviewed-by: Naushir Patuck <[email protected]> [Kieran: Remove duplicated Matrix3x3 from ccm.cpp] Signed-off-by: Kieran Bingham <[email protected]>
1 parent 17ae869 commit 3f50974

File tree

5 files changed

+170
-49
lines changed

5 files changed

+170
-49
lines changed

src/ipa/rpi/common/ipa_base.cpp

Lines changed: 136 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ const ControlInfoMap::Map ipaColourControls{
9494
{ &controls::AwbEnable, ControlInfo(false, true) },
9595
{ &controls::AwbMode, ControlInfo(controls::AwbModeValues) },
9696
{ &controls::ColourGains, ControlInfo(0.0f, 32.0f) },
97+
{ &controls::ColourCorrectionMatrix, ControlInfo(0.0f, 8.0f) },
9798
{ &controls::ColourTemperature, ControlInfo(100, 100000) },
9899
{ &controls::Saturation, ControlInfo(0.0f, 32.0f, 1.0f) },
99100
};
@@ -126,7 +127,7 @@ namespace ipa::RPi {
126127
IpaBase::IpaBase()
127128
: controller_(), frameLengths_(FrameLengthsQueueSize, 0s), statsMetadataOutput_(false),
128129
stitchSwapBuffers_(false), frameCount_(0), mistrustCount_(0), lastRunTimestamp_(0),
129-
firstStart_(true), flickerState_({ 0, 0s })
130+
firstStart_(true), flickerState_({ 0, 0s }), awbEnabled_(true)
130131
{
131132
}
132133

@@ -821,6 +822,102 @@ void IpaBase::applyControls(const ControlList &controls)
821822
}
822823
}
823824

825+
/*
826+
* We must also handle any AWB on/off changes first, so that the CCM algorithm
827+
* knows its state correctly.
828+
*/
829+
const auto awbEnable = controls.get(controls::AwbEnable);
830+
if (awbEnable)
831+
do {
832+
/* Silently ignore this control for a mono sensor. */
833+
if (monoSensor_)
834+
break;
835+
836+
RPiController::AwbAlgorithm *awb = dynamic_cast<RPiController::AwbAlgorithm *>(
837+
controller_.getAlgorithm("awb"));
838+
if (!awb) {
839+
LOG(IPARPI, Warning)
840+
<< "Could not set AWB_ENABLE - no AWB algorithm";
841+
break;
842+
}
843+
844+
awbEnabled_ = *awbEnable;
845+
846+
if (!awbEnabled_)
847+
awb->disableAuto();
848+
else {
849+
awb->enableAuto();
850+
851+
/* The CCM algorithm must go back to auto as well. */
852+
RPiController::CcmAlgorithm *ccm = dynamic_cast<RPiController::CcmAlgorithm *>(
853+
controller_.getAlgorithm("ccm"));
854+
if (ccm)
855+
ccm->enableAuto();
856+
}
857+
858+
libcameraMetadata_.set(controls::AwbEnable, awbEnabled_);
859+
} while (false);
860+
861+
const auto colourGains = controls.get(controls::ColourGains);
862+
if (colourGains)
863+
do {
864+
/* Silently ignore this control for a mono sensor. */
865+
if (monoSensor_)
866+
break;
867+
868+
auto gains = *colourGains;
869+
RPiController::AwbAlgorithm *awb = dynamic_cast<RPiController::AwbAlgorithm *>(
870+
controller_.getAlgorithm("awb"));
871+
if (!awb) {
872+
LOG(IPARPI, Warning)
873+
<< "Could not set COLOUR_GAINS - no AWB algorithm";
874+
break;
875+
}
876+
877+
awb->setManualGains(gains[0], gains[1]);
878+
if (gains[0] != 0.0f && gains[1] != 0.0f) {
879+
/* A gain of 0.0f will switch back to auto mode. */
880+
libcameraMetadata_.set(controls::ColourGains,
881+
{ gains[0], gains[1] });
882+
883+
awbEnabled_ = false; /* doing this puts AWB into manual mode */
884+
} else {
885+
awbEnabled_ = true; /* doing this puts AWB into auto mode */
886+
887+
/* The CCM algorithm must go back to auto as well. */
888+
RPiController::CcmAlgorithm *ccm = dynamic_cast<RPiController::CcmAlgorithm *>(
889+
controller_.getAlgorithm("ccm"));
890+
if (ccm)
891+
ccm->enableAuto();
892+
}
893+
894+
/* This metadata will get reported back automatically. */
895+
break;
896+
} while (false);
897+
898+
const auto colourTemperature = controls.get(controls::ColourTemperature);
899+
if (colourTemperature)
900+
do {
901+
/* Silently ignore this control for a mono sensor. */
902+
if (monoSensor_)
903+
break;
904+
905+
auto temperatureK = *colourTemperature;
906+
RPiController::AwbAlgorithm *awb = dynamic_cast<RPiController::AwbAlgorithm *>(
907+
controller_.getAlgorithm("awb"));
908+
if (!awb) {
909+
LOG(IPARPI, Warning)
910+
<< "Could not set COLOUR_TEMPERATURE - no AWB algorithm";
911+
break;
912+
}
913+
914+
awb->setColourTemperature(temperatureK);
915+
awbEnabled_ = false; /* doing this puts AWB into manual mode */
916+
917+
/* This metadata will get reported back automatically. */
918+
break;
919+
} while (false);
920+
824921
/* Iterate over controls */
825922
for (auto const &ctrl : controls) {
826923
LOG(IPARPI, Debug) << "Request ctrl: "
@@ -1037,25 +1134,7 @@ void IpaBase::applyControls(const ControlList &controls)
10371134
}
10381135

10391136
case controls::AWB_ENABLE: {
1040-
/* Silently ignore this control for a mono sensor. */
1041-
if (monoSensor_)
1042-
break;
1043-
1044-
RPiController::AwbAlgorithm *awb = dynamic_cast<RPiController::AwbAlgorithm *>(
1045-
controller_.getAlgorithm("awb"));
1046-
if (!awb) {
1047-
LOG(IPARPI, Warning)
1048-
<< "Could not set AWB_ENABLE - no AWB algorithm";
1049-
break;
1050-
}
1051-
1052-
if (ctrl.second.get<bool>() == false)
1053-
awb->disableAuto();
1054-
else
1055-
awb->enableAuto();
1056-
1057-
libcameraMetadata_.set(controls::AwbEnable,
1058-
ctrl.second.get<bool>());
1137+
/* We handled this one above. */
10591138
break;
10601139
}
10611140

@@ -1080,47 +1159,60 @@ void IpaBase::applyControls(const ControlList &controls)
10801159
LOG(IPARPI, Error) << "AWB mode " << idx
10811160
<< " not recognised";
10821161
}
1162+
10831163
break;
10841164
}
10851165

10861166
case controls::COLOUR_GAINS: {
1087-
/* Silently ignore this control for a mono sensor. */
1088-
if (monoSensor_)
1089-
break;
1090-
1091-
auto gains = ctrl.second.get<Span<const float>>();
1092-
RPiController::AwbAlgorithm *awb = dynamic_cast<RPiController::AwbAlgorithm *>(
1093-
controller_.getAlgorithm("awb"));
1094-
if (!awb) {
1095-
LOG(IPARPI, Warning)
1096-
<< "Could not set COLOUR_GAINS - no AWB algorithm";
1097-
break;
1098-
}
1099-
1100-
awb->setManualGains(gains[0], gains[1]);
1101-
if (gains[0] != 0.0f && gains[1] != 0.0f)
1102-
/* A gain of 0.0f will switch back to auto mode. */
1103-
libcameraMetadata_.set(controls::ColourGains,
1104-
{ gains[0], gains[1] });
1167+
/* We handled this one above. */
11051168
break;
11061169
}
11071170

11081171
case controls::COLOUR_TEMPERATURE: {
1109-
/* Silently ignore this control for a mono sensor. */
1172+
/* We handled this one above. */
1173+
break;
1174+
}
1175+
1176+
case controls::COLOUR_CORRECTION_MATRIX: {
11101177
if (monoSensor_)
11111178
break;
11121179

1113-
auto temperatureK = ctrl.second.get<int32_t>();
1180+
auto floats = ctrl.second.get<Span<const float>>();
1181+
RPiController::CcmAlgorithm *ccm = dynamic_cast<RPiController::CcmAlgorithm *>(
1182+
controller_.getAlgorithm("ccm"));
1183+
if (!ccm) {
1184+
LOG(IPARPI, Warning)
1185+
<< "Could not set COLOUR_CORRECTION_MATRIX - no CCM algorithm";
1186+
break;
1187+
}
1188+
11141189
RPiController::AwbAlgorithm *awb = dynamic_cast<RPiController::AwbAlgorithm *>(
11151190
controller_.getAlgorithm("awb"));
1116-
if (!awb) {
1191+
if (awb && awbEnabled_) {
11171192
LOG(IPARPI, Warning)
1118-
<< "Could not set COLOUR_TEMPERATURE - no AWB algorithm";
1193+
<< "Could not set COLOUR_CORRECTION_MATRIX - AWB is active";
11191194
break;
11201195
}
11211196

1122-
awb->setColourTemperature(temperatureK);
1123-
/* This metadata will get reported back automatically. */
1197+
/* We are guaranteed this control contains 9 values. Nevertheless: */
1198+
assert(floats.size() == 9);
1199+
1200+
Matrix<double, 3, 3> matrix;
1201+
for (std::size_t i = 0; i < 3; ++i)
1202+
for (std::size_t j = 0; j < 3; ++j)
1203+
matrix[i][j] = static_cast<double>(floats[i * 3 + j]);
1204+
1205+
ccm->setCcm(matrix);
1206+
1207+
/*
1208+
* But if AWB is running, go back to auto mode. The CCM gets remembered,
1209+
* which avoids the race between setting the CCM and disabling AWB in
1210+
* the same set of controls.
1211+
*/
1212+
if (awbEnabled_)
1213+
ccm->enableAuto();
1214+
1215+
/* This metadata will be reported back automatically. */
11241216
break;
11251217
}
11261218

src/ipa/rpi/common/ipa_base.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ class IpaBase : public IPARPiInterface
140140
int32_t mode;
141141
utils::Duration manualPeriod;
142142
} flickerState_;
143+
144+
bool awbEnabled_;
143145
};
144146

145147
} /* namespace ipa::RPi */

src/ipa/rpi/controller/ccm_algorithm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,22 @@
66
*/
77
#pragma once
88

9+
#include "libcamera/internal/matrix.h"
10+
911
#include "algorithm.h"
1012

1113
namespace RPiController {
1214

15+
using Matrix3x3 = libcamera::Matrix<double, 3, 3>;
16+
1317
class CcmAlgorithm : public Algorithm
1418
{
1519
public:
1620
CcmAlgorithm(Controller *controller) : Algorithm(controller) {}
1721
/* A CCM algorithm must provide the following: */
22+
virtual void enableAuto() = 0;
1823
virtual void setSaturation(double saturation) = 0;
24+
virtual void setCcm(Matrix3x3 const &matrix) = 0;
1925
};
2026

2127
} /* namespace RPiController */

src/ipa/rpi/controller/rpi/ccm.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ LOG_DEFINE_CATEGORY(RPiCcm)
2929

3030
#define NAME "rpi.ccm"
3131

32-
using Matrix3x3 = Matrix<double, 3, 3>;
33-
3432
Ccm::Ccm(Controller *controller)
35-
: CcmAlgorithm(controller), saturation_(1.0) {}
33+
: CcmAlgorithm(controller), enableAuto_(true), saturation_(1.0),
34+
manualCcm_({ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 })
35+
{
36+
}
3637

3738
char const *Ccm::name() const
3839
{
@@ -78,11 +79,22 @@ int Ccm::read(const libcamera::YamlObject &params)
7879
return 0;
7980
}
8081

82+
void Ccm::enableAuto()
83+
{
84+
enableAuto_ = true;
85+
}
86+
8187
void Ccm::setSaturation(double saturation)
8288
{
8389
saturation_ = saturation;
8490
}
8591

92+
void Ccm::setCcm(Matrix3x3 const &matrix)
93+
{
94+
enableAuto_ = false;
95+
manualCcm_ = matrix;
96+
}
97+
8698
void Ccm::initialise()
8799
{
88100
}
@@ -151,7 +163,13 @@ void Ccm::prepare(Metadata *imageMetadata)
151163
LOG(RPiCcm, Warning) << "no colour temperature found";
152164
if (!luxOk)
153165
LOG(RPiCcm, Warning) << "no lux value found";
154-
Matrix3x3 ccm = calculateCcm(config_.ccms, awb.temperatureK);
166+
167+
Matrix3x3 ccm;
168+
if (enableAuto_)
169+
ccm = calculateCcm(config_.ccms, awb.temperatureK);
170+
else
171+
ccm = manualCcm_;
172+
155173
double saturation = saturation_;
156174
struct CcmStatus ccmStatus;
157175
ccmStatus.saturation = saturation;

src/ipa/rpi/controller/rpi/ccm.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
#include <vector>
1010

11-
#include "libcamera/internal/matrix.h"
1211
#include <libipa/pwl.h>
1312

1413
#include "../ccm_algorithm.h"
@@ -33,13 +32,17 @@ class Ccm : public CcmAlgorithm
3332
Ccm(Controller *controller = NULL);
3433
char const *name() const override;
3534
int read(const libcamera::YamlObject &params) override;
35+
void enableAuto() override;
3636
void setSaturation(double saturation) override;
37+
void setCcm(Matrix3x3 const &matrix) override;
3738
void initialise() override;
3839
void prepare(Metadata *imageMetadata) override;
3940

4041
private:
4142
CcmConfig config_;
43+
bool enableAuto_;
4244
double saturation_;
45+
Matrix3x3 manualCcm_;
4346
};
4447

4548
} /* namespace RPiController */

0 commit comments

Comments
 (0)