From patchwork Mon Aug 4 11:11:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24045 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 88946BDCC1 for ; Mon, 4 Aug 2025 11:11:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9FB2C6921D; Mon, 4 Aug 2025 13:11:24 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="toAQWUHe"; dkim-atps=neutral Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 641896920D for ; Mon, 4 Aug 2025 13:11:23 +0200 (CEST) Received: by mail-wr1-x42f.google.com with SMTP id ffacd0b85a97d-3b8d0f1fb49so2097958f8f.2 for ; Mon, 04 Aug 2025 04:11:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1754305882; x=1754910682; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=71DARSHGgyE699X1OTM5rrKd2lu2B9IbK9KdxuSzV0w=; b=toAQWUHeBckmKxMvF4AHISvtByBU4wLCWzGjlyqNNy4l2f/42q8j7AKc3c6PoZkMJu 5Hn5TxwCA/RZeJOXGfSBQS6pNKwQOgDTQbhF0cHl7xGT7lDbEMFsCYbPjiW86rY/BtCH qm80CHBy7p0TCrO1r0cP/xVPPpnM8+iq9BBGOSI0dyvz1TkxFyxofTHKxHQzyum1LVrC E2TzTXqQTw+RvnDmkHscxFnEuyffoHrzFGZYm4Lyg0bobmHf9siaugGZ6CrOAUiTx4wY elQvTuYxTiclgOHD3yfgFI0Y6K1BKNwLOuZ0mwdEML1X5ivUSnw7f7Mpp+FAP9Y96XP8 ShEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1754305882; x=1754910682; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=71DARSHGgyE699X1OTM5rrKd2lu2B9IbK9KdxuSzV0w=; b=vOqj+qnyePcO2eHiTJK8IR1oxKYXzKBXqEk1rITo+Y1eX/e6/SCWyadcODZyfcyr6T IbJRsNqVBBvMHgCcLzh9X7XKvHRIenFpPhW6Ypd98J7M6xemcq2IeYxl77JH3WPhSY1c hc5j8litKvlMb86tPaiU9sWFtr5kUA3cz7nJzYaFA2MbxEnjfByzlaIp9nTyjCTgkmfY eimKqEQ0RK5z7rhP8gRKsn6QyXJJxsyTdDIzJAAmkP9NgsNQIJSWwml4R9JMAmbfitpE ek71zfjzJQkUKShnIoLEzwUcK4jXhxBQ0WHMYO34XlFGVB19X5JE7M74SLI7QVjichPT aQYg== X-Gm-Message-State: AOJu0Yys+Srexogsc5ZuZhC/cIAIQrRtrtcL/0zIM94gtHIp/5AGqnoQ 2rKodJtihWcVHV1R1Pvj7ctrEaes2c5x4TkkbVtA2KUaD5q7c6cmIYOk865ivpvoXlZghW6+vw/ ab3Ju1F8= X-Gm-Gg: ASbGncsUWe7ZT/KMhMSGPTkSudm0U2Xk4DtfbpLJZzVqqj99RrPKKv9QB28VcfL8uQp Og33uMPGesKBQJJsT22WsXv2hy+ByPmkMA7bR61zPQSIWv+8PLMsbvzTitgiLTq6bfR3aUQNj7i 8pFOOrdClCV5UTja1bQL+KKR+u/QSldrk76RxnVCGP8Ed/1BVvsZQ9KJd2Bo4oRpIBx9AKPQckQ I6I3uHPCEP7VCzTIsRAHbMe2pKyORstoz/OvsZfamzUEoUa1A20wW4HijhDTnnyqdZbyqsgIMXZ Q4LlBeXcXVkEuVHvzVkkMAoE/khIrvF0xUiwZw1NsweF0RCVL26dB3hC5J/69bnOrhZcPGKD2f6 5R8EvmaKzoJ8EwWUeIymgNGhbWqHpRnt8xjqG33EgzJ2RYzn2GKfDig== X-Google-Smtp-Source: AGHT+IFNtjtpJQzL6QrjBfS020hhFpT+9E2Ujr3hx0MznZio9RO0w0ICbdpuijybvLi8oaxu0eJdrg== X-Received: by 2002:a5d:5d10:0:b0:3a4:fbaf:749e with SMTP id ffacd0b85a97d-3b8d94c2141mr6211953f8f.49.1754305882346; Mon, 04 Aug 2025 04:11:22 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-458a7c91c0esm143148155e9.11.2025.08.04.04.11.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Aug 2025 04:11:21 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [PATCH] ipa: rpi: ccm: Implement "manual" CCM mode Date: Mon, 4 Aug 2025 12:11:18 +0100 Message-Id: <20250804111118.10190-1-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.39.5 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" The CCM algorithm will now let an explicit colour matrix be set when AWB is in manual mode. Signed-off-by: David Plowman --- src/ipa/rpi/common/ipa_base.cpp | 67 +++++++++++++++++++++++--- src/ipa/rpi/common/ipa_base.h | 2 + src/ipa/rpi/controller/ccm_algorithm.h | 6 +++ src/ipa/rpi/controller/rpi/ccm.cpp | 21 +++++++- src/ipa/rpi/controller/rpi/ccm.h | 5 +- 5 files changed, 92 insertions(+), 9 deletions(-) diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp index ce2343e9..3153bee6 100644 --- a/src/ipa/rpi/common/ipa_base.cpp +++ b/src/ipa/rpi/common/ipa_base.cpp @@ -94,6 +94,7 @@ const ControlInfoMap::Map ipaColourControls{ { &controls::AwbEnable, ControlInfo(false, true) }, { &controls::AwbMode, ControlInfo(controls::AwbModeValues) }, { &controls::ColourGains, ControlInfo(0.0f, 32.0f) }, + { &controls::ColourCorrectionMatrix, ControlInfo(0.0f, 8.0f) }, { &controls::ColourTemperature, ControlInfo(100, 100000) }, { &controls::Saturation, ControlInfo(0.0f, 32.0f, 1.0f) }, }; @@ -126,7 +127,7 @@ namespace ipa::RPi { IpaBase::IpaBase() : controller_(), frameLengths_(FrameLengthsQueueSize, 0s), statsMetadataOutput_(false), stitchSwapBuffers_(false), frameCount_(0), mistrustCount_(0), lastRunTimestamp_(0), - firstStart_(true), flickerState_({ 0, 0s }) + firstStart_(true), flickerState_({ 0, 0s }), awbEnabled_(true) { } @@ -1049,13 +1050,21 @@ void IpaBase::applyControls(const ControlList &controls) break; } - if (ctrl.second.get() == false) + awbEnabled_ = ctrl.second.get(); + + if (!awbEnabled_) awb->disableAuto(); - else + else { awb->enableAuto(); - libcameraMetadata_.set(controls::AwbEnable, - ctrl.second.get()); + /* If AWB is running, the CCM must go back to auto as well. */ + RPiController::CcmAlgorithm *ccm = dynamic_cast( + controller_.getAlgorithm("ccm")); + if (ccm) + ccm->enableAuto(); + } + + libcameraMetadata_.set(controls::AwbEnable, awbEnabled_); break; } @@ -1098,10 +1107,20 @@ void IpaBase::applyControls(const ControlList &controls) } awb->setManualGains(gains[0], gains[1]); - if (gains[0] != 0.0f && gains[1] != 0.0f) + if (gains[0] != 0.0f && gains[1] != 0.0f) { /* A gain of 0.0f will switch back to auto mode. */ libcameraMetadata_.set(controls::ColourGains, { gains[0], gains[1] }); + awbEnabled_ = false; /* puts AWB into manual mode */ + } else { + awbEnabled_ = true; /* puts AWB into auto mode */ + + /* If AWB is running, the CCM must go back to auto as well. */ + RPiController::CcmAlgorithm *ccm = dynamic_cast( + controller_.getAlgorithm("ccm")); + if (ccm) + ccm->enableAuto(); + } break; } @@ -1120,10 +1139,46 @@ void IpaBase::applyControls(const ControlList &controls) } awb->setColourTemperature(temperatureK); + awbEnabled_ = false; /* this puts AWB into manual mode */ /* This metadata will get reported back automatically. */ break; } + case controls::COLOUR_CORRECTION_MATRIX: { + if (monoSensor_) + break; + + auto floats = ctrl.second.get>(); + RPiController::CcmAlgorithm *ccm = dynamic_cast( + controller_.getAlgorithm("ccm")); + if (!ccm) { + LOG(IPARPI, Warning) + << "Could not set COLOUR_CORRECTION_MATRIX - no CCM algorithm"; + break; + } + + /* We are guaranteed this control contains 9 values. Nevertheless: */ + assert(floats.size() == 9); + + Matrix matrix; + for (std::size_t i = 0; i < 3; ++i) + for (std::size_t j = 0; j < 3; ++j) + matrix[i][j] = static_cast(floats[i * 3 + j]); + + ccm->setCcm(matrix); + + /* + * But if AWB is running, go back to auto mode. The CCM gets remembered, + * which avoids the race between setting the CCM and disabling AWB in + * the same set of controls. + */ + if (awbEnabled_) + ccm->enableAuto(); + + /* This metadata will be reported back automatically. */ + break; + } + case controls::BRIGHTNESS: { RPiController::ContrastAlgorithm *contrast = dynamic_cast( controller_.getAlgorithm("contrast")); diff --git a/src/ipa/rpi/common/ipa_base.h b/src/ipa/rpi/common/ipa_base.h index e2f6e330..5348f2ea 100644 --- a/src/ipa/rpi/common/ipa_base.h +++ b/src/ipa/rpi/common/ipa_base.h @@ -140,6 +140,8 @@ private: int32_t mode; utils::Duration manualPeriod; } flickerState_; + + bool awbEnabled_; }; } /* namespace ipa::RPi */ diff --git a/src/ipa/rpi/controller/ccm_algorithm.h b/src/ipa/rpi/controller/ccm_algorithm.h index 6678ba75..785c408a 100644 --- a/src/ipa/rpi/controller/ccm_algorithm.h +++ b/src/ipa/rpi/controller/ccm_algorithm.h @@ -6,16 +6,22 @@ */ #pragma once +#include "libcamera/internal/matrix.h" + #include "algorithm.h" namespace RPiController { +using Matrix3x3 = libcamera::Matrix; + class CcmAlgorithm : public Algorithm { public: CcmAlgorithm(Controller *controller) : Algorithm(controller) {} /* A CCM algorithm must provide the following: */ + virtual void enableAuto() = 0; virtual void setSaturation(double saturation) = 0; + virtual void setCcm(Matrix3x3 const &matrix) = 0; }; } /* namespace RPiController */ diff --git a/src/ipa/rpi/controller/rpi/ccm.cpp b/src/ipa/rpi/controller/rpi/ccm.cpp index 8607f152..25bcea2d 100644 --- a/src/ipa/rpi/controller/rpi/ccm.cpp +++ b/src/ipa/rpi/controller/rpi/ccm.cpp @@ -32,7 +32,7 @@ LOG_DEFINE_CATEGORY(RPiCcm) using Matrix3x3 = Matrix; Ccm::Ccm(Controller *controller) - : CcmAlgorithm(controller), saturation_(1.0) {} + : CcmAlgorithm(controller), enableAuto_(true), saturation_(1.0) {} char const *Ccm::name() const { @@ -78,11 +78,22 @@ int Ccm::read(const libcamera::YamlObject ¶ms) return 0; } +void Ccm::enableAuto() +{ + enableAuto_ = true; +} + void Ccm::setSaturation(double saturation) { saturation_ = saturation; } +void Ccm::setCcm(Matrix3x3 const &matrix) +{ + enableAuto_ = false; + manualCcm_ = matrix; +} + void Ccm::initialise() { } @@ -151,7 +162,13 @@ void Ccm::prepare(Metadata *imageMetadata) LOG(RPiCcm, Warning) << "no colour temperature found"; if (!luxOk) LOG(RPiCcm, Warning) << "no lux value found"; - Matrix3x3 ccm = calculateCcm(config_.ccms, awb.temperatureK); + + Matrix3x3 ccm; + if (enableAuto_) + ccm = calculateCcm(config_.ccms, awb.temperatureK); + else + ccm = manualCcm_; + double saturation = saturation_; struct CcmStatus ccmStatus; ccmStatus.saturation = saturation; diff --git a/src/ipa/rpi/controller/rpi/ccm.h b/src/ipa/rpi/controller/rpi/ccm.h index c05dbb17..70f28ed3 100644 --- a/src/ipa/rpi/controller/rpi/ccm.h +++ b/src/ipa/rpi/controller/rpi/ccm.h @@ -8,7 +8,6 @@ #include -#include "libcamera/internal/matrix.h" #include #include "../ccm_algorithm.h" @@ -33,13 +32,17 @@ public: Ccm(Controller *controller = NULL); char const *name() const override; int read(const libcamera::YamlObject ¶ms) override; + void enableAuto() override; void setSaturation(double saturation) override; + void setCcm(Matrix3x3 const &matrix) override; void initialise() override; void prepare(Metadata *imageMetadata) override; private: CcmConfig config_; + bool enableAuto_; double saturation_; + Matrix3x3 manualCcm_; }; } /* namespace RPiController */