summaryrefslogtreecommitdiff
path: root/src/ipa/simple
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipa/simple')
-rw-r--r--src/ipa/simple/black_level.cpp4
-rw-r--r--src/ipa/simple/black_level.h7
-rw-r--r--src/ipa/simple/meson.build5
-rw-r--r--src/ipa/simple/soft_simple.cpp79
4 files changed, 68 insertions, 27 deletions
diff --git a/src/ipa/simple/black_level.cpp b/src/ipa/simple/black_level.cpp
index c7e8d8b7..cc490eb5 100644
--- a/src/ipa/simple/black_level.cpp
+++ b/src/ipa/simple/black_level.cpp
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2024, Red Hat Inc.
*
- * black_level.cpp - black level handling
+ * black level handling
*/
#include "black_level.h"
@@ -43,7 +43,7 @@ BlackLevel::BlackLevel()
* \return The black level, in the range from 0 (minimum) to 255 (maximum).
* If the black level couldn't be determined yet, return 0.
*/
-unsigned int BlackLevel::get() const
+uint8_t BlackLevel::get() const
{
return blackLevelSet_ ? blackLevel_ : 0;
}
diff --git a/src/ipa/simple/black_level.h b/src/ipa/simple/black_level.h
index 7e37757e..5e032f9f 100644
--- a/src/ipa/simple/black_level.h
+++ b/src/ipa/simple/black_level.h
@@ -2,12 +2,13 @@
/*
* Copyright (C) 2024, Red Hat Inc.
*
- * black_level.h - black level handling
+ * black level handling
*/
#pragma once
#include <array>
+#include <stdint.h>
#include "libcamera/internal/software_isp/swisp_stats.h"
@@ -17,11 +18,11 @@ class BlackLevel
{
public:
BlackLevel();
- unsigned int get() const;
+ uint8_t get() const;
void update(SwIspStats::Histogram &yHistogram);
private:
- unsigned int blackLevel_;
+ uint8_t blackLevel_;
bool blackLevelSet_;
};
diff --git a/src/ipa/simple/meson.build b/src/ipa/simple/meson.build
index 44b5f1d7..33d1c96a 100644
--- a/src/ipa/simple/meson.build
+++ b/src/ipa/simple/meson.build
@@ -10,9 +10,8 @@ soft_simple_sources = files([
mod = shared_module(ipa_name,
[soft_simple_sources, libcamera_generated_ipa_headers],
name_prefix : '',
- include_directories : [ipa_includes, libipa_includes],
- dependencies : libcamera_private,
- link_with : libipa,
+ include_directories : [ipa_includes],
+ dependencies : [libcamera_private, libipa_dep],
install : true,
install_dir : ipa_install_dir)
diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp
index b9fb58b5..b7746ce0 100644
--- a/src/ipa/simple/soft_simple.cpp
+++ b/src/ipa/simple/soft_simple.cpp
@@ -2,9 +2,12 @@
/*
* Copyright (C) 2023, Linaro Ltd
*
- * soft_simple.cpp - Simple Software Image Processing Algorithm module
+ * Simple Software Image Processing Algorithm module
*/
+#include <cmath>
+#include <numeric>
+#include <stdint.h>
#include <sys/mman.h>
#include <linux/v4l2-controls.h>
@@ -82,6 +85,10 @@ private:
ControlInfoMap sensorInfoMap_;
BlackLevel blackLevel_;
+ static constexpr unsigned int kGammaLookupSize = 1024;
+ std::array<uint8_t, kGammaLookupSize> gammaTable_;
+ int lastBlackLevel_ = -1;
+
int32_t exposureMin_, exposureMax_;
int32_t exposure_;
double againMin_, againMax_, againMinStep_;
@@ -240,27 +247,61 @@ void IPASoftSimple::stop()
void IPASoftSimple::processStats(const ControlList &sensorControls)
{
+ SwIspStats::Histogram histogram = stats_->yHistogram;
+ if (ignoreUpdates_ > 0)
+ blackLevel_.update(histogram);
+ const uint8_t blackLevel = blackLevel_.get();
+
+ /*
+ * Black level must be subtracted to get the correct AWB ratios, they
+ * would be off if they were computed from the whole brightness range
+ * rather than from the sensor range.
+ */
+ const uint64_t nPixels = std::accumulate(
+ histogram.begin(), histogram.end(), 0);
+ const uint64_t offset = blackLevel * nPixels;
+ const uint64_t sumR = stats_->sumR_ - offset / 4;
+ const uint64_t sumG = stats_->sumG_ - offset / 2;
+ const uint64_t sumB = stats_->sumB_ - offset / 4;
+
/*
* Calculate red and blue gains for AWB.
* Clamp max gain at 4.0, this also avoids 0 division.
+ * Gain: 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.
*/
- if (stats_->sumR_ <= stats_->sumG_ / 4)
- params_->gainR = 1024;
- else
- params_->gainR = 256 * stats_->sumG_ / stats_->sumR_;
+ const unsigned int gainR = sumR <= sumG / 4 ? 1024 : 256 * sumG / sumR;
+ const unsigned int gainB = sumB <= sumG / 4 ? 1024 : 256 * sumG / sumB;
+ /* Green gain and gamma values are fixed */
+ constexpr unsigned int gainG = 256;
+
+ /* Update the gamma table if needed */
+ if (blackLevel != lastBlackLevel_) {
+ constexpr float gamma = 0.5;
+ const unsigned int blackIndex = blackLevel * kGammaLookupSize / 256;
+ std::fill(gammaTable_.begin(), gammaTable_.begin() + blackIndex, 0);
+ const float divisor = kGammaLookupSize - blackIndex - 1.0;
+ for (unsigned int i = blackIndex; i < kGammaLookupSize; i++)
+ gammaTable_[i] = UINT8_MAX *
+ std::pow((i - blackIndex) / divisor, gamma);
+
+ lastBlackLevel_ = blackLevel;
+ }
- if (stats_->sumB_ <= stats_->sumG_ / 4)
- params_->gainB = 1024;
- else
- params_->gainB = 256 * stats_->sumG_ / stats_->sumB_;
+ for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {
+ constexpr unsigned int div =
+ DebayerParams::kRGBLookupSize * 256 / kGammaLookupSize;
+ unsigned int idx;
- /* Green gain and gamma values are fixed */
- params_->gainG = 256;
- params_->gamma = 0.5;
+ /* Apply gamma after gain! */
+ idx = std::min({ i * gainR / div, (kGammaLookupSize - 1) });
+ params_->red[i] = gammaTable_[idx];
- if (ignoreUpdates_ > 0)
- blackLevel_.update(stats_->yHistogram);
- params_->blackLevel = blackLevel_.get();
+ idx = std::min({ i * gainG / div, (kGammaLookupSize - 1) });
+ params_->green[i] = gammaTable_[idx];
+
+ idx = std::min({ i * gainB / div, (kGammaLookupSize - 1) });
+ params_->blue[i] = gammaTable_[idx];
+ }
setIspParams.emit();
@@ -281,7 +322,7 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)
* https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf
*/
const unsigned int blackLevelHistIdx =
- params_->blackLevel / (256 / SwIspStats::kYHistogramSize);
+ blackLevel / (256 / SwIspStats::kYHistogramSize);
const unsigned int histogramSize =
SwIspStats::kYHistogramSize - blackLevelHistIdx;
const unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount;
@@ -329,8 +370,8 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)
LOG(IPASoft, Debug) << "exposureMSV " << exposureMSV
<< " exp " << exposure_ << " again " << again_
- << " gain R/B " << params_->gainR << "/" << params_->gainB
- << " black level " << params_->blackLevel;
+ << " gain R/B " << gainR << "/" << gainB
+ << " black level " << static_cast<unsigned int>(blackLevel);
}
void IPASoftSimple::updateExposure(double exposureMSV)
@@ -389,7 +430,7 @@ extern "C" {
const struct IPAModuleInfo ipaModuleInfo = {
IPA_MODULE_API_VERSION,
0,
- "SimplePipelineHandler",
+ "simple",
"simple",
};