From patchwork Fri Sep 13 07:57:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 21258 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 7EEF2C324C for ; Fri, 13 Sep 2024 07:58:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 270E76350E; Fri, 13 Sep 2024 09:58:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="eYuIyF9f"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 599C663504 for ; Fri, 13 Sep 2024 09:58:19 +0200 (CEST) Received: from ideasonboard.com (213-229-8-243.static.upcbusiness.at [213.229.8.243]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8C25A1011; Fri, 13 Sep 2024 09:57:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1726214220; bh=xJLxMRw47iu6x6DQ3E63NZqhqnC645GatEgAZzP+h7E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eYuIyF9f4fkGuYl8BVwuRvGdmMZKAuzzf79QLGJUOb/sivgWwBk9/azzOBnaGm6Bw 94XYIBYDDsBLTdxIcAbRSV75eBsBtUxJ9TiDzFzS8NfWU9GNPJ6/M6MicFi0bqZyfZ gXDpGcOcOIopR6qZgdInIuF1Nc+P/8c3vTi9S9Ss= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH v2 9/9] ipa: rkisp1: Add polynomial LSC loader Date: Fri, 13 Sep 2024 09:57:27 +0200 Message-ID: <20240913075750.35115-10-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240913075750.35115-1-stefan.klug@ideasonboard.com> References: <20240913075750.35115-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a loader that is capable to load polynomial coefficients from the tuning files. The polynoms are sampled at load time to reduce the computational overhead at runtime. Signed-off-by: Stefan Klug --- src/ipa/rkisp1/algorithms/lsc.cpp | 126 +++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 12867b8f7d0f..b0ad2234cd11 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -16,6 +16,7 @@ #include "libcamera/internal/yaml_parser.h" +#include "libipa/lsc_polynomial.h" #include "linux/rkisp1-config.h" /** @@ -70,6 +71,123 @@ namespace ipa::rkisp1::algorithms { LOG_DEFINE_CATEGORY(RkISP1Lsc) +class LscPolynomialLoader +{ +public: + LscPolynomialLoader(const Size &sensorSize, + const Rectangle &cropRectangle, + const std::vector &xSizes, + const std::vector &ySizes) + : sensorSize_(sensorSize), + cropRectangle_(cropRectangle), + xSizes_(xSizes), + ySizes_(ySizes) + { + } + + int parseLscData(const YamlObject &yamlSets, + std::map &lscData) + { + const auto &sets = yamlSets.asList(); + for (const auto &yamlSet : sets) { + std::optional pr, pgr, pgb, pb; + uint32_t ct = yamlSet["ct"].get(0); + + if (lscData.count(ct)) { + LOG(RkISP1Lsc, Error) + << "Multiple sets found for " + << "color temperature " << ct; + return -EINVAL; + } + + LensShadingCorrection::Components &set = lscData[ct]; + pr = yamlSet["r"].get(); + pgr = yamlSet["gr"].get(); + pgb = yamlSet["gb"].get(); + pb = yamlSet["b"].get(); + + if (!(pr || pgr || pgb || pb)) { + LOG(RkISP1Lsc, Error) + << "Failed to parse polynomial for " + << "colour temperature " << ct; + return -EINVAL; + } + + set.ct = ct; + pr->setReferenceImageSize(sensorSize_); + pgr->setReferenceImageSize(sensorSize_); + pgb->setReferenceImageSize(sensorSize_); + pb->setReferenceImageSize(sensorSize_); + set.r = samplePolynomial(*pr); + set.gr = samplePolynomial(*pgr); + set.gb = samplePolynomial(*pgb); + set.b = samplePolynomial(*pb); + } + + if (lscData.empty()) { + LOG(RkISP1Lsc, Error) << "Failed to load any sets"; + return -EINVAL; + } + + return 0; + } + +private: + std::vector sizesListToPositions(const std::vector &sizes) + { + const int half = sizes.size(); + std::vector res(half * 2 + 1); + double x = 0.0; + + res[half] = 0.5; + for (int i = 1; i <= half; i++) { + x += sizes[half - i]; + res[half - i] = 0.5 - x; + res[half + i] = 0.5 + x; + } + + return res; + } + + std::vector samplePolynomial(const LscPolynomial &poly) + { + constexpr int k = RKISP1_CIF_ISP_LSC_SAMPLES_MAX; + + double m = poly.getM(); + double x0 = cropRectangle_.x / m; + double y0 = cropRectangle_.y / m; + double w = cropRectangle_.width / m; + double h = cropRectangle_.height / m; + std::vector res; + + assert(xSizes_.size() * 2 + 1 == k); + + res.reserve(k * k); + + std::vector xPos(sizesListToPositions(xSizes_)); + std::vector yPos(sizesListToPositions(ySizes_)); + + for (int x = 0; x < k; x++) { + for (int y = 0; y < k; y++) { + double xp = x0 + xPos[x] * w; + double yp = y0 + yPos[y] * h; + int v = static_cast( + poly.sampleAtNormalizedPixelPos(xp, yp) * + 1024); + + v = std::min(std::max(v, 1024), 4095); + res.push_back(v); + } + } + return res; + } + + Size sensorSize_; + Rectangle cropRectangle_; + const std::vector &xSizes_; + const std::vector &ySizes_; +}; + class LscClassicLoader { public: @@ -193,11 +311,17 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, std::map lscData; int res = 0; std::optional type = tuningData["type"].get(); - if (!type.has_value()) { + if (!tuningData.contains("type")) { LOG(RkISP1Lsc, Warning) << "LSC data is in classic format. " << "This will be deprecated soon."; auto loader = LscClassicLoader(); res = loader.parseLscData(yamlSets, lscData); + } else if (*type == "polynomial") { + auto loader = LscPolynomialLoader(context.sensorInfo.activeAreaSize, + context.sensorInfo.analogCrop, + xSize_, + ySize_); + res = loader.parseLscData(yamlSets, lscData); } else { LOG(RkISP1Lsc, Error) << "Unsupported LSC type '" << *type << "'"; res = -EINVAL;