-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libcamera: software_isp: Move exposure+gain to an algorithm module
This is the last step to fully convert software ISP to Algorithm-based processing. The newly introduced frameContext.sensor parameters are set, and the updated code moved, before calling Algorithm::process() to have the values up-to-date in stats processing. Resolves software ISP TODO #10. Signed-off-by: Milan Zamazal <[email protected]> Reviewed-by: Kieran Bingham <[email protected]> Reviewed-by: Umang Jain <[email protected]> Signed-off-by: Kieran Bingham <[email protected]>
- Loading branch information
Showing
8 changed files
with
228 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* SPDX-License-Identifier: LGPL-2.1-or-later */ | ||
/* | ||
* Copyright (C) 2024, Red Hat Inc. | ||
* | ||
* Exposure and gain | ||
*/ | ||
|
||
#include "agc.h" | ||
|
||
#include <stdint.h> | ||
|
||
#include <libcamera/base/log.h> | ||
|
||
namespace libcamera { | ||
|
||
LOG_DEFINE_CATEGORY(IPASoftExposure) | ||
|
||
namespace ipa::soft::algorithms { | ||
|
||
/* | ||
* The number of bins to use for the optimal exposure calculations. | ||
*/ | ||
static constexpr unsigned int kExposureBinsCount = 5; | ||
|
||
/* | ||
* The exposure is optimal when the mean sample value of the histogram is | ||
* in the middle of the range. | ||
*/ | ||
static constexpr float kExposureOptimal = kExposureBinsCount / 2.0; | ||
|
||
/* | ||
* The below value implements the hysteresis for the exposure adjustment. | ||
* It is small enough to have the exposure close to the optimal, and is big | ||
* enough to prevent the exposure from wobbling around the optimal value. | ||
*/ | ||
static constexpr float kExposureSatisfactory = 0.2; | ||
|
||
Agc::Agc() | ||
{ | ||
} | ||
|
||
void Agc::updateExposure(IPAContext &context, double exposureMSV) | ||
{ | ||
/* | ||
* kExpDenominator of 10 gives ~10% increment/decrement; | ||
* kExpDenominator of 5 - about ~20% | ||
*/ | ||
static constexpr uint8_t kExpDenominator = 10; | ||
static constexpr uint8_t kExpNumeratorUp = kExpDenominator + 1; | ||
static constexpr uint8_t kExpNumeratorDown = kExpDenominator - 1; | ||
|
||
double next; | ||
int32_t &exposure = context.activeState.agc.exposure; | ||
double &again = context.activeState.agc.again; | ||
|
||
if (exposureMSV < kExposureOptimal - kExposureSatisfactory) { | ||
next = exposure * kExpNumeratorUp / kExpDenominator; | ||
if (next - exposure < 1) | ||
exposure += 1; | ||
else | ||
exposure = next; | ||
if (exposure >= context.configuration.agc.exposureMax) { | ||
next = again * kExpNumeratorUp / kExpDenominator; | ||
if (next - again < context.configuration.agc.againMinStep) | ||
again += context.configuration.agc.againMinStep; | ||
else | ||
again = next; | ||
} | ||
} | ||
|
||
if (exposureMSV > kExposureOptimal + kExposureSatisfactory) { | ||
if (exposure == context.configuration.agc.exposureMax && | ||
again > context.configuration.agc.againMin) { | ||
next = again * kExpNumeratorDown / kExpDenominator; | ||
if (again - next < context.configuration.agc.againMinStep) | ||
again -= context.configuration.agc.againMinStep; | ||
else | ||
again = next; | ||
} else { | ||
next = exposure * kExpNumeratorDown / kExpDenominator; | ||
if (exposure - next < 1) | ||
exposure -= 1; | ||
else | ||
exposure = next; | ||
} | ||
} | ||
|
||
exposure = std::clamp(exposure, context.configuration.agc.exposureMin, | ||
context.configuration.agc.exposureMax); | ||
again = std::clamp(again, context.configuration.agc.againMin, | ||
context.configuration.agc.againMax); | ||
|
||
LOG(IPASoftExposure, Debug) | ||
<< "exposureMSV " << exposureMSV | ||
<< " exp " << exposure << " again " << again; | ||
} | ||
|
||
void Agc::process(IPAContext &context, | ||
[[maybe_unused]] const uint32_t frame, | ||
[[maybe_unused]] IPAFrameContext &frameContext, | ||
const SwIspStats *stats, | ||
[[maybe_unused]] ControlList &metadata) | ||
{ | ||
/* | ||
* Calculate Mean Sample Value (MSV) according to formula from: | ||
* https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf | ||
*/ | ||
const auto &histogram = stats->yHistogram; | ||
const unsigned int blackLevelHistIdx = | ||
context.activeState.blc.level / (256 / SwIspStats::kYHistogramSize); | ||
const unsigned int histogramSize = | ||
SwIspStats::kYHistogramSize - blackLevelHistIdx; | ||
const unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount; | ||
const unsigned int yHistValsPerBinMod = | ||
histogramSize / (histogramSize % kExposureBinsCount + 1); | ||
int exposureBins[kExposureBinsCount] = {}; | ||
unsigned int denom = 0; | ||
unsigned int num = 0; | ||
|
||
for (unsigned int i = 0; i < histogramSize; i++) { | ||
unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin; | ||
exposureBins[idx] += histogram[blackLevelHistIdx + i]; | ||
} | ||
|
||
for (unsigned int i = 0; i < kExposureBinsCount; i++) { | ||
LOG(IPASoftExposure, Debug) << i << ": " << exposureBins[i]; | ||
denom += exposureBins[i]; | ||
num += exposureBins[i] * (i + 1); | ||
} | ||
|
||
float exposureMSV = (denom == 0 ? 0 : static_cast<float>(num) / denom); | ||
updateExposure(context, exposureMSV); | ||
} | ||
|
||
REGISTER_IPA_ALGORITHM(Agc, "Agc") | ||
|
||
} /* namespace ipa::soft::algorithms */ | ||
|
||
} /* namespace libcamera */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* SPDX-License-Identifier: LGPL-2.1-or-later */ | ||
/* | ||
* Copyright (C) 2024, Red Hat Inc. | ||
* | ||
* Exposure and gain | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "algorithm.h" | ||
|
||
namespace libcamera { | ||
|
||
namespace ipa::soft::algorithms { | ||
|
||
class Agc : public Algorithm | ||
{ | ||
public: | ||
Agc(); | ||
~Agc() = default; | ||
|
||
void process(IPAContext &context, const uint32_t frame, | ||
IPAFrameContext &frameContext, | ||
const SwIspStats *stats, | ||
ControlList &metadata) override; | ||
|
||
private: | ||
void updateExposure(IPAContext &context, double exposureMSV); | ||
}; | ||
|
||
} /* namespace ipa::soft::algorithms */ | ||
|
||
} /* namespace libcamera */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
soft_simple_ipa_algorithms = files([ | ||
'awb.cpp', | ||
'agc.cpp', | ||
'blc.cpp', | ||
'lut.cpp', | ||
]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,5 @@ algorithms: | |
- BlackLevel: | ||
- Awb: | ||
- Lut: | ||
- Agc: | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.