diff options
Diffstat (limited to 'users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch')
-rw-r--r-- | users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch | 396 |
1 files changed, 0 insertions, 396 deletions
diff --git a/users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch b/users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch deleted file mode 100644 index c746b74dba67..000000000000 --- a/users/flokli/ipu6-softisp/libcamera/0018-libcamera-software_isp-Apply-black-level-compensatio.patch +++ /dev/null @@ -1,396 +0,0 @@ -From bb608d177135d74e3c98b8a61fb459ebe254bca5 Mon Sep 17 00:00:00 2001 -From: Milan Zamazal <mzamazal@redhat.com> -Date: Mon, 11 Mar 2024 15:15:21 +0100 -Subject: [PATCH 18/21] libcamera: software_isp: Apply black level compensation - -Black may not be represented as 0 pixel value for given hardware, it may be -higher. If this is not compensated then various problems may occur such as low -contrast or suboptimal exposure. - -The black pixel value can be either retrieved from a tuning file for the given -hardware, or automatically on fly. The former is the right and correct method, -while the latter can be used when a tuning file is not available for the given -hardware. Since there is currently no support for tuning files in software ISP, -the automatic, hardware independent way, is always used. Support for tuning -files should be added in future but it will require more work than this patch. - -The patch looks at the image histogram and assumes that black starts when pixel -values start occurring on the left. A certain amount of the darkest pixels is -ignored; it doesn't matter whether they represent various kinds of noise or are -real, they are better to omit in any case to make the image looking better. It -also doesn't matter whether the darkest pixels occur around the supposed black -level or are spread between 0 and the black level, the difference is not -important. - -An arbitrary threshold of 2% darkest pixels is applied; there is no magic about -that value. - -The patch assumes that the black values for different colors are the same and -doesn't attempt any other non-primitive enhancements. It cannot completely -replace tuning files and simplicity, while providing visible benefit, is its -goal. Anything more sophisticated is left for future patches. - -A possible cheap enhancement, if needed, could be setting exposure + gain to -minimum values temporarily, before setting the black level. In theory, the -black level should be fixed but it may not be reached in all images. For this -reason, the patch updates black level only if the observed value is lower than -the current one; it should be never increased. - -The purpose of the patch is to compensate for hardware properties. General -image contrast enhancements are out of scope of this patch. - -Stats are still gathered as an uncorrected histogram, to avoid any confusion and -to represent the raw image data. Exposure must be determined after the black -level correction -- it has no influence on the sub-black area and must be -correct after applying the black level correction. The granularity of the -histogram is increased from 16 to 64 to provide a better precision (there is no -theory behind either of those numbers). - -Reviewed-by: Hans de Goede <hdegoede@redhat.com> -Signed-off-by: Milan Zamazal <mzamazal@redhat.com> -Signed-off-by: Hans de Goede <hdegoede@redhat.com> ---- - .../internal/software_isp/debayer_params.h | 4 + - .../internal/software_isp/swisp_stats.h | 10 ++- - src/ipa/simple/black_level.cpp | 86 +++++++++++++++++++ - src/ipa/simple/black_level.h | 28 ++++++ - src/ipa/simple/meson.build | 7 +- - src/ipa/simple/soft_simple.cpp | 28 ++++-- - src/libcamera/software_isp/debayer_cpu.cpp | 13 ++- - src/libcamera/software_isp/debayer_cpu.h | 1 + - src/libcamera/software_isp/software_isp.cpp | 2 +- - 9 files changed, 162 insertions(+), 17 deletions(-) - create mode 100644 src/ipa/simple/black_level.cpp - create mode 100644 src/ipa/simple/black_level.h - -diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h -index 98965fa1..5e38e08b 100644 ---- a/include/libcamera/internal/software_isp/debayer_params.h -+++ b/include/libcamera/internal/software_isp/debayer_params.h -@@ -43,6 +43,10 @@ struct DebayerParams { - * \brief Gamma correction, 1.0 is no correction - */ - float gamma; -+ /** -+ * \brief Level of the black point, 0..255, 0 is no correction. -+ */ -+ unsigned int blackLevel; - }; - - } /* namespace libcamera */ -diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h -index afe42c9a..25cd5abd 100644 ---- a/include/libcamera/internal/software_isp/swisp_stats.h -+++ b/include/libcamera/internal/software_isp/swisp_stats.h -@@ -7,6 +7,8 @@ - - #pragma once - -+#include <array> -+ - namespace libcamera { - - /** -@@ -28,11 +30,15 @@ struct SwIspStats { - /** - * \brief Number of bins in the yHistogram. - */ -- static constexpr unsigned int kYHistogramSize = 16; -+ static constexpr unsigned int kYHistogramSize = 64; -+ /** -+ * \brief Type of the histogram. -+ */ -+ using histogram = std::array<unsigned int, kYHistogramSize>; - /** - * \brief A histogram of luminance values. - */ -- std::array<unsigned int, kYHistogramSize> yHistogram; -+ histogram yHistogram; - }; - - } /* namespace libcamera */ -diff --git a/src/ipa/simple/black_level.cpp b/src/ipa/simple/black_level.cpp -new file mode 100644 -index 00000000..8d52201b ---- /dev/null -+++ b/src/ipa/simple/black_level.cpp -@@ -0,0 +1,86 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2024, Red Hat Inc. -+ * -+ * black_level.cpp - black level handling -+ */ -+ -+#include "black_level.h" -+ -+#include <numeric> -+ -+#include <libcamera/base/log.h> -+ -+namespace libcamera { -+ -+LOG_DEFINE_CATEGORY(IPASoftBL) -+ -+/** -+ * \class BlackLevel -+ * \brief Object providing black point level for software ISP -+ * -+ * Black level can be provided in hardware tuning files or, if no tuning file is -+ * available for the given hardware, guessed automatically, with less accuracy. -+ * As tuning files are not yet implemented for software ISP, BlackLevel -+ * currently provides only guessed black levels. -+ * -+ * This class serves for tracking black level as a property of the underlying -+ * hardware, not as means of enhancing a particular scene or image. -+ * -+ * The class is supposed to be instantiated for the given camera stream. -+ * The black level can be retrieved using BlackLevel::get() method. It is -+ * initially 0 and may change when updated using BlackLevel::update() method. -+ */ -+ -+BlackLevel::BlackLevel() -+ : blackLevel_(255), blackLevelSet_(false) -+{ -+} -+ -+/** -+ * \brief Return the current black level -+ * -+ * \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 -+{ -+ return blackLevelSet_ ? blackLevel_ : 0; -+} -+ -+/** -+ * \brief Update black level from the provided histogram -+ * \param[in] yHistogram The histogram to be used for updating black level -+ * -+ * The black level is property of the given hardware, not image. It is updated -+ * only if it has not been yet set or if it is lower than the lowest value seen -+ * so far. -+ */ -+void BlackLevel::update(SwIspStats::histogram &yHistogram) -+{ -+ // The constant is selected to be "good enough", not overly conservative or -+ // aggressive. There is no magic about the given value. -+ constexpr float ignoredPercentage_ = 0.02; -+ const unsigned int total = -+ std::accumulate(begin(yHistogram), end(yHistogram), 0); -+ const unsigned int pixelThreshold = ignoredPercentage_ * total; -+ const unsigned int currentBlackIdx = -+ blackLevel_ / (256 / SwIspStats::kYHistogramSize); -+ -+ for (unsigned int i = 0, seen = 0; -+ i < currentBlackIdx && i < SwIspStats::kYHistogramSize; -+ i++) { -+ seen += yHistogram[i]; -+ if (seen >= pixelThreshold) { -+ blackLevel_ = i * (256 / SwIspStats::kYHistogramSize); -+ blackLevelSet_ = true; -+ LOG(IPASoftBL, Debug) -+ << "Auto-set black level: " -+ << i << "/" << SwIspStats::kYHistogramSize -+ << " (" << 100 * (seen - yHistogram[i]) / total << "% below, " -+ << 100 * seen / total << "% at or below)"; -+ break; -+ } -+ }; -+} -+} // namespace libcamera -diff --git a/src/ipa/simple/black_level.h b/src/ipa/simple/black_level.h -new file mode 100644 -index 00000000..b3785db0 ---- /dev/null -+++ b/src/ipa/simple/black_level.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: LGPL-2.1-or-later */ -+/* -+ * Copyright (C) 2024, Red Hat Inc. -+ * -+ * black_level.h - black level handling -+ */ -+ -+#pragma once -+ -+#include <array> -+ -+#include "libcamera/internal/software_isp/swisp_stats.h" -+ -+namespace libcamera { -+ -+class BlackLevel -+{ -+public: -+ BlackLevel(); -+ unsigned int get() const; -+ void update(std::array<unsigned int, SwIspStats::kYHistogramSize> &yHistogram); -+ -+private: -+ unsigned int blackLevel_; -+ bool blackLevelSet_; -+}; -+ -+} // namespace libcamera -diff --git a/src/ipa/simple/meson.build b/src/ipa/simple/meson.build -index 3e863db7..44b5f1d7 100644 ---- a/src/ipa/simple/meson.build -+++ b/src/ipa/simple/meson.build -@@ -2,8 +2,13 @@ - - ipa_name = 'ipa_soft_simple' - -+soft_simple_sources = files([ -+ 'soft_simple.cpp', -+ 'black_level.cpp', -+]) -+ - mod = shared_module(ipa_name, -- ['soft_simple.cpp', libcamera_generated_ipa_headers], -+ [soft_simple_sources, libcamera_generated_ipa_headers], - name_prefix : '', - include_directories : [ipa_includes, libipa_includes], - dependencies : libcamera_private, -diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp -index 312df4ba..ac027568 100644 ---- a/src/ipa/simple/soft_simple.cpp -+++ b/src/ipa/simple/soft_simple.cpp -@@ -22,6 +22,8 @@ - #include "libcamera/internal/software_isp/debayer_params.h" - #include "libcamera/internal/software_isp/swisp_stats.h" - -+#include "black_level.h" -+ - namespace libcamera { - - LOG_DEFINE_CATEGORY(IPASoft) -@@ -33,7 +35,8 @@ class IPASoftSimple : public ipa::soft::IPASoftInterface - public: - IPASoftSimple() - : params_(static_cast<DebayerParams *>(MAP_FAILED)), -- stats_(static_cast<SwIspStats *>(MAP_FAILED)), ignore_updates_(0) -+ stats_(static_cast<SwIspStats *>(MAP_FAILED)), -+ blackLevel_(BlackLevel()), ignore_updates_(0) - { - } - -@@ -63,6 +66,7 @@ private: - SharedFD fdParams_; - DebayerParams *params_; - SwIspStats *stats_; -+ BlackLevel blackLevel_; - - int32_t exposure_min_, exposure_max_; - int32_t again_min_, again_max_; -@@ -196,6 +200,10 @@ void IPASoftSimple::processStats(const ControlList &sensorControls) - params_->gainG = 256; - params_->gamma = 0.5; - -+ if (ignore_updates_ > 0) -+ blackLevel_.update(stats_->yHistogram); -+ params_->blackLevel = blackLevel_.get(); -+ - setIspParams.emit(0); - - /* -@@ -211,18 +219,19 @@ void IPASoftSimple::processStats(const ControlList &sensorControls) - * Calculate Mean Sample Value (MSV) according to formula from: - * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf - */ -- constexpr unsigned int yHistValsPerBin = -- SwIspStats::kYHistogramSize / kExposureBinsCount; -- constexpr unsigned int yHistValsPerBinMod = -- SwIspStats::kYHistogramSize / -- (SwIspStats::kYHistogramSize % kExposureBinsCount + 1); -+ const unsigned int blackLevelHistIdx = -+ params_->blackLevel / (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 < SwIspStats::kYHistogramSize; i++) { -+ for (unsigned int i = 0; i < histogramSize; i++) { - unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin; -- ExposureBins[idx] += stats_->yHistogram[i]; -+ ExposureBins[idx] += stats_->yHistogram[blackLevelHistIdx + i]; - } - - for (unsigned int i = 0; i < kExposureBinsCount; i++) { -@@ -256,7 +265,8 @@ void IPASoftSimple::processStats(const ControlList &sensorControls) - - LOG(IPASoft, Debug) << "exposureMSV " << exposureMSV - << " exp " << exposure_ << " again " << again_ -- << " gain R/B " << params_->gainR << "/" << params_->gainB; -+ << " gain R/B " << params_->gainR << "/" << params_->gainB -+ << " black level " << params_->blackLevel; - } - - void IPASoftSimple::updateExposure(double exposureMSV) -diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp -index a1692693..3be3cdfe 100644 ---- a/src/libcamera/software_isp/debayer_cpu.cpp -+++ b/src/libcamera/software_isp/debayer_cpu.cpp -@@ -35,7 +35,7 @@ namespace libcamera { - * \param[in] stats Pointer to the stats object to use. - */ - DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats) -- : stats_(std::move(stats)), gamma_correction_(1.0) -+ : stats_(std::move(stats)), gamma_correction_(1.0), blackLevel_(0) - { - #ifdef __x86_64__ - enableInputMemcpy_ = false; -@@ -683,11 +683,16 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams - } - - /* Apply DebayerParams */ -- if (params.gamma != gamma_correction_) { -- for (unsigned int i = 0; i < kGammaLookupSize; i++) -- gamma_[i] = UINT8_MAX * powf(i / (kGammaLookupSize - 1.0), params.gamma); -+ if (params.gamma != gamma_correction_ || params.blackLevel != blackLevel_) { -+ const unsigned int blackIndex = -+ params.blackLevel * kGammaLookupSize / 256; -+ std::fill(gamma_.begin(), gamma_.begin() + blackIndex, 0); -+ const float divisor = kGammaLookupSize - blackIndex - 1.0; -+ for (unsigned int i = blackIndex; i < kGammaLookupSize; i++) -+ gamma_[i] = UINT8_MAX * powf((i - blackIndex) / divisor, params.gamma); - - gamma_correction_ = params.gamma; -+ blackLevel_ = params.blackLevel; - } - - if (swapRedBlueGains_) -diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h -index 5f44fc65..ea02f909 100644 ---- a/src/libcamera/software_isp/debayer_cpu.h -+++ b/src/libcamera/software_isp/debayer_cpu.h -@@ -147,6 +147,7 @@ private: - bool enableInputMemcpy_; - bool swapRedBlueGains_; - float gamma_correction_; -+ unsigned int blackLevel_; - unsigned int measuredFrames_; - int64_t frameProcessTime_; - /* Skip 30 frames for things to stabilize then measure 30 frames */ -diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp -index 388b4496..9b49be41 100644 ---- a/src/libcamera/software_isp/software_isp.cpp -+++ b/src/libcamera/software_isp/software_isp.cpp -@@ -64,7 +64,7 @@ LOG_DEFINE_CATEGORY(SoftwareIsp) - */ - SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls) - : debayer_(nullptr), -- debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f }, -+ debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f, 0 }, - dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System) - { - if (!dmaHeap_.isValid()) { --- -2.43.2 - |