diff options
Diffstat (limited to 'src/ipa/simple')
-rw-r--r-- | src/ipa/simple/black_level.cpp | 4 | ||||
-rw-r--r-- | src/ipa/simple/black_level.h | 7 | ||||
-rw-r--r-- | src/ipa/simple/meson.build | 5 | ||||
-rw-r--r-- | src/ipa/simple/soft_simple.cpp | 79 |
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", }; |