From patchwork Fri Jun 20 12:42:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23609 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 529B7BDE6B for ; Fri, 20 Jun 2025 12:45:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CBD1C68DEE; Fri, 20 Jun 2025 14:45:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="da19/KMT"; dkim-atps=neutral Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AB66861535 for ; Fri, 20 Jun 2025 14:44:58 +0200 (CEST) Received: by mail-wm1-x32d.google.com with SMTP id 5b1f17b1804b1-4535fc0485dso2484525e9.0 for ; Fri, 20 Jun 2025 05:44:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423498; x=1751028298; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=frwK0qays/9gk1irCD7nqtI6enlAuzK77v7RfYNMXpU=; b=da19/KMThAlxIvb8cLv1StG1YQfuGgSas6JHMQxO9LDen7V+6o5lzbrMfZ3UrmUvN0 BtDRjjDWOSTFSItHpKCdgRsCBUKKdJ9ijjyebuQbogJy0AJcBhQnwtiw2NYJXIH4KUxq vaWlTebCHh/8PDmsqLs+QfX+fBJEIvwrXzRkOFmeogdS4Dk9kPu9L+iN4JaWzSO80kJi w/gMSjUf7jfK9mNMcFu/1zZ61iSUkHW+appJc+FpWy8hn/MoEXax+s8Lt3kjcB4DA/bc UdQRkpUYo/ijTmwL1eW45YXPZaD2VZIS6XhsauuHMmHS/UlhO2q93XnUJf8ZsTFzhwl+ SfPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423498; x=1751028298; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=frwK0qays/9gk1irCD7nqtI6enlAuzK77v7RfYNMXpU=; b=wRci9rvwBLad7WUBvHF6XS2ggsqcz399M3LxsqY5UUMVfUsr3ks2n0jAUvlXeqLE61 bvAu/Kp4kFhcj/fXuEYSO4Ny+WTGrdmcwFOnpVlzWVGNhfYFBCnNeKlr05/e2irHOxy7 9URGn+AeijVKCnblLLClp0UQIURkvJW2fWHFQdLqPv9vW1ULcwwS/ymHIBxC/en9Ak8B g1JB2/YAZZe1eA0FSiauCozGA9MUMgV/lERyT3n3tDdSMgABOm6Nb4EBGf4ApKW3rhOm bFEi8XuzJkWEgSvBYICYfDYFeJ7WT+4ajvTy7t8+pzMc61zIQzNJgo+tTvHn3lAMSJ/O eRaQ== X-Gm-Message-State: AOJu0YzSxiWUBvYeZQRFW5HNKffLmsMJBVXUR3zkyAzas/LeWgPswZ// Cc4F1ulYd2oN3ZudvF7IFzUKdGndfcdAWMc1t5yZ+n4Su7BoDpB/EKI4nptrJ4GRo/ywXwRa06W QXt4B X-Gm-Gg: ASbGncsxETV4ctw+ZC+hM66RIUux38PmOH8c1fJ5QvNiSRDSRGD7m3OeIIchuirdnfe r6fGwWfnc+zXz2Fe3OkUP1xX9CGSFuoXiuQnF0EqxY+xYb+Dl74SR+K6xG7sOtPV0iFrImRNY4B 0yq65scKxvWs0boKJOJa0E7F2YRIbpcZ4e7lMV8bWxU6BFDceWaNx/OsYLMyTYZRA7wLjEWKG0e eLhnDjsBev+Gh+onH4L1WKnmLlZs465gOGvsenyJ1Pe0R08Gzox0i1gOiAK0H0rv2JXHED18BYE 3+NQ9D0b7H1jm2eAPSww1I0FrqJgRlVTDhQIRr/arR2dexleHrSoSxOubXU3VXevYk4rBUx1pQI +joLfhw== X-Google-Smtp-Source: AGHT+IGhUDNGpV48uQ1ya2kZSs4uUM1kiclr7X4KmS9Qa0h9i+PybKGH6fZm9D0DZWjpkLZc8aGSZw== X-Received: by 2002:a05:600c:1d0a:b0:451:dee4:cd07 with SMTP id 5b1f17b1804b1-4536478e1e7mr10076895e9.0.1750423497870; Fri, 20 Jun 2025 05:44:57 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.44.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:44:57 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 1/8] ipa: rpi: Defer initialising AF LensPosition ControlInfo and value Date: Fri, 20 Jun 2025 13:42:22 +0100 Message-ID: <20250620124452.557855-2-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst This fixes two small bugs: We previously populated LensPosition's ControlInfo with hard-coded values, ignoring the tuning file. Now we query the AfAlgorithm to get limits (over all AF ranges) and default (for AfRangeNormal). We previously sent a default position to the lens driver, even when a user-specified starting position would follow. Defer doing this, to reduce unnecessary lens movement at startup (for some drivers). Fixes: https://bugs.libcamera.org/show_bug.cgi?id=258 Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/common/ipa_base.cpp | 53 +++++++++++++++++---------- src/ipa/rpi/controller/af_algorithm.h | 8 +++- src/ipa/rpi/controller/rpi/af.cpp | 16 +++++++- src/ipa/rpi/controller/rpi/af.h | 4 +- 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp index 6565f5366312..a5bdcbb5838c 100644 --- a/src/ipa/rpi/common/ipa_base.cpp +++ b/src/ipa/rpi/common/ipa_base.cpp @@ -233,25 +233,6 @@ int32_t IpaBase::configure(const IPACameraSensorInfo &sensorInfo, const ConfigPa agcStatus.analogueGain = defaultAnalogueGain; applyAGC(&agcStatus, ctrls); - /* - * Set the lens to the default (typically hyperfocal) position - * on first start. - */ - if (lensPresent_) { - RPiController::AfAlgorithm *af = - dynamic_cast(controller_.getAlgorithm("af")); - - if (af) { - float defaultPos = - ipaAfControls.at(&controls::LensPosition).def().get(); - ControlList lensCtrl(lensCtrls_); - int32_t hwpos; - - af->setLensPosition(defaultPos, &hwpos); - lensCtrl.set(V4L2_CID_FOCUS_ABSOLUTE, hwpos); - result->lensControls = std::move(lensCtrl); - } - } } result->sensorControls = std::move(ctrls); @@ -281,8 +262,20 @@ int32_t IpaBase::configure(const IPACameraSensorInfo &sensorInfo, const ConfigPa ctrlMap.merge(ControlInfoMap::Map(ipaColourControls)); /* Declare Autofocus controls, only if we have a controllable lens */ - if (lensPresent_) + if (lensPresent_) { ctrlMap.merge(ControlInfoMap::Map(ipaAfControls)); + RPiController::AfAlgorithm *af = + dynamic_cast(controller_.getAlgorithm("af")); + if (af) { + double min, max, dflt; + af->getLensLimits(min, max); + dflt = af->getDefaultLensPosition(); + ctrlMap[&controls::LensPosition] = + ControlInfo(static_cast(min), + static_cast(max), + static_cast(dflt)); + } + } result->controlInfo = ControlInfoMap(std::move(ctrlMap), controls::controls); @@ -320,6 +313,26 @@ void IpaBase::start(const ControlList &controls, StartResult *result) /* Make a note of this as it tells us the HDR status of the first few frames. */ hdrStatus_ = agcStatus.hdr; + /* + * AF: If no lens position was specified, drive lens to a default position. + * This had to be deferred (not initialised by a constructor) until here + * to ensure that exactly ONE starting position is sent to the lens driver. + * It should be the static API default, not dependent on AF range or mode. + */ + if (firstStart_ && lensPresent_) { + RPiController::AfAlgorithm *af = dynamic_cast( + controller_.getAlgorithm("af")); + if (af && !af->getLensPosition()) { + int32_t hwpos; + double pos = af->getDefaultLensPosition(); + if (af->setLensPosition(pos, &hwpos, true)) { + ControlList lensCtrls(lensCtrls_); + lensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE, hwpos); + setLensControls.emit(lensCtrls); + } + } + } + /* * Initialise frame counts, and decide how many frames must be hidden or * "mistrusted", which depends on whether this is a startup from cold, diff --git a/src/ipa/rpi/controller/af_algorithm.h b/src/ipa/rpi/controller/af_algorithm.h index ad9b575450e3..382609f9b2d8 100644 --- a/src/ipa/rpi/controller/af_algorithm.h +++ b/src/ipa/rpi/controller/af_algorithm.h @@ -33,6 +33,10 @@ public: * * getMode() is provided mainly for validating controls. * getLensPosition() is provided for populating DeviceStatus. + * + * getDefaultlensPosition() and getLensLimits() were added for + * populating ControlInfoMap. They return the static API limits + * which should be independent of the current range or mode. */ enum AfRange { AfRangeNormal = 0, @@ -66,7 +70,9 @@ public: } virtual void setMode(AfMode mode) = 0; virtual AfMode getMode() const = 0; - virtual bool setLensPosition(double dioptres, int32_t *hwpos) = 0; + virtual double getDefaultLensPosition() const = 0; + virtual void getLensLimits(double &min, double &max) const = 0; + virtual bool setLensPosition(double dioptres, int32_t *hwpos, bool force = false) = 0; virtual std::optional getLensPosition() const = 0; virtual void triggerScan() = 0; virtual void cancelScan() = 0; diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 2157eb94f427..041cb51db277 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -715,11 +715,23 @@ void Af::setWindows(libcamera::Span const &wins) invalidateWeights(); } -bool Af::setLensPosition(double dioptres, int *hwpos) +double Af::getDefaultLensPosition() const +{ + return cfg_.ranges[AfRangeNormal].focusDefault; +} + +void Af::getLensLimits(double &min, double &max) const +{ + /* Limits for manual focus are set by map, not by ranges */ + min = cfg_.map.domain().start; + max = cfg_.map.domain().end; +} + +bool Af::setLensPosition(double dioptres, int *hwpos, bool force) { bool changed = false; - if (mode_ == AfModeManual) { + if (mode_ == AfModeManual || force) { LOG(RPiAf, Debug) << "setLensPosition: " << dioptres; ftarget_ = cfg_.map.domain().clamp(dioptres); changed = !(initted_ && fsmooth_ == ftarget_); diff --git a/src/ipa/rpi/controller/rpi/af.h b/src/ipa/rpi/controller/rpi/af.h index 317a51f3ecc3..d8ece1ab119c 100644 --- a/src/ipa/rpi/controller/rpi/af.h +++ b/src/ipa/rpi/controller/rpi/af.h @@ -54,7 +54,9 @@ public: void setWindows(libcamera::Span const &wins) override; void setMode(AfMode mode) override; AfMode getMode() const override; - bool setLensPosition(double dioptres, int32_t *hwpos) override; + double getDefaultLensPosition() const override; + void getLensLimits(double &min, double &max) const override; + bool setLensPosition(double dioptres, int32_t *hwpos, bool force) override; std::optional getLensPosition() const override; void triggerScan() override; void cancelScan() override; From patchwork Fri Jun 20 12:42:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23610 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 5477DBDE6B for ; Fri, 20 Jun 2025 12:45:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 77F8B61535; Fri, 20 Jun 2025 14:45:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="ZR7n+Sw/"; 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 2C39E61535 for ; Fri, 20 Jun 2025 14:44:59 +0200 (CEST) Received: by mail-wr1-x42f.google.com with SMTP id ffacd0b85a97d-3a4e749d7b2so353163f8f.0 for ; Fri, 20 Jun 2025 05:44:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423498; x=1751028298; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=1fgw5gWlXRgAGINCK27+v1vEnL5TJfgKBKWPe1uS9M8=; b=ZR7n+Sw/JdmA9+GKE1/oTpY15ePHs6Zto+8BjGsxV47aZ9/uTcWW61J3cvg0U295VZ kHviOaNPNUzXJZ+5RGRzyKIRYoW9HcYJ5uqSQYiK4QcjUClX6ZxA0PkifWopO1gEIAOH QOmGgphipz9tfivmxJ4dCCUyJF4PTq9F9nfPziGhFb1iiOtDYUYpE3Ays6YN1S+d+xCr nVB3O0SDZbz1xQkJBQgBBIQXOaW6rtT4Rmz3edKZS4ykZUOcAAn4llVMAOSbnty6HKT3 Btp9NWGWrmsPGncUPZa9MPQTDTb3nd2hjs9w1JBNdTlCfq5GFs/ay5ZFDjH1BepgYSms X3AA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423498; x=1751028298; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1fgw5gWlXRgAGINCK27+v1vEnL5TJfgKBKWPe1uS9M8=; b=awZxYmqU4O6CalbirDCe0Nq1vk6MCRg2+TYWQOkLJkvhVNR3Bot0DxSL2ZRHFHA69w bYXo202+Li4xvU4n8O/4XKeTo6YKrZqFM2HBL1PtSvpge5gUqjHgfno9bvilTao92hDh aRAr1LZwi7r4UmhY6i/yGmg5C7j4wAglRUU2QmOsHB0VjB91uYpdnxRGAg27dFfr1YMn v5wDICs9GTc5ojJkffV0ZfCgLq8BR/djdsb9V0dpSWXK9lI+ErjRx0BJ9gURj1zkoTbd H9WSAELSeHnVLaKcLf65LGH8/hza+9qM2MwhNFVLOelrWa9l/K6Van+52q8QS4JNn/cE Rykg== X-Gm-Message-State: AOJu0Yx94m4rPGPmkuifRtlDIxzqX7bPZN3t/9ytFeXXDvkejO/tzErR XhSbX/Lhi/AGvOxgsppWjG9n/MtE2IrDYE6h8siKHs6BZ0L2bctnimfqtX3zohYnWlcFlwuH7BU KtDba X-Gm-Gg: ASbGncsELat11iL/sTKNCOSWJUswpgV8LIMCkOzJScwFheelpoKWT2lcVMkknTE9JeR 2oi37NGQyDR/1C7Nsa/U3Ir1DkhhOptsTwJ556vwCHKUUZ+SXHeAgE1tHV8oV6wTYxvf6/3OPe1 +/SdPBJyCs49kbvD+UYJYZapcDnONtvMNufqzP7SUzjSOb9IUZXqRVod2jmCDZYSjc40IIjsoNm dUtRCgFVZguIZBJtUaVq3hKbog89oH7MYsM+yyxDB3+1JVUFhxqfd/5BPZ6TnKfewB0LdcazZyA KRQyvGkLXqlyDi0HyBQLOhb1zyFSVUbl9FyT6HBT4+1NDJRjuOufZkLuTJw1Tx+Tp/vjDSk15dE lmXAI3g== X-Google-Smtp-Source: AGHT+IG+V2QnXhGMLGsz1b49YX+JWTlKouCpYcyTJsmce+nG18y0Jrqq3ike0fb0OGRjnqBKBY0kpQ== X-Received: by 2002:a05:600c:c087:b0:439:a30f:2e49 with SMTP id 5b1f17b1804b1-453657bd470mr7316525e9.5.1750423498446; Fri, 20 Jun 2025 05:44:58 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.44.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:44:58 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 2/8] ipa: rpi: controller: Improve findPeak() function in AF algorithm Date: Fri, 20 Jun 2025 13:42:23 +0100 Message-ID: <20250620124452.557855-3-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst Improve quadratic peak fitting in findPeak(). The old approximation was good but only valid when points were equally spaced and the MAX was not at one end of the series. Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/controller/rpi/af.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 041cb51db277..8df614ed7b6b 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -436,15 +436,28 @@ double Af::findPeak(unsigned i) const { double f = scanData_[i].focus; - if (i > 0 && i + 1 < scanData_.size()) { - double dropLo = scanData_[i].contrast - scanData_[i - 1].contrast; - double dropHi = scanData_[i].contrast - scanData_[i + 1].contrast; - if (0.0 <= dropLo && dropLo < dropHi) { - double param = 0.3125 * (1.0 - dropLo / dropHi) * (1.6 - dropLo / dropHi); - f += param * (scanData_[i - 1].focus - f); - } else if (0.0 <= dropHi && dropHi < dropLo) { - double param = 0.3125 * (1.0 - dropHi / dropLo) * (1.6 - dropHi / dropLo); - f += param * (scanData_[i + 1].focus - f); + if (scanData_.size() >= 3) { + /* + * Given the sample with the highest contrast score and its two + * neighbours either side (or same side if at the end of a scan), + * solve for the best lens position by fitting a parabola. + * Adapted from awb.cpp: interpolateQaudaratic() + */ + + if (i == 0) + i++; + else if (i + 1 >= scanData_.size()) + i--; + + double abx = scanData_[i - 1].focus - scanData_[i].focus; + double aby = scanData_[i - 1].contrast - scanData_[i].contrast; + double cbx = scanData_[i + 1].focus - scanData_[i].focus; + double cby = scanData_[i + 1].contrast - scanData_[i].contrast; + double denom = 2.0 * (aby * cbx - cby * abx); + if (std::abs(denom) >= (1.0 / 64.0) && denom * abx > 0.0) { + f = (aby * cbx * cbx - cby * abx * abx) / denom; + f = std::clamp(f, std::min(abx, cbx), std::max(abx, cbx)); + f += scanData_[i].focus; } } From patchwork Fri Jun 20 12:42:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23611 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 A6590BDE6B for ; Fri, 20 Jun 2025 12:45:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4B8BC68DF8; Fri, 20 Jun 2025 14:45:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="HfV76mwc"; dkim-atps=neutral Received: from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com [IPv6:2a00:1450:4864:20::32f]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D217B68DE9 for ; Fri, 20 Jun 2025 14:44:59 +0200 (CEST) Received: by mail-wm1-x32f.google.com with SMTP id 5b1f17b1804b1-4530e6f4db4so721425e9.2 for ; Fri, 20 Jun 2025 05:44:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423499; x=1751028299; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=7EfgoST468pTOcCeNOjVH8kfATETd/PEr3m+VpAYBV0=; b=HfV76mwcaIwsMl9JkkXdZBGkpqDvNwaHlnOEF5d1+jO+gkwRUF0BTg6+G5nUYpad0+ 1kOPp2KAKNCmDC3iUxIckHzWUq779knnvyRxDPO6ownfGIFs7D+j+weDppqmoNyV61lK mLkhOAzII6wI15IYc3LatdWDrFw/yeU8Gnns4zROgPG2HfxeDubZNuyqSz9QOCPmELKR BgOIOUvzEBeiffiEGb+aJhJ3Io1f4VAHgSVt22RXgiJHSi5PZ8gBTJ6t8pwPOuFkcxkG 4dT6zIDr/LFOG6jaSzAS9uuZQM3UyHZNhd5IEV0ZHCSUh8Lv4+VIQNSgqDYKOasU9cCE K2mw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423499; x=1751028299; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7EfgoST468pTOcCeNOjVH8kfATETd/PEr3m+VpAYBV0=; b=ADnguLDiRCGLjorg6cCqWxm8mIQYoSzMxWWBWB76K94l3sfyCqgnAOP65DlzStwlTd UCx1WQcXDMwsaIBajRs+kDGZ5KHbYEimpcf+Qq3Y4J8ostqPyCPXkCRt5A7r0NaxoT/t FoFHhlU1hPq2tPmNZXFea+SI97s1nziRIcZXTaCWRjLWVxrn8qsseIKrXvbRXmYn1AIB kdS+mVhgrhnLetjCG2NBiNImLUPs+hpDxCdVA3sI96xIHSsgDf4pq/NxMQUt02/g8+co lNk0RhsfeHBZ+Amvmm7rgUOtzLoUQSwJmuSAY6l/i3DX4zJDwRToWuJkt1AyWGVPVxnk iMTg== X-Gm-Message-State: AOJu0YwlqrrvjUjiz+dG4qgBJFun727MNkHjk9AkWltsK444PJ+g/VkZ AJDW7/xkrsSfs2wlYiZaTYm2aG6jr2mBFZehvQUTpojRqpMFnucjDUwfv4twTk7Xob5GGPKEGMO 1R4XD X-Gm-Gg: ASbGnctr7/i8DAi18IPP9XRiPE0VSpgQ5kiM6cFMzxEx5nJWWr8E4lREnEmmfnBnWso kIAN3j+LS2IMV40coY0wfC9qZsM/e0qzT1jnyY14TtT9KVoLa5jdmKmrUhlRJVhlSNTB9Ge7R/C v9WvktVRqnS7HVWkQASwdAJZ5xlKubGWIfQwVwhwvUwQXrfGkOnCrSHRO9Ny/KqlaUC/6c4NxRb G+RoknWyoOWJoFjuqDnqtJ3uXqlm2Vo/o3buwGv2pZ6nd6WRtv1Mn7gbiNoHbX3XoIGlxNOPxo9 ZY2ECw1n1HBG4dXVEqxWYivr9SNOzxKTTqCGFTmJ62exmNvJL3vFEi/vYSXmzF+0CNU2WBQyMJq R/4860A== X-Google-Smtp-Source: AGHT+IF9wwYwGwYNbkAajQ1zS+nRolfRzaKEe6S2d2c3N6e7wmajiq4JO2r4PHKFVbnQDaf+tS/5Ig== X-Received: by 2002:a05:600c:c042:b0:451:df07:f41e with SMTP id 5b1f17b1804b1-45367307cd9mr3191595e9.1.1750423499015; Fri, 20 Jun 2025 05:44:59 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.44.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:44:58 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 3/8] ipa: rpi: controller: AutoFocus weighting tweak Date: Fri, 20 Jun 2025 13:42:24 +0100 Message-ID: <20250620124452.557855-4-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst In getPhase(), stop using different weights for sumWc and sumWcp. This should improve linearity e.g. in earlyTerminationByPhase(). Phases are slightly larger but confidence values slightly reduced. Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/controller/rpi/af.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 8df614ed7b6b..5304f54ca967 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -328,9 +328,8 @@ bool Af::getPhase(PdafRegions const ®ions, double &phase, double &conf) if (c >= cfg_.confThresh) { if (c > cfg_.confClip) c = cfg_.confClip; - c -= (cfg_.confThresh >> 2); + c -= (cfg_.confThresh >> 1); sumWc += w * c; - c -= (cfg_.confThresh >> 2); sumWcp += (int64_t)(w * c) * (int64_t)data.phase; } } From patchwork Fri Jun 20 12:42:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23612 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 A6543BDE6B for ; Fri, 20 Jun 2025 12:45:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4BF7261538; Fri, 20 Jun 2025 14:45:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="gbIhFK7c"; dkim-atps=neutral Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5C20968DEC for ; Fri, 20 Jun 2025 14:45:00 +0200 (CEST) Received: by mail-wr1-x431.google.com with SMTP id ffacd0b85a97d-3a577f164c8so288296f8f.2 for ; Fri, 20 Jun 2025 05:45:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423500; x=1751028300; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZtR9/ErdKUSfx6biHWA2K9BllLNkDfqCLyVdT4Rw+b8=; b=gbIhFK7c78OFkcQTyE+YuhwTuKf7RcnYDjCQvdXttZER24g7NKyX8O6aL9svo/fju0 lgslcCrtVmlaGa8mpjRV9EfspQv5yUIPvJWS35pN3qMbn6mls2NDVEAmoeco9SIpicex JfQ1p5pX2BCs03AOgc2wmEMXMzBEjXRmgiA8OSQ+cMGHoYkERaV/ODA7zSbg2MEddLJT QrS9bDVT8zbCex9S7BECfJkWqdkO6IF9nqCsADO9J9weG33JcVriEhUoANYFx9dn1RzC OOvTFKd0uq9lgK6Y5o6LLXxnmTM8uYvJyIP8L4ZpB+CMZb0nFCBWwRNp7B4Sormi2CC3 n0Jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423500; x=1751028300; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZtR9/ErdKUSfx6biHWA2K9BllLNkDfqCLyVdT4Rw+b8=; b=DNX6fTRipl5zEqdD+1vWWr9pqEmP+DwxapEXQkN84C0v88y3/S5Ra2gO/jNPzYCRaM xdhw6vt43hU8Wy5NH3yrs8gBCw/3Qtwv4ZT4jLdW6dUbfV5Hd4l6ULacRmSQVWT+eao9 2vXrXGBMFCthYdU37fmchb/Y3WgrDPdsBJrZlw/oBReREjiKZy++ph0dHDJ5FUcDgRsd gXc1jMuVpaTgamJAi0eL2wT09QtYv0qNh4QUGtDP6bd667QoPE1TVbHrac53Izd3SMvV eIv0F9T9685h7eO+6YkcqLKEX1wttlim2sOEXY2TgcLKA31zvO2dPqMgS/jVgEbDuGup mnZA== X-Gm-Message-State: AOJu0Yzgt9i2JtnlqjKY2/gh3kvljnj4RIT7wEJZdAeHHL7jpcimagmA t9nZVgh7TwB4nA2WmGSRYEETEYa53cgVXUpr0/aMcIv/wFiNmro/B8uQ775KC1hg+vRxQzQ9tQ3 +fgOn X-Gm-Gg: ASbGncukm6OKLzyh5+e4T9g2w6mn26A4/ej2gCd4gK4ZZEGpr0aM4DlMu/Voe0ZKA5q iTVmicQSJzmK6urlxcONaYFMpBGVcP7jLqGBMQ4oSFS/Sqp04IIIWJcsWp7e8jatiMT3YDYgXVs 3yeUZ8EaWqZz9jl2/n/x8P/mv1Vl5rsh9R99qHuj3juTaljvvMBj8uj5kXQudzqpKDcA76p3OMg RubNjTQlJ4Q1V/pp5tIMto53Hj12OHUsnF5KTz/XmfcklHpxf1EbeXASmr82v9KSXBEa8YLYhyq RDL0xB4wMKLBXMlCErKkpghnm0t0kFi33pwYWA6mE+aB30JDLLyV6WK8HxtfSfWyNQ5uJh4xcXL 64a2zug== X-Google-Smtp-Source: AGHT+IEm+Fmnq9dEsZe60wPFdFCigAjle+kLrRC7WkeF+oRlF01b0ILE6Ukt/Ej640THCx6Y50GRdQ== X-Received: by 2002:a05:600c:6989:b0:43d:fa58:81d2 with SMTP id 5b1f17b1804b1-453659b60b2mr10262525e9.9.1750423499612; Fri, 20 Jun 2025 05:44:59 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.44.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:44:59 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 4/8] ipa: rpi: controller: Autofocus CAF/PDAF stability tweak Date: Fri, 20 Jun 2025 13:42:25 +0100 Message-ID: <20250620124452.557855-5-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst When in Continuous AF mode using PDAF, only move the lens when phase has had the same sign for at least 4 frames. This reduces lens wobble in e.g. noisy conditions. Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/controller/rpi/af.cpp | 12 +++++++++++- src/ipa/rpi/controller/rpi/af.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 5304f54ca967..3b2d6167df61 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -181,9 +181,11 @@ Af::Af(Controller *controller) ftarget_(-1.0), fsmooth_(-1.0), prevContrast_(0.0), + prevPhase_(0.0), skipCount_(0), stepCount_(0), dropCount_(0), + sameSignCount_(0), scanMaxContrast_(0.0), scanMinContrast_(1.0e9), scanData_(), @@ -513,6 +515,13 @@ void Af::doAF(double contrast, double phase, double conf) return; } + /* Count frames for which PDAF phase has had same sign */ + if (phase * prevPhase_ <= 0.0) + sameSignCount_ = 0; + else + sameSignCount_++; + prevPhase_ = phase; + if (scanState_ == ScanState::Pdaf) { /* * Use PDAF closed-loop control whenever available, in both CAF @@ -522,7 +531,8 @@ void Af::doAF(double contrast, double phase, double conf) * scan only after a number of frames with low PDAF confidence. */ if (conf > (dropCount_ ? 1.0 : 0.25) * cfg_.confEpsilon) { - doPDAF(phase, conf); + if (mode_ == AfModeAuto || sameSignCount_ >= 3) + doPDAF(phase, conf); if (stepCount_ > 0) stepCount_--; else if (mode_ != AfModeContinuous) diff --git a/src/ipa/rpi/controller/rpi/af.h b/src/ipa/rpi/controller/rpi/af.h index d8ece1ab119c..b06a3a16fab5 100644 --- a/src/ipa/rpi/controller/rpi/af.h +++ b/src/ipa/rpi/controller/rpi/af.h @@ -158,7 +158,9 @@ private: bool initted_; double ftarget_, fsmooth_; double prevContrast_; + double prevPhase_; unsigned skipCount_, stepCount_, dropCount_; + unsigned sameSignCount_; unsigned scanMaxIndex_; double scanMaxContrast_, scanMinContrast_; std::vector scanData_; From patchwork Fri Jun 20 12:42:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23613 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 30CBCBDE6B for ; Fri, 20 Jun 2025 12:45:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 378E268DF5; Fri, 20 Jun 2025 14:45:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="HPdXYfRo"; dkim-atps=neutral Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DD1D468DC6 for ; Fri, 20 Jun 2025 14:45:00 +0200 (CEST) Received: by mail-wr1-x430.google.com with SMTP id ffacd0b85a97d-3a4e57d018cso300746f8f.1 for ; Fri, 20 Jun 2025 05:45:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423500; x=1751028300; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=24KjDT2YWBwBNbd3x7CDgdf7GATAgEkVdmI8IyKPmTk=; b=HPdXYfRo2ks970/Fft3QaFiIH73SI5e46U2u6ZTWGQ4d+O5APdXdSpTNDVYtLiP2sK XiMbyxEHxEGn0EWb4ntC48Rm7nnMoys0mfog1RMSIEygaYKOWCNJqXlIYBcQMjzCq50p Fj8blBwpI0uGMIH6aYAOKOoMFMKEmcC0uoygYJBePrBaCrobmXy27MqB0F2nFhnqagEn jccWoQoqyQWUpf2rY2uycuGZxGt+SWAEKT8BZ5zKy+fRY4NEuAcpAIhMqwVBFAynknmY En0ARGU6w18WD2s7k+YwKHFkOBXhAJ9kwxVJbTxGWrHGDwbap9Xw8LprYt7ALqpbxGLb DgEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423500; x=1751028300; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=24KjDT2YWBwBNbd3x7CDgdf7GATAgEkVdmI8IyKPmTk=; b=uk81i1IjqmJuAQm/lsitdWNZdiOoiYqAVvnvaO3xsBwMB4uQznV0nQg5zOUfwvtHdk iMMtYdJSx5ESHoNcjkcsnzSxujzGQ+LXy5uTOaZy+NGozvKrA+y5UsYexCHSjwyPeNoC QjiyZ2K3QzbfWmbmx5iUFd00O7CSznF9tbNBbjKRFipJoDR0atMP1xdCKm9M5mXipLmo 1Mi3H7LvgY7cRVC6px65NoLDxgZrMmH86Q23BpjiTa8fLpSnBLhEtvrL1Dr5KbTQHpSH ZXdiJ4AM2yxUftwX1fR52g6QWcvB2S+lubxZ3TGGvLapVnmrZVRD4Jt3JZJZHND3aUlX vE7A== X-Gm-Message-State: AOJu0YzPSGv9SOuPlwoWuufKWqXsvqtRluM+unNV/l/iWHwMT48IZOnb u89gLANeFbnouLuzKNIc/u2SBvsDRvBT9LSHmRJsSnvLKUs23UxVRuvk7hV4eJO49XafcHi2FFT egDYi X-Gm-Gg: ASbGncuymL5oLAxDzZHRZP+UMp7jIrA61egGp+8EcJVBxFL8mdYXGXU1XQ11dFBSwdp YJGa9ZXPLYM9sLd4qS6nx/bhcjCKDvWi1o4xFshdJIIDwSuCkTo0ONYjux6AHKyF1ZXGOeTaOln wOpogYY1k/x4weKiZlq/6n5+cbj7SbnMgXG9/pYRF9W8q7XF0CNurmtpoDI4fmkFcTElsHwxjDd B7sBMRXP7NhHyBWjJzEGfSNngDCU3TqOSJuVCaJuy9Syp5ZmMCuJnS4dQEyVM0Qk5HvlphzxDXd MW3MjMIEqErv2GUajRF1j1rTUbWhecm7TBPVSQP/23AA4mVyB94zSE6qdmVieM8F7dkGpeQL1s6 fSt8+Qw== X-Google-Smtp-Source: AGHT+IHBgECgTN4VV0Cclz5AavamnOvPTx3PmVkiyqVoabLjkewYkt8veSsk0wosL4yQYHTE5lZfVQ== X-Received: by 2002:a05:6000:2211:b0:3a5:7875:576 with SMTP id ffacd0b85a97d-3a6d12d737bmr901101f8f.1.1750423500172; Fri, 20 Jun 2025 05:45:00 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.44.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:44:59 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 5/8] ipa: rpi: controller: AutoFocus tweak earlyTerminationByPhase() Date: Fri, 20 Jun 2025 13:42:26 +0100 Message-ID: <20250620124452.557855-6-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst Increase threshold for ETBP, from "confEpsilon" to "confThresh". Correct sign test to take account of pdafGain sign (typically -ve). Reduce allowed extrapolation range, but relax the check in the case of Continuous AF, when we go back into the PDAF closed loop. Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/controller/rpi/af.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 3b2d6167df61..ecc0fc4175a7 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -411,7 +411,7 @@ void Af::doPDAF(double phase, double conf) bool Af::earlyTerminationByPhase(double phase) { if (scanData_.size() > 0 && - scanData_[scanData_.size() - 1].conf >= cfg_.confEpsilon) { + scanData_[scanData_.size() - 1].conf >= cfg_.confThresh) { double oldFocus = scanData_[scanData_.size() - 1].focus; double oldPhase = scanData_[scanData_.size() - 1].phase; @@ -420,11 +420,12 @@ bool Af::earlyTerminationByPhase(double phase) * Interpolate/extrapolate the lens position for zero phase. * Check that the extrapolation is well-conditioned. */ - if ((ftarget_ - oldFocus) * (phase - oldPhase) > 0.0) { + if ((ftarget_ - oldFocus) * (phase - oldPhase) * cfg_.speeds[speed_].pdafGain < 0.0) { double param = phase / (phase - oldPhase); - if (-3.0 <= param && param <= 3.5) { - ftarget_ += param * (oldFocus - ftarget_); + if ((-2.5 <= param || mode_ == AfModeContinuous) && param <= 3.0) { LOG(RPiAf, Debug) << "ETBP: param=" << param; + param = std::max(param, -2.5); + ftarget_ += param * (oldFocus - ftarget_); return true; } } @@ -562,7 +563,7 @@ void Af::doAF(double contrast, double phase, double conf) else scanState_ = ScanState::Idle; scanData_.clear(); - } else if (conf >= cfg_.confEpsilon && earlyTerminationByPhase(phase)) { + } else if (conf >= cfg_.confThresh && earlyTerminationByPhase(phase)) { scanState_ = ScanState::Settle; stepCount_ = (mode_ == AfModeContinuous) ? 0 : cfg_.speeds[speed_].stepFrames; From patchwork Fri Jun 20 12:42:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23614 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 4D322C3240 for ; Fri, 20 Jun 2025 12:45:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AA28B68DFA; Fri, 20 Jun 2025 14:45:12 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="SQ/7t7SK"; dkim-atps=neutral Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C184E68DED for ; Fri, 20 Jun 2025 14:45:01 +0200 (CEST) Received: by mail-wr1-x42e.google.com with SMTP id ffacd0b85a97d-3a4ee391e6fso297752f8f.3 for ; Fri, 20 Jun 2025 05:45:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423501; x=1751028301; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=z+/M/GBxeweYftAicR2QQxTn1xxyvAvg8zZbDwaDW2Q=; b=SQ/7t7SKAV74rV0MR/0zGnP4sJJpllJR5BnJxXxv+uZgvt373AwMclCCEG3lmGUtIh kmQjyJ7xtM/rstcsox4OYdzdr6X/gg7STSHG45cTcFyp0MoznLKpdohVGRKZttplFzuL 4SHc9j3MNsiSKDt245+cC8TMSbRPOFL33Syb3bGLNM6FMtvKnByiQUk6rQSVDk5aNton zlZXwrEHlnNx+1pJMA67NzdRYYJSTtUZH02Lm8HRhJmrd4eIcPqYssfuaxuOBWCjyEd4 UMswuWqC4EIQTY/9S2h3l1LoRyGSRMQUXPSdOpwIUA/qBSqW8zkuKkxoqst/c465TGoW sT1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423501; x=1751028301; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=z+/M/GBxeweYftAicR2QQxTn1xxyvAvg8zZbDwaDW2Q=; b=eQUYYAA1fzQIXMP2zAagz5tShOkdrbWZWdkv6YRvLDgp1Vk1aHUEdIWT6d99hgynJP 4e4kvDdnvovnqUh4pwDKcsKRkb2iO62dr6LTgm9vxG5mZkZ+x09O+tPOIzGG6sRPu/61 uRTOwi5QHYXdfXkjBDdYOCgViBvAvjve9GQvq2EZ7fCA1x28lFDkfLLsibGnLHGQNjQd DG+Z8u05j0gBtxYNFfcnOeKgVZt/2+OOC2FH6hxZyVmUsIHeo57akBjhh9GIrgg3KSDf ESmAt64OH1etCSzCdYiq42+Ggj24l6G1uez2QfJrq0PeqD25jib6nmNdsz8BiMtXQbxt 8n0w== X-Gm-Message-State: AOJu0YywpngUNXT3g8XytItsqNZSIdD9QnH+DEqyxWdY3O7ig7uyObRA 7dB5yo5KTUtfQGqFCdHGhegsvf0dWBry8MLyL2KokOXVOv+FMVP8T8YWEmDDK+bKAm/cxd3ezKK efip1 X-Gm-Gg: ASbGncs/byOPcnxMbxPHeycFVRb9iYNuHOxjEJVCr8eyPfaV2HnzfsXR/ZCA9dcWpUu 73BdBhcFFWhyaswLKxgceRRHy7CiIhKa7as5jeVQ8YwHmTJRrf4jYRAHLDrWeoO7xdsuaEQJBAS vNktaAXOc0VeWI0CWAA23YMGnV7G4M/qZ/bmx+WyxkxyfWwtvEx/H8O3LfcRZUb3fJ7+A4YjZm2 641isboi4ggRSIiW4hAekiaLZ5PXu6MliMwyUgwquvFkCC3+SfPOgmThWvIw5P41lutadwVBilw PRe6TqMxtqPx7nF7QNjNssMfnYILtVFPAMCoL0BtC7RohMCIQ+H3oEmYwsdxtVG0ydrv6zgtbsn hgnfmmwoYYm2b5P4Y X-Google-Smtp-Source: AGHT+IE3h2D0ZR2HRJzay5YgOmCdgR+Fd9/p+PBUBGYKTUvnhJh3Ji4KAQUKLPn+Y7oqt7G182+P2Q== X-Received: by 2002:a05:6000:400f:b0:3a4:f912:86af with SMTP id ffacd0b85a97d-3a6d11931e8mr897526f8f.2.1750423500791; Fri, 20 Jun 2025 05:45:00 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.45.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:45:00 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 6/8] ipa: rpi: controller: Autofocus to use AWB statistics; re-trigger Date: Fri, 20 Jun 2025 13:42:27 +0100 Message-ID: <20250620124452.557855-7-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst Analyse AWB statistics: used both for scene change detection and to detect IR lighting (when a flag is set in the tuning file). Option to suppress PDAF altogether when IR lighting is detected. Rather than being based solely on PDAF "dropout", allow a scan to be (re-)triggered whenever the scene changes and then stabilizes, based on contrast and average RGB statistics within the AF window. Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/controller/rpi/af.cpp | 137 +++++++++++++++++++++++++++--- src/ipa/rpi/controller/rpi/af.h | 37 +++++--- 2 files changed, 149 insertions(+), 25 deletions(-) diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index ecc0fc4175a7..4396420a0277 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -46,6 +46,8 @@ Af::SpeedDependentParams::SpeedDependentParams() : stepCoarse(1.0), stepFine(0.25), contrastRatio(0.75), + retriggerRatio(0.75), + retriggerDelay(10), pdafGain(-0.02), pdafSquelch(0.125), maxSlew(2.0), @@ -60,6 +62,7 @@ Af::CfgParams::CfgParams() confThresh(16), confClip(512), skipFrames(5), + checkForIR(false), map() { } @@ -87,6 +90,8 @@ void Af::SpeedDependentParams::read(const libcamera::YamlObject ¶ms) readNumber(stepCoarse, params, "step_coarse"); readNumber(stepFine, params, "step_fine"); readNumber(contrastRatio, params, "contrast_ratio"); + readNumber(retriggerRatio, params, "retrigger_ratio"); + readNumber(retriggerDelay, params, "retrigger_delay"); readNumber(pdafGain, params, "pdaf_gain"); readNumber(pdafSquelch, params, "pdaf_squelch"); readNumber(maxSlew, params, "max_slew"); @@ -137,6 +142,7 @@ int Af::CfgParams::read(const libcamera::YamlObject ¶ms) readNumber(confThresh, params, "conf_thresh"); readNumber(confClip, params, "conf_clip"); readNumber(skipFrames, params, "skip_frames"); + readNumber(checkForIR, params, "check_for_ir"); if (params.contains("map")) map = params["map"].get(ipa::Pwl{}); @@ -176,29 +182,37 @@ Af::Af(Controller *controller) useWindows_(false), phaseWeights_(), contrastWeights_(), + awbWeights_(), scanState_(ScanState::Idle), initted_(false), + irFlag_(false), ftarget_(-1.0), fsmooth_(-1.0), prevContrast_(0.0), + oldSceneContrast_(0.0), + prevAverage_{ 0.0, 0.0, 0.0 }, + oldSceneAverage_{ 0.0, 0.0, 0.0 }, prevPhase_(0.0), skipCount_(0), stepCount_(0), dropCount_(0), sameSignCount_(0), + sceneChangeCount_(0), scanMaxContrast_(0.0), scanMinContrast_(1.0e9), scanData_(), reportState_(AfState::Idle) { /* - * Reserve space for data, to reduce memory fragmentation. It's too early - * to query the size of the PDAF (from camera) and Contrast (from ISP) - * statistics, but these are plausible upper bounds. + * Reserve space for data structures, to reduce memory fragmentation. + * It's too early to query the size of the PDAF sensor data, so guess. */ + windows_.reserve(1); phaseWeights_.w.reserve(16 * 12); contrastWeights_.w.reserve(getHardwareConfig().focusRegions.width * getHardwareConfig().focusRegions.height); + contrastWeights_.w.reserve(getHardwareConfig().awbRegions.width * + getHardwareConfig().awbRegions.height); scanData_.reserve(32); } @@ -309,6 +323,7 @@ void Af::invalidateWeights() { phaseWeights_.sum = 0; contrastWeights_.sum = 0; + awbWeights_.sum = 0; } bool Af::getPhase(PdafRegions const ®ions, double &phase, double &conf) @@ -365,6 +380,54 @@ double Af::getContrast(const FocusRegions &focusStats) return (contrastWeights_.sum > 0) ? ((double)sumWc / (double)contrastWeights_.sum) : 0.0; } +/* + * Get the average R, G, B values in AF window[s] (from AWB statistics). + * Optionally, check if all of {R,G,B} are within 4:5 of each other + * across more than 50% of the counted area and within the AF window: + * for an RGB sensor this strongly suggests that IR lighting is in use. + */ + +bool Af::getAverageAndTestIr(const RgbyRegions &awbStats, double rgb[3]) +{ + libcamera::Size size = awbStats.size(); + if (size.height != awbWeights_.rows || + size.width != awbWeights_.cols || awbWeights_.sum == 0) { + LOG(RPiAf, Debug) << "Recompute RGB weights " << size.width << 'x' << size.height; + computeWeights(&awbWeights_, size.height, size.width); + } + + uint64_t sr = 0, sg = 0, sb = 0, sw = 1; + uint64_t greyCount = 0, allCount = 0; + for (unsigned i = 0; i < awbStats.numRegions(); ++i) { + uint64_t r = awbStats.get(i).val.rSum; + uint64_t g = awbStats.get(i).val.gSum; + uint64_t b = awbStats.get(i).val.bSum; + uint64_t w = awbWeights_.w[i]; + if (w) { + sw += w; + sr += w * r; + sg += w * g; + sb += w * b; + } + if (cfg_.checkForIR) { + if (4 * r < 5 * b && 4 * b < 5 * r && + 4 * r < 5 * g && 4 * g < 5 * r && + 4 * b < 5 * g && 4 * g < 5 * b) + greyCount += awbStats.get(i).counted; + allCount += awbStats.get(i).counted; + } + } + + rgb[0] = sr / (double)sw; + rgb[1] = sg / (double)sw; + rgb[2] = sb / (double)sw; + + return (cfg_.checkForIR && 2 * greyCount > allCount && + 4 * sr < 5 * sb && 4 * sb < 5 * sr && + 4 * sr < 5 * sg && 4 * sg < 5 * sr && + 4 * sb < 5 * sg && 4 * sg < 5 * sb); +} + void Af::doPDAF(double phase, double conf) { /* Apply loop gain */ @@ -473,6 +536,8 @@ void Af::doScan(double contrast, double phase, double conf) if (scanData_.empty() || contrast > scanMaxContrast_) { scanMaxContrast_ = contrast; scanMaxIndex_ = scanData_.size(); + if (scanState_ != ScanState::Fine) + std::copy(prevAverage_, prevAverage_ + 3, oldSceneAverage_); } if (contrast < scanMinContrast_) scanMinContrast_ = contrast; @@ -523,27 +588,63 @@ void Af::doAF(double contrast, double phase, double conf) sameSignCount_++; prevPhase_ = phase; + if (mode_ == AfModeManual) + return; /* nothing to do */ + if (scanState_ == ScanState::Pdaf) { /* * Use PDAF closed-loop control whenever available, in both CAF * mode and (for a limited number of iterations) when triggered. - * If PDAF fails (due to poor contrast, noise or large defocus), - * fall back to a CDAF-based scan. To avoid "nuisance" scans, - * scan only after a number of frames with low PDAF confidence. + * If PDAF fails (due to poor contrast, noise or large defocus) + * for at least dropoutFrames, fall back to a CDAF-based scan + * immediately (in triggered-auto) or on scene change (in CAF). */ - if (conf > (dropCount_ ? 1.0 : 0.25) * cfg_.confEpsilon) { + if (conf >= cfg_.confEpsilon) { if (mode_ == AfModeAuto || sameSignCount_ >= 3) doPDAF(phase, conf); if (stepCount_ > 0) stepCount_--; else if (mode_ != AfModeContinuous) scanState_ = ScanState::Idle; + oldSceneContrast_ = contrast; + std::copy(prevAverage_, prevAverage_ + 3, oldSceneAverage_); + sceneChangeCount_ = 0; dropCount_ = 0; - } else if (++dropCount_ == cfg_.speeds[speed_].dropoutFrames) + return; + } else { + dropCount_++; + if (dropCount_ < cfg_.speeds[speed_].dropoutFrames) + return; + if (mode_ != AfModeContinuous) { + startProgrammedScan(); + return; + } + /* else fall through to waiting for a scene change */ + } + } + if (scanState_ < ScanState::Coarse && mode_ == AfModeContinuous) { + /* + * In CAF mode, not in a scan, and PDAF is unavailable. + * Wait for a scene change, followed by stability. + */ + if (contrast + 1.0 < cfg_.speeds[speed_].retriggerRatio * oldSceneContrast_ || + oldSceneContrast_ + 1.0 < cfg_.speeds[speed_].retriggerRatio * contrast || + prevAverage_[0] + 1.0 < cfg_.speeds[speed_].retriggerRatio * oldSceneAverage_[0] || + oldSceneAverage_[0] + 1.0 < cfg_.speeds[speed_].retriggerRatio * prevAverage_[0] || + prevAverage_[1] + 1.0 < cfg_.speeds[speed_].retriggerRatio * oldSceneAverage_[1] || + oldSceneAverage_[1] + 1.0 < cfg_.speeds[speed_].retriggerRatio * prevAverage_[1] || + prevAverage_[2] + 1.0 < cfg_.speeds[speed_].retriggerRatio * oldSceneAverage_[2] || + oldSceneAverage_[2] + 1.0 < cfg_.speeds[speed_].retriggerRatio * prevAverage_[2]) { + oldSceneContrast_ = contrast; + std::copy(prevAverage_, prevAverage_ + 3, oldSceneAverage_); + sceneChangeCount_ = 1; + } else if (sceneChangeCount_) + sceneChangeCount_++; + if (sceneChangeCount_ >= cfg_.speeds[speed_].retriggerDelay) startProgrammedScan(); } else if (scanState_ >= ScanState::Coarse && fsmooth_ == ftarget_) { /* - * Scanning sequence. This means PDAF has become unavailable. + * CDAF-based scanning sequence. * Allow a delay between steps for CDAF FoM statistics to be * updated, and a "settling time" at the end of the sequence. * [A coarse or fine scan can be abandoned if two PDAF samples @@ -562,11 +663,14 @@ void Af::doAF(double contrast, double phase, double conf) scanState_ = ScanState::Pdaf; else scanState_ = ScanState::Idle; + dropCount_ = 0; + sceneChangeCount_ = 0; + oldSceneContrast_ = std::max(scanMaxContrast_, prevContrast_); scanData_.clear(); } else if (conf >= cfg_.confThresh && earlyTerminationByPhase(phase)) { + std::copy(prevAverage_, prevAverage_ + 3, oldSceneAverage_); scanState_ = ScanState::Settle; - stepCount_ = (mode_ == AfModeContinuous) ? 0 - : cfg_.speeds[speed_].stepFrames; + stepCount_ = (mode_ == AfModeContinuous) ? 0 : cfg_.speeds[speed_].stepFrames; } else doScan(contrast, phase, conf); } @@ -596,7 +700,8 @@ void Af::updateLensPosition() void Af::startAF() { /* Use PDAF if the tuning file allows it; else CDAF. */ - if (cfg_.speeds[speed_].dropoutFrames > 0 && + if (cfg_.speeds[speed_].pdafGain != 0.0 && + cfg_.speeds[speed_].dropoutFrames > 0 && (mode_ == AfModeContinuous || cfg_.speeds[speed_].pdafFrames > 0)) { if (!initted_) { ftarget_ = cfg_.ranges[range_].focusDefault; @@ -606,6 +711,8 @@ void Af::startAF() scanState_ = ScanState::Pdaf; scanData_.clear(); dropCount_ = 0; + oldSceneContrast_ = 0.0; + sceneChangeCount_ = 0; reportState_ = AfState::Scanning; } else startProgrammedScan(); @@ -656,7 +763,7 @@ void Af::prepare(Metadata *imageMetadata) uint32_t oldSt = stepCount_; if (imageMetadata->get("pdaf.regions", regions) == 0) getPhase(regions, phase, conf); - doAF(prevContrast_, phase, conf); + doAF(prevContrast_, phase, irFlag_ ? 0 : conf); updateLensPosition(); LOG(RPiAf, Debug) << std::fixed << std::setprecision(2) << static_cast(reportState_) @@ -666,7 +773,8 @@ void Af::prepare(Metadata *imageMetadata) << " ft" << oldFt << "->" << ftarget_ << " fs" << oldFs << "->" << fsmooth_ << " cont=" << (int)prevContrast_ - << " phase=" << (int)phase << " conf=" << (int)conf; + << " phase=" << (int)phase << " conf=" << (int)conf + << (irFlag_ ? " IR" : ""); } /* Report status and produce new lens setting */ @@ -690,6 +798,7 @@ void Af::process(StatisticsPtr &stats, [[maybe_unused]] Metadata *imageMetadata) { (void)imageMetadata; prevContrast_ = getContrast(stats->focusRegions); + irFlag_ = getAverageAndTestIr(stats->awbRegions, prevAverage_); } /* Controls */ diff --git a/src/ipa/rpi/controller/rpi/af.h b/src/ipa/rpi/controller/rpi/af.h index b06a3a16fab5..e1700f998f29 100644 --- a/src/ipa/rpi/controller/rpi/af.h +++ b/src/ipa/rpi/controller/rpi/af.h @@ -15,20 +15,28 @@ /* * This algorithm implements a hybrid of CDAF and PDAF, favouring PDAF. * - * Whenever PDAF is available, it is used in a continuous feedback loop. - * When triggered in auto mode, we simply enable AF for a limited number - * of frames (it may terminate early if the delta becomes small enough). + * Whenever PDAF is available (and reports sufficiently high confidence), + * it is used for continuous feedback control of the lens position. When + * triggered in Auto mode, we enable the loop for a limited number of frames + * (it may terminate sooner if the phase becomes small). In CAF mode, the + * PDAF loop runs continuously. Very small lens movements are suppressed. * * When PDAF confidence is low (due e.g. to low contrast or extreme defocus) * or PDAF data are absent, fall back to CDAF with a programmed scan pattern. - * A coarse and fine scan are performed, using ISP's CDAF focus FoM to - * estimate the lens position with peak contrast. This is slower due to - * extra latency in the ISP, and requires a settling time between steps. + * A coarse and fine scan are performed, using the ISP's CDAF contrast FoM + * to estimate the lens position with peak contrast. (This is slower due to + * extra latency in the ISP, and requires a settling time between steps.) + * The scan may terminate early if PDAF recovers and allows the zero-phase + * lens position to be interpolated. * - * Some hysteresis is applied to the switch between PDAF and CDAF, to avoid - * "nuisance" scans. During each interval where PDAF is not working, only - * ONE scan will be performed; CAF cannot track objects using CDAF alone. + * In CAF mode, the fallback to a CDAF scan is triggered when PDAF fails to + * report high confidence and a configurable number of frames have elapsed + * since the last image change since either PDAF was working or a previous + * scan found peak contrast. Image changes are detected using both contrast + * and AWB statistics (within the AF window[s]). * + * IR lighting can interfere with the correct operation of PDAF, so we + * optionally try to detect it (from AWB statistics). */ namespace RPiController { @@ -85,6 +93,8 @@ private: double stepCoarse; /* used for scans */ double stepFine; /* used for scans */ double contrastRatio; /* used for scan termination and reporting */ + double retriggerRatio; /* contrast and RGB ratio for re-triggering */ + uint32_t retriggerDelay; /* frames of stability before re-triggering */ double pdafGain; /* coefficient for PDAF feedback loop */ double pdafSquelch; /* PDAF stability parameter (device-specific) */ double maxSlew; /* limit for lens movement per frame */ @@ -103,6 +113,7 @@ private: uint32_t confThresh; /* PDAF confidence cell min (sensor-specific) */ uint32_t confClip; /* PDAF confidence cell max (sensor-specific) */ uint32_t skipFrames; /* frames to skip at start or modeswitch */ + bool checkForIR; /* Set this if PDAF is unreliable in IR light */ libcamera::ipa::Pwl map; /* converts dioptres -> lens driver position */ CfgParams(); @@ -131,6 +142,7 @@ private: void invalidateWeights(); bool getPhase(PdafRegions const ®ions, double &phase, double &conf); double getContrast(const FocusRegions &focusStats); + bool getAverageAndTestIr(const RgbyRegions &awbStats, double rgb[3]); void doPDAF(double phase, double conf); bool earlyTerminationByPhase(double phase); double findPeak(unsigned index) const; @@ -152,15 +164,18 @@ private: bool useWindows_; RegionWeights phaseWeights_; RegionWeights contrastWeights_; + RegionWeights awbWeights_; /* Working state. */ ScanState scanState_; - bool initted_; + bool initted_, irFlag_; double ftarget_, fsmooth_; - double prevContrast_; + double prevContrast_, oldSceneContrast_; + double prevAverage_[3], oldSceneAverage_[3]; double prevPhase_; unsigned skipCount_, stepCount_, dropCount_; unsigned sameSignCount_; + unsigned sceneChangeCount_; unsigned scanMaxIndex_; double scanMaxContrast_, scanMinContrast_; std::vector scanData_; From patchwork Fri Jun 20 12:42:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23615 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 D02F9BDE6B for ; Fri, 20 Jun 2025 12:45:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BF30D68E01; Fri, 20 Jun 2025 14:45:16 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="CIVsR3pT"; dkim-atps=neutral Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4985C68DF0 for ; Fri, 20 Jun 2025 14:45:02 +0200 (CEST) Received: by mail-wr1-x432.google.com with SMTP id ffacd0b85a97d-3a577f164c8so288300f8f.2 for ; Fri, 20 Jun 2025 05:45:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423502; x=1751028302; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=KWje5sBJ8QU0mBeCf3VYQD9sRSW4DAtdZgufgu9drJU=; b=CIVsR3pTTggLjpouEUuzmNwgjZGWZ6AJ3/6idIHYQ4x8Avj0KBW/lqTlz4tiO1f1hH unfnCl5hTj56uazE077J6O5pvPMnSeNrxSepWIGyAeTDd7PxmVvcbO/sd3fXwAhpuULy BuMQR8Iku5b5Th2L6XX6IH5xBBi7TWtppbYO0GiGsi0hZnt388eqY1AY+6RndmVPU6Y7 mGlZ37WJhMHPhD7cr5IsGxDfmBPPeFQVctZ38yt007OVXKctiTr3r+shMWFltW1s409f up6ImGot5FyPfm58pDONIa751pt9AHPcMs9uYp5tFrwV9KS4Lp3GWTY2IWO906SObg8Q T20g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423502; x=1751028302; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KWje5sBJ8QU0mBeCf3VYQD9sRSW4DAtdZgufgu9drJU=; b=bMBHi08bZTAJYelDgbOE9MPwg6j4t/AXWLtHPA7UYIgDiPn5/7+Cyplmv0dDWDl0dl IaF3CvQFvbwdKWQR5riV17xHzTH4lrcqqi5Zth+5kivqioe+Rz1ZKv4FktUphgTo0p+R 3zs8W/HTk9beWT7wRkMfGJdMCXQLcY7/yNbipZRun2N5X70m8elogJrkgoP542A8tmYa 78wWMzy3x6RFkZohUUVAGCGpgPbSVOHFOhqMUwkJZUgeaAVtFMCx+/k5Z79q1DEHizEn TEKgyS4p+hxKdZ/YMnelpFKtXiqhskU3DFh0hyHXoCVE4+ooAGCNRvw4oyj2YY7xVu6U aOJQ== X-Gm-Message-State: AOJu0Yx2NX+yyZiGAiyEMPrhuih0lYNGoTKJr2wzqi1IM4wENYPtw9ge nKGvjvSPiytrNRUh1zj8Mon36WWu4GzCr30Cn6n0mzsWgyIoEGU9wweJbZDZwDGr0p9gOdlU0sw cTsbI X-Gm-Gg: ASbGncuT6/t83MRBVILeCvrWvOmcP1q/CtJntU7C5dzFctt7mqSKa70ii3llYEmato5 +jzNb2x5jXA0ijk6tFpOBN6YCibfjHo7DBuAUQO0hToVl1h37aNv8GlzDi9/R374YQ7lxs7Uc/d cyJzVde8khZFr9gD5gGXhso25Nl5SQH9SUuwCN1i1t2SXpQ/PXauWVij7rW2+sMfpxFsPC44yW5 sPsyDVapID+knRG0JFZ1pw07UKnB9ixerS2teqByyObOu7vOPl4a72hLtPi47e5IjYjLBEFhY0o YQvbs36ZWu84tW4iew4Cm2wnikt4pK0ln1mv21djPgUX8m/rpv6EAv4oOKF0Flb0cUmi0YCpvTT 39I5fBA== X-Google-Smtp-Source: AGHT+IEVkEHsgfVFjJkozYT/AL6UaYdLLn8b7+QJL8QWOK+kgxzXG1a0CGqxRAXLtMHmklxlvlw8EA== X-Received: by 2002:a05:600c:1d02:b0:450:d4b4:92d0 with SMTP id 5b1f17b1804b1-453653c105emr9273005e9.3.1750423501409; Fri, 20 Jun 2025 05:45:01 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.45.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:45:01 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 7/8] ipa: rpi: controller: AutoFocus bidirectional scanning Date: Fri, 20 Jun 2025 13:42:28 +0100 Message-ID: <20250620124452.557855-8-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst To reduce unnecessary lens movements, allow the CDAF-based search procedure to start from either end of the range; or if not near an end, from the current lens position. This sometimes requires a second coarse scan, if the first one started in the middle and did not find peak contrast. Shorten the fine scan from 5 steps to 3 steps; allow fine scan to be omitted altogether when "step_fine": 0 in the tuning file. Move updateLensPosition() out of startProgrammedScan() to avoid calling it more than once per iteration. Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/controller/rpi/af.cpp | 97 ++++++++++++++++++++----------- src/ipa/rpi/controller/rpi/af.h | 9 +-- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 4396420a0277..eaaca4bc9d7a 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -200,6 +200,7 @@ Af::Af(Controller *controller) sceneChangeCount_(0), scanMaxContrast_(0.0), scanMinContrast_(1.0e9), + scanStep_(0.0), scanData_(), reportState_(AfState::Idle) { @@ -251,13 +252,14 @@ void Af::switchMode(CameraMode const &cameraMode, [[maybe_unused]] Metadata *met << statsRegion_.height; invalidateWeights(); - if (scanState_ >= ScanState::Coarse && scanState_ < ScanState::Settle) { + if (scanState_ >= ScanState::Coarse1 && scanState_ < ScanState::Settle) { /* * If a scan was in progress, re-start it, as CDAF statistics * may have changed. Though if the application is just about * to take a still picture, this will not help... */ startProgrammedScan(); + updateLensPosition(); } skipCount_ = cfg_.skipFrames; } @@ -543,31 +545,42 @@ void Af::doScan(double contrast, double phase, double conf) scanMinContrast_ = contrast; scanData_.emplace_back(ScanRecord{ ftarget_, contrast, phase, conf }); - if (scanState_ == ScanState::Coarse) { - if (ftarget_ >= cfg_.ranges[range_].focusMax || - contrast < cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) { - /* - * Finished course scan, or termination based on contrast. - * Jump to just after max contrast and start fine scan. - */ - ftarget_ = std::min(ftarget_, findPeak(scanMaxIndex_) + - 2.0 * cfg_.speeds[speed_].stepFine); - scanState_ = ScanState::Fine; - scanData_.clear(); - } else - ftarget_ += cfg_.speeds[speed_].stepCoarse; - } else { /* ScanState::Fine */ - if (ftarget_ <= cfg_.ranges[range_].focusMin || scanData_.size() >= 5 || - contrast < cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) { - /* - * Finished fine scan, or termination based on contrast. - * Use quadratic peak-finding to find best contrast position. - */ - ftarget_ = findPeak(scanMaxIndex_); + if ((scanStep_ >= 0.0 && ftarget_ >= cfg_.ranges[range_].focusMax) || + (scanStep_ <= 0.0 && ftarget_ <= cfg_.ranges[range_].focusMin) || + (scanState_ == ScanState::Fine && scanData_.size() >= 3) || + contrast < cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) { + double pk = findPeak(scanMaxIndex_); + /* + * Finished a scan, by hitting a limit or due to constrast dropping off. + * If this is a first coarse scan and we didn't bracket the peak, reverse! + * If this is a fine scan, or no fine step was defined, we've finished. + * Otherwise, start fine scan in opposite direction. + */ + if (scanState_ == ScanState::Coarse1 && + scanData_[0].contrast >= cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) { + scanStep_ = -scanStep_; + scanState_ = ScanState::Coarse2; + } else if (scanState_ == ScanState::Fine || cfg_.speeds[speed_].stepFine <= 0.0) { + ftarget_ = pk; scanState_ = ScanState::Settle; - } else - ftarget_ -= cfg_.speeds[speed_].stepFine; - } + } else if (scanState_ == ScanState::Coarse1 && + scanData_[0].contrast >= cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) { + scanStep_ = -scanStep_; + scanState_ = ScanState::Coarse2; + } else if (scanStep_ >= 0.0) { + ftarget_ = std::min(pk + cfg_.speeds[speed_].stepFine, + cfg_.ranges[range_].focusMax); + scanStep_ = -cfg_.speeds[speed_].stepFine; + scanState_ = ScanState::Fine; + } else { + ftarget_ = std::max(pk - cfg_.speeds[speed_].stepFine, + cfg_.ranges[range_].focusMin); + scanStep_ = cfg_.speeds[speed_].stepFine; + scanState_ = ScanState::Fine; + } + scanData_.clear(); + } else + ftarget_ += scanStep_; stepCount_ = (ftarget_ == fsmooth_) ? 0 : cfg_.speeds[speed_].stepFrames; } @@ -622,7 +635,7 @@ void Af::doAF(double contrast, double phase, double conf) /* else fall through to waiting for a scene change */ } } - if (scanState_ < ScanState::Coarse && mode_ == AfModeContinuous) { + if (scanState_ < ScanState::Coarse1 && mode_ == AfModeContinuous) { /* * In CAF mode, not in a scan, and PDAF is unavailable. * Wait for a scene change, followed by stability. @@ -642,7 +655,7 @@ void Af::doAF(double contrast, double phase, double conf) sceneChangeCount_++; if (sceneChangeCount_ >= cfg_.speeds[speed_].retriggerDelay) startProgrammedScan(); - } else if (scanState_ >= ScanState::Coarse && fsmooth_ == ftarget_) { + } else if (scanState_ >= ScanState::Coarse1 && fsmooth_ == ftarget_) { /* * CDAF-based scanning sequence. * Allow a delay between steps for CDAF FoM statistics to be @@ -714,15 +727,27 @@ void Af::startAF() oldSceneContrast_ = 0.0; sceneChangeCount_ = 0; reportState_ = AfState::Scanning; - } else + } else { startProgrammedScan(); + updateLensPosition(); + } } void Af::startProgrammedScan() { - ftarget_ = cfg_.ranges[range_].focusMin; - updateLensPosition(); - scanState_ = ScanState::Coarse; + if (!initted_ || mode_ != AfModeContinuous || + fsmooth_ <= cfg_.ranges[range_].focusMin + 2.0 * cfg_.speeds[speed_].stepCoarse) { + ftarget_ = cfg_.ranges[range_].focusMin; + scanStep_ = cfg_.speeds[speed_].stepCoarse; + scanState_ = ScanState::Coarse2; + } else if (fsmooth_ >= cfg_.ranges[range_].focusMax - 2.0 * cfg_.speeds[speed_].stepCoarse) { + ftarget_ = cfg_.ranges[range_].focusMax; + scanStep_ = -cfg_.speeds[speed_].stepCoarse; + scanState_ = ScanState::Coarse2; + } else { + scanStep_ = -cfg_.speeds[speed_].stepCoarse; + scanState_ = ScanState::Coarse1; + } scanMaxContrast_ = 0.0; scanMinContrast_ = 1.0e9; scanMaxIndex_ = 0; @@ -785,7 +810,9 @@ void Af::prepare(Metadata *imageMetadata) else status.pauseState = AfPauseState::Running; - if (mode_ == AfModeAuto && scanState_ != ScanState::Idle) + if (scanState_ == ScanState::Idle) + status.state = AfState::Idle; + else if (mode_ == AfModeAuto) status.state = AfState::Scanning; else status.state = reportState_; @@ -907,7 +934,7 @@ void Af::setMode(AfAlgorithm::AfMode mode) pauseFlag_ = false; if (mode == AfModeContinuous) scanState_ = ScanState::Trigger; - else if (mode != AfModeAuto || scanState_ < ScanState::Coarse) + else if (mode != AfModeAuto || scanState_ < ScanState::Coarse1) goIdle(); } } @@ -923,11 +950,11 @@ void Af::pause(AfAlgorithm::AfPause pause) if (mode_ == AfModeContinuous) { if (pause == AfPauseResume && pauseFlag_) { pauseFlag_ = false; - if (scanState_ < ScanState::Coarse) + if (scanState_ < ScanState::Coarse1) scanState_ = ScanState::Trigger; } else if (pause != AfPauseResume && !pauseFlag_) { pauseFlag_ = true; - if (pause == AfPauseImmediate || scanState_ < ScanState::Coarse) + if (pause == AfPauseImmediate || scanState_ < ScanState::Coarse1) goIdle(); } } diff --git a/src/ipa/rpi/controller/rpi/af.h b/src/ipa/rpi/controller/rpi/af.h index e1700f998f29..d35a39d12049 100644 --- a/src/ipa/rpi/controller/rpi/af.h +++ b/src/ipa/rpi/controller/rpi/af.h @@ -75,7 +75,8 @@ private: Idle = 0, Trigger, Pdaf, - Coarse, + Coarse1, + Coarse2, Fine, Settle }; @@ -90,8 +91,8 @@ private: }; struct SpeedDependentParams { - double stepCoarse; /* used for scans */ - double stepFine; /* used for scans */ + double stepCoarse; /* in dioptres; used for scans */ + double stepFine; /* in dioptres; used for scans */ double contrastRatio; /* used for scan termination and reporting */ double retriggerRatio; /* contrast and RGB ratio for re-triggering */ uint32_t retriggerDelay; /* frames of stability before re-triggering */ @@ -177,7 +178,7 @@ private: unsigned sameSignCount_; unsigned sceneChangeCount_; unsigned scanMaxIndex_; - double scanMaxContrast_, scanMinContrast_; + double scanMaxContrast_, scanMinContrast_, scanStep_; std::vector scanData_; AfState reportState_; }; From patchwork Fri Jun 20 12:42:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 23616 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 67461BDE6B for ; Fri, 20 Jun 2025 12:45:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AD83E68DF7; Fri, 20 Jun 2025 14:45:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="EASE5bnp"; dkim-atps=neutral Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DA44B68DD0 for ; Fri, 20 Jun 2025 14:45:02 +0200 (CEST) Received: by mail-wr1-x434.google.com with SMTP id ffacd0b85a97d-3a577f164c8so288304f8f.2 for ; Fri, 20 Jun 2025 05:45:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1750423502; x=1751028302; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=UE9g7xzDCM3KeDeKQb1yKv5x19VC4Pck1UyFswYi0Zs=; b=EASE5bnpaRIiB7zleAvejiT7CiPCdODay0Tl7JV2ckzLEmBdlXhz7GZRjo/3gAeoN4 H0nEud7YlPwnzjyNM+KlLnwtqPhoFNdJYm41/ilVCnktLJexQIsvwtG8fuKGB9Nm2P+6 HbsyL1mu7asZNwWDrVHdFmBSYowr6HDnzY8VywcPGY0dHrFI1zvWW71jIOibgeuXtIyy cIgai2BdqGnlMQnEhPnuXD4auJOjY6AigekHQz8i3lBhy+Wz2QXhkAXMOTFuo+fWbBg2 LSZr28y+fajPdk63eX07hWINDiamrfe94SR8JuVm81eehKzmE3gj06eccITOgNsDw407 iHiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750423502; x=1751028302; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UE9g7xzDCM3KeDeKQb1yKv5x19VC4Pck1UyFswYi0Zs=; b=NkTiJD2+r+gKaP9VcGdyqG2n9RLCnp/TztJUf0Z6lvjnYdbmfMPdYPZ6O6XJRVeiyq yBupcoW25cWnNz6rtUp3iBghsjEgPGanRSRji2AIGSiMCCcp3qOm4Nn/cEpcypCO/y5x ElElh8Wi9qrMRwXyDqQRTogMZMrkBc1IuVZJ8onTK0u92UUc7lxRwd2XFgWMJZyrZt77 laj7HaqDpcSr3GlLlvYDMFtdCzXKRoERYiJooBEtY5tl2YTudkxfdpkLnBRv0qM9+io0 lsTUZFx3Lec9iw11A/AAjpEsv5oGeqK7FCJNoxaDo95gJGhDN9LqX+g+AxQ4g1P3TyPM kZ/g== X-Gm-Message-State: AOJu0YwW7AFGqjgw2xtykrLaReXuENh+/YtmzH1DNmS4SRU+JAiOERzF 8S/kBU+zcnz3VwB3/+HWcyXbMccV8zux8v2h0vFmV3/cZg5HpxntxwcetRiQKxDs6zvMeN9lAET sCQ0F X-Gm-Gg: ASbGncvUwRf8t8q1bqpfnl8YcqHrPuugKkcjrQd69unUSn/6P1+PH8p1RfEUna6SEKs 53CQK+qU4FECeLHZWkXqUW9jw36z7IV4N9FK6wi/ClETXmShbHAZNsWmD8T/AFvQZux4vpNZe9H 9D9A0Jyx1sjzF5y8x+rmXtZ4uuyHhQ3/sywybd/qSxLEmeAqiN4xfPRpEf1feZKAd7d9ti7xQ7M jx2sJ5SETuO2CzAZUwHxNGIIlL+y3UCI8Gys0noy+fKtCyrlW9bKHcHFVGYqlPDJvY6Hm5nDWtA 9Zq9g8C4GMBUFzhbuHDarZUvuza8plPsMzIP3tWzHxXkFA2tw2q8HCNF2EDaRmmukkGM1LO0EOc BX7K6mA== X-Google-Smtp-Source: AGHT+IH4aaN35RGrYO17rGe5UzPbLEfJcXK7eKeFRurH70TCfPW7MO7nd6PkIXr4+6YJWzXP4nUdGw== X-Received: by 2002:a05:6000:2906:b0:3a5:2208:41b6 with SMTP id ffacd0b85a97d-3a6d12dde9cmr940417f8f.11.1750423502010; Fri, 20 Jun 2025 05:45:02 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45361461375sm41561525e9.14.2025.06.20.05.45.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jun 2025 05:45:01 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Nick Hollinghurst , Naushir Patuck Subject: [PATCH v1 8/8] ipa: rpi: Update IMX708 camera tuning files for AutoFocus changes Date: Fri, 20 Jun 2025 13:42:29 +0100 Message-ID: <20250620124452.557855-9-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250620124452.557855-1-naush@raspberrypi.com> References: <20250620124452.557855-1-naush@raspberrypi.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" From: Nick Hollinghurst Explicitly add new parameters: "retrigger_ratio", "retrigger_delay", "check_for_ir". Tweak other parameters to suit algorithm changes. (Though existing tuning files should still work acceptably.) Add AfSpeedFast parameters for the Raspberry Pi V3 standard lens. Signed-off-by: Nick Hollinghurst Signed-off-by: Naushir Patuck Reviewed-by: Naushir Patuck --- src/ipa/rpi/pisp/data/imx708.json | 23 ++++++++++++++++++--- src/ipa/rpi/pisp/data/imx708_noir.json | 23 ++++++++++++++++++--- src/ipa/rpi/pisp/data/imx708_wide.json | 19 ++++++++++------- src/ipa/rpi/pisp/data/imx708_wide_noir.json | 19 ++++++++++------- src/ipa/rpi/vc4/data/imx708.json | 23 ++++++++++++++++++--- src/ipa/rpi/vc4/data/imx708_noir.json | 23 ++++++++++++++++++--- src/ipa/rpi/vc4/data/imx708_wide.json | 19 ++++++++++------- src/ipa/rpi/vc4/data/imx708_wide_noir.json | 19 ++++++++++------- 8 files changed, 128 insertions(+), 40 deletions(-) diff --git a/src/ipa/rpi/pisp/data/imx708.json b/src/ipa/rpi/pisp/data/imx708.json index e8d25c216025..7f2e786550b8 100644 --- a/src/ipa/rpi/pisp/data/imx708.json +++ b/src/ipa/rpi/pisp/data/imx708.json @@ -1139,11 +1139,27 @@ "step_coarse": 1.0, "step_fine": 0.25, "contrast_ratio": 0.75, - "pdaf_gain": -0.02, + "retrigger_ratio": 0.8, + "retrigger_delay": 10, + "pdaf_gain": -0.016, "pdaf_squelch": 0.125, - "max_slew": 2.0, + "max_slew": 1.5, "pdaf_frames": 20, "dropout_frames": 6, + "step_frames": 5 + }, + "fast": + { + "step_coarse": 1.25, + "step_fine": 0.0, + "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 8, + "pdaf_gain": -0.02, + "pdaf_squelch": 0.125, + "max_slew": 2.0, + "pdaf_frames": 16, + "dropout_frames": 4, "step_frames": 4 } }, @@ -1151,6 +1167,7 @@ "conf_thresh": 16, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": false, "map": [ 0.0, 445, 15.0, 925 ] } }, @@ -1267,4 +1284,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/ipa/rpi/pisp/data/imx708_noir.json b/src/ipa/rpi/pisp/data/imx708_noir.json index e69afb0c6d64..c5e6a2652727 100644 --- a/src/ipa/rpi/pisp/data/imx708_noir.json +++ b/src/ipa/rpi/pisp/data/imx708_noir.json @@ -1156,11 +1156,27 @@ "step_coarse": 1.0, "step_fine": 0.25, "contrast_ratio": 0.75, - "pdaf_gain": -0.02, + "retrigger_ratio": 0.8, + "retrigger_delay": 10, + "pdaf_gain": -0.016, "pdaf_squelch": 0.125, - "max_slew": 2.0, + "max_slew": 1.5, "pdaf_frames": 20, "dropout_frames": 6, + "step_frames": 5 + }, + "fast": + { + "step_coarse": 1.25, + "step_fine": 0.0, + "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 8, + "pdaf_gain": -0.02, + "pdaf_squelch": 0.125, + "max_slew": 2.0, + "pdaf_frames": 16, + "dropout_frames": 4, "step_frames": 4 } }, @@ -1168,6 +1184,7 @@ "conf_thresh": 16, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": true, "map": [ 0.0, 445, 15.0, 925 ] } }, @@ -1230,4 +1247,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/ipa/rpi/pisp/data/imx708_wide.json b/src/ipa/rpi/pisp/data/imx708_wide.json index 9fff05d93efa..8550cdfc1db0 100644 --- a/src/ipa/rpi/pisp/data/imx708_wide.json +++ b/src/ipa/rpi/pisp/data/imx708_wide.json @@ -1148,23 +1148,27 @@ "step_coarse": 2.0, "step_fine": 0.5, "contrast_ratio": 0.75, + "retrigger_ratio" : 0.8, + "retrigger_delay" : 10, "pdaf_gain": -0.03, "pdaf_squelch": 0.2, - "max_slew": 4.0, + "max_slew": 3.0, "pdaf_frames": 20, "dropout_frames": 6, - "step_frames": 4 + "step_frames": 5 }, "fast": { - "step_coarse": 2.0, - "step_fine": 0.5, + "step_coarse": 2.5, + "step_fine": 0.0, "contrast_ratio": 0.75, + "retrigger_ratio" : 0.8, + "retrigger_delay" : 8, "pdaf_gain": -0.05, "pdaf_squelch": 0.2, - "max_slew": 5.0, + "max_slew": 4.0, "pdaf_frames": 16, - "dropout_frames": 6, + "dropout_frames": 4, "step_frames": 4 } }, @@ -1172,6 +1176,7 @@ "conf_thresh": 12, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": false, "map": [ 0.0, 420, 35.0, 920 ] } }, @@ -1290,4 +1295,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/ipa/rpi/pisp/data/imx708_wide_noir.json b/src/ipa/rpi/pisp/data/imx708_wide_noir.json index 75d1149b6d3e..069a06180320 100644 --- a/src/ipa/rpi/pisp/data/imx708_wide_noir.json +++ b/src/ipa/rpi/pisp/data/imx708_wide_noir.json @@ -1057,23 +1057,27 @@ "step_coarse": 2.0, "step_fine": 0.5, "contrast_ratio": 0.75, + "retrigger_ratio" : 0.8, + "retrigger_delay" : 10, "pdaf_gain": -0.03, "pdaf_squelch": 0.2, - "max_slew": 4.0, + "max_slew": 3.0, "pdaf_frames": 20, "dropout_frames": 6, - "step_frames": 4 + "step_frames": 5 }, "fast": { - "step_coarse": 2.0, - "step_fine": 0.5, + "step_coarse": 2.5, + "step_fine": 0.0, "contrast_ratio": 0.75, + "retrigger_ratio" : 0.8, + "retrigger_delay" : 8, "pdaf_gain": -0.05, "pdaf_squelch": 0.2, - "max_slew": 5.0, + "max_slew": 4.0, "pdaf_frames": 16, - "dropout_frames": 6, + "dropout_frames": 4, "step_frames": 4 } }, @@ -1081,6 +1085,7 @@ "conf_thresh": 12, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": true, "map": [ 0.0, 420, 35.0, 920 ] } }, @@ -1145,4 +1150,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/ipa/rpi/vc4/data/imx708.json b/src/ipa/rpi/vc4/data/imx708.json index 4de6f0796fd0..e54ceff494e5 100644 --- a/src/ipa/rpi/vc4/data/imx708.json +++ b/src/ipa/rpi/vc4/data/imx708.json @@ -638,11 +638,27 @@ "step_coarse": 1.0, "step_fine": 0.25, "contrast_ratio": 0.75, - "pdaf_gain": -0.02, + "retrigger_ratio": 0.8, + "retrigger_delay": 10, + "pdaf_gain": -0.016, "pdaf_squelch": 0.125, - "max_slew": 2.0, + "max_slew": 1.5, "pdaf_frames": 20, "dropout_frames": 6, + "step_frames": 5 + }, + "fast": + { + "step_coarse": 1.25, + "step_fine": 0.0, + "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 8, + "pdaf_gain": -0.02, + "pdaf_squelch": 0.125, + "max_slew": 2.0, + "pdaf_frames": 16, + "dropout_frames": 4, "step_frames": 4 } }, @@ -650,6 +666,7 @@ "conf_thresh": 16, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": false, "map": [ 0.0, 445, 15.0, 925 ] } }, @@ -668,4 +685,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/ipa/rpi/vc4/data/imx708_noir.json b/src/ipa/rpi/vc4/data/imx708_noir.json index 7b7ee874f66a..f351a1800924 100644 --- a/src/ipa/rpi/vc4/data/imx708_noir.json +++ b/src/ipa/rpi/vc4/data/imx708_noir.json @@ -737,11 +737,27 @@ "step_coarse": 1.0, "step_fine": 0.25, "contrast_ratio": 0.75, - "pdaf_gain": -0.02, + "retrigger_ratio": 0.8, + "retrigger_delay": 10, + "pdaf_gain": -0.016, "pdaf_squelch": 0.125, - "max_slew": 2.0, + "max_slew": 1.5, "pdaf_frames": 20, "dropout_frames": 6, + "step_frames": 5 + }, + "fast": + { + "step_coarse": 1.25, + "step_fine": 0.0, + "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 8, + "pdaf_gain": -0.02, + "pdaf_squelch": 0.125, + "max_slew": 2.0, + "pdaf_frames": 16, + "dropout_frames": 4, "step_frames": 4 } }, @@ -749,6 +765,7 @@ "conf_thresh": 16, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": true, "map": [ 0.0, 445, 15.0, 925 ] } }, @@ -767,4 +784,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/ipa/rpi/vc4/data/imx708_wide.json b/src/ipa/rpi/vc4/data/imx708_wide.json index 6f45aafc0997..bf1b122cd7e6 100644 --- a/src/ipa/rpi/vc4/data/imx708_wide.json +++ b/src/ipa/rpi/vc4/data/imx708_wide.json @@ -637,23 +637,27 @@ "step_coarse": 2.0, "step_fine": 0.5, "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 10, "pdaf_gain": -0.03, "pdaf_squelch": 0.2, - "max_slew": 4.0, + "max_slew": 3.0, "pdaf_frames": 20, "dropout_frames": 6, - "step_frames": 4 + "step_frames": 5 }, "fast": { - "step_coarse": 2.0, - "step_fine": 0.5, + "step_coarse": 2.5, + "step_fine": 0.0, "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 8, "pdaf_gain": -0.05, "pdaf_squelch": 0.2, - "max_slew": 5.0, + "max_slew": 4.0, "pdaf_frames": 16, - "dropout_frames": 6, + "dropout_frames": 4, "step_frames": 4 } }, @@ -661,6 +665,7 @@ "conf_thresh": 12, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": false, "map": [ 0.0, 420, 35.0, 920 ] } }, @@ -679,4 +684,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/ipa/rpi/vc4/data/imx708_wide_noir.json b/src/ipa/rpi/vc4/data/imx708_wide_noir.json index b9a5227e1acc..ea1c8c690b5c 100644 --- a/src/ipa/rpi/vc4/data/imx708_wide_noir.json +++ b/src/ipa/rpi/vc4/data/imx708_wide_noir.json @@ -628,23 +628,27 @@ "step_coarse": 2.0, "step_fine": 0.5, "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 10, "pdaf_gain": -0.03, "pdaf_squelch": 0.2, - "max_slew": 4.0, + "max_slew": 3.0, "pdaf_frames": 20, "dropout_frames": 6, - "step_frames": 4 + "step_frames": 5 }, "fast": { - "step_coarse": 2.0, - "step_fine": 0.5, + "step_coarse": 2.5, + "step_fine": 0.0, "contrast_ratio": 0.75, + "retrigger_ratio": 0.8, + "retrigger_delay": 8, "pdaf_gain": -0.05, "pdaf_squelch": 0.2, - "max_slew": 5.0, + "max_slew": 4.0, "pdaf_frames": 16, - "dropout_frames": 6, + "dropout_frames": 4, "step_frames": 4 } }, @@ -652,6 +656,7 @@ "conf_thresh": 12, "conf_clip": 512, "skip_frames": 5, + "check_for_ir": true, "map": [ 0.0, 420, 35.0, 920 ] } }, @@ -670,4 +675,4 @@ } } ] -} \ No newline at end of file +}