114 lines
4.3 KiB
Diff
114 lines
4.3 KiB
Diff
|
|
From b99ba09cd463cbfbb6530a82c9e2702bfd0bb29a Mon Sep 17 00:00:00 2001
|
||
|
|
From: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
|
||
|
|
Date: Mon, 17 Aug 2026 02:18:32 +0200
|
||
|
|
Subject: [PATCH] libcamera: software_isp: af: Re-baseline the scene reference
|
||
|
|
after a sweep
|
||
|
|
|
||
|
|
Measured on the FP6 with the DW9784: a sweep converged on 38% with a
|
||
|
|
recorded maximum sharpness of 4848088, and two stats frames later the
|
||
|
|
metric at that same position read 1995445 - a 59% drop with the lens
|
||
|
|
parked and the scene unchanged. The sweep maximum was measured under
|
||
|
|
whatever exposure and gain the AGC happened to be using several hundred
|
||
|
|
milliseconds earlier, so comparing the settled scene against it fires
|
||
|
|
the focus-loss detector immediately and the lens sweeps forever.
|
||
|
|
|
||
|
|
Take the reference from the first measurement after the lens has
|
||
|
|
settled, and require the scene to look different for four consecutive
|
||
|
|
stats frames before re-focusing, so that a single AGC excursion does not
|
||
|
|
count as the scene changing.
|
||
|
|
|
||
|
|
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
|
||
|
|
---
|
||
|
|
src/ipa/simple/algorithms/af.cpp | 37 ++++++++++++++++++++++++++------
|
||
|
|
src/ipa/simple/ipa_context.h | 4 ++++
|
||
|
|
2 files changed, 35 insertions(+), 6 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/src/ipa/simple/algorithms/af.cpp b/src/ipa/simple/algorithms/af.cpp
|
||
|
|
index 00148ce1b..6c9510389 100644
|
||
|
|
--- a/src/ipa/simple/algorithms/af.cpp
|
||
|
|
+++ b/src/ipa/simple/algorithms/af.cpp
|
||
|
|
@@ -34,6 +34,8 @@ constexpr double kFineStepMin = 1.0;
|
||
|
|
constexpr uint32_t kSettleSkipLong = 3;
|
||
|
|
/* Relative sharpness change that makes a settled scene worth re-focusing. */
|
||
|
|
constexpr double kFocusLossThreshold = 0.3;
|
||
|
|
+/* Consecutive stats frames that change must persist for before re-focusing. */
|
||
|
|
+constexpr uint32_t kFocusLossFrames = 4;
|
||
|
|
/*
|
||
|
|
* Focus continuously by default: applications that know nothing about AF never
|
||
|
|
* send an AfMode or an AfTrigger, and they are the ones this exists for.
|
||
|
|
@@ -140,6 +142,8 @@ void Af::restart(IPAContext &context)
|
||
|
|
focus.stop = 100;
|
||
|
|
focus.step = kCoarseStep;
|
||
|
|
focus.skip = kSettleSkipLong;
|
||
|
|
+ focus.settled = false;
|
||
|
|
+ focus.lossCount = 0;
|
||
|
|
context.activeState.knobs.focus_pos = 0;
|
||
|
|
context.activeState.knobs.focus_sweep = true;
|
||
|
|
LOG(IPASoftAutoFocus, Info) << "Starting focus sweep";
|
||
|
|
@@ -165,13 +169,34 @@ void Af::step(IPAContext &context, double &focus_pos, uint64_t sharp, bool &swee
|
||
|
|
if (context.activeState.knobs.af_mode != controls::AfModeContinuous)
|
||
|
|
return;
|
||
|
|
|
||
|
|
- if (utils::abs_diff(sharp, focus.sharpness_max) >
|
||
|
|
+ /*
|
||
|
|
+ * Take the reference the scene is compared against here, at
|
||
|
|
+ * the settled position, rather than reusing the maximum found
|
||
|
|
+ * during the sweep: that maximum was measured under whatever
|
||
|
|
+ * exposure and gain the AGC happened to be using at the time.
|
||
|
|
+ */
|
||
|
|
+ if (!focus.settled) {
|
||
|
|
+ focus.sharpness_max = sharp;
|
||
|
|
+ focus.lossCount = 0;
|
||
|
|
+ focus.settled = true;
|
||
|
|
+ LOG(IPASoftAutoFocus, Debug)
|
||
|
|
+ << "Settled sharpness reference " << sharp;
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (utils::abs_diff(sharp, focus.sharpness_max) <=
|
||
|
|
focus.sharpness_max * kFocusLossThreshold) {
|
||
|
|
- LOG(IPASoftAutoFocus, Info)
|
||
|
|
- << "Focus lost: " << sharp << " vs "
|
||
|
|
- << focus.sharpness_max;
|
||
|
|
- restart(context);
|
||
|
|
+ focus.lossCount = 0;
|
||
|
|
+ return;
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ if (++focus.lossCount < kFocusLossFrames)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ LOG(IPASoftAutoFocus, Info)
|
||
|
|
+ << "Focus lost: " << sharp << " vs "
|
||
|
|
+ << focus.sharpness_max;
|
||
|
|
+ restart(context);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -204,10 +229,10 @@ void Af::step(IPAContext &context, double &focus_pos, uint64_t sharp, bool &swee
|
||
|
|
|
||
|
|
sweep = false;
|
||
|
|
focus_pos = focus.focus_max_pos;
|
||
|
|
+ focus.settled = false;
|
||
|
|
LOG(IPASoftAutoFocus, Info)
|
||
|
|
<< "Sweep end. Best focus: " << focus.focus_max_pos
|
||
|
|
<< " after " << steps_ << " frames";
|
||
|
|
- /* sharpness_max is kept to detect the scene changing later on. */
|
||
|
|
}
|
||
|
|
|
||
|
|
void Af::process(IPAContext &context,
|
||
|
|
diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h
|
||
|
|
index 4c594cd29..36a28256b 100644
|
||
|
|
--- a/src/ipa/simple/ipa_context.h
|
||
|
|
+++ b/src/ipa/simple/ipa_context.h
|
||
|
|
@@ -41,6 +41,10 @@ struct IPASessionConfiguration {
|
||
|
|
double start, stop, step;
|
||
|
|
/* Stats frames to ignore while the lens settles */
|
||
|
|
uint32_t skip;
|
||
|
|
+ /* Set once the post-sweep sharpness reference has been taken */
|
||
|
|
+ bool settled;
|
||
|
|
+ /* Consecutive stats frames the scene has looked different */
|
||
|
|
+ uint32_t lossCount;
|
||
|
|
} focus;
|
||
|
|
};
|
||
|
|
|