Skip to content

Commit 3b42893

Browse files
ipa: rpi: controller: AutoFocus bidirectional scanning
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 <nick.hollinghurst@raspberrypi.com>
1 parent 5c70b8b commit 3b42893

File tree

2 files changed

+67
-39
lines changed

2 files changed

+67
-39
lines changed

src/ipa/rpi/controller/rpi/af.cpp

Lines changed: 62 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ Af::Af(Controller *controller)
200200
sceneChangeCount_(0),
201201
scanMaxContrast_(0.0),
202202
scanMinContrast_(1.0e9),
203+
scanStep_(0.0),
203204
scanData_(),
204205
reportState_(AfState::Idle)
205206
{
@@ -251,13 +252,14 @@ void Af::switchMode(CameraMode const &cameraMode, [[maybe_unused]] Metadata *met
251252
<< statsRegion_.height;
252253
invalidateWeights();
253254

254-
if (scanState_ >= ScanState::Coarse && scanState_ < ScanState::Settle) {
255+
if (scanState_ >= ScanState::Coarse1 && scanState_ < ScanState::Settle) {
255256
/*
256257
* If a scan was in progress, re-start it, as CDAF statistics
257258
* may have changed. Though if the application is just about
258259
* to take a still picture, this will not help...
259260
*/
260261
startProgrammedScan();
262+
updateLensPosition();
261263
}
262264
skipCount_ = cfg_.skipFrames;
263265
}
@@ -543,31 +545,42 @@ void Af::doScan(double contrast, double phase, double conf)
543545
scanMinContrast_ = contrast;
544546
scanData_.emplace_back(ScanRecord{ ftarget_, contrast, phase, conf });
545547

546-
if (scanState_ == ScanState::Coarse) {
547-
if (ftarget_ >= cfg_.ranges[range_].focusMax ||
548-
contrast < cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) {
549-
/*
550-
* Finished course scan, or termination based on contrast.
551-
* Jump to just after max contrast and start fine scan.
552-
*/
553-
ftarget_ = std::min(ftarget_, findPeak(scanMaxIndex_) +
554-
2.0 * cfg_.speeds[speed_].stepFine);
555-
scanState_ = ScanState::Fine;
556-
scanData_.clear();
557-
} else
558-
ftarget_ += cfg_.speeds[speed_].stepCoarse;
559-
} else { /* ScanState::Fine */
560-
if (ftarget_ <= cfg_.ranges[range_].focusMin || scanData_.size() >= 5 ||
561-
contrast < cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) {
562-
/*
563-
* Finished fine scan, or termination based on contrast.
564-
* Use quadratic peak-finding to find best contrast position.
565-
*/
566-
ftarget_ = findPeak(scanMaxIndex_);
548+
if ((scanStep_ >= 0.0 && ftarget_ >= cfg_.ranges[range_].focusMax) ||
549+
(scanStep_ <= 0.0 && ftarget_ <= cfg_.ranges[range_].focusMin) ||
550+
(scanState_ == ScanState::Fine && scanData_.size() >= 3) ||
551+
contrast < cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) {
552+
double pk = findPeak(scanMaxIndex_);
553+
/*
554+
* Finished a scan, by hitting a limit or due to constrast dropping off.
555+
* If this is a first coarse scan and we didn't bracket the peak, reverse!
556+
* If this is a fine scan, or no fine step was defined, we've finished.
557+
* Otherwise, start fine scan in opposite direction.
558+
*/
559+
if (scanState_ == ScanState::Coarse1 &&
560+
scanData_[0].contrast >= cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) {
561+
scanStep_ = -scanStep_;
562+
scanState_ = ScanState::Coarse2;
563+
} else if (scanState_ == ScanState::Fine || cfg_.speeds[speed_].stepFine <= 0.0) {
564+
ftarget_ = pk;
567565
scanState_ = ScanState::Settle;
568-
} else
569-
ftarget_ -= cfg_.speeds[speed_].stepFine;
570-
}
566+
} else if (scanState_ == ScanState::Coarse1 &&
567+
scanData_[0].contrast >= cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) {
568+
scanStep_ = -scanStep_;
569+
scanState_ = ScanState::Coarse2;
570+
} else if (scanStep_ >= 0.0) {
571+
ftarget_ = std::min(pk + cfg_.speeds[speed_].stepFine,
572+
cfg_.ranges[range_].focusMax);
573+
scanStep_ = -cfg_.speeds[speed_].stepFine;
574+
scanState_ = ScanState::Fine;
575+
} else {
576+
ftarget_ = std::max(pk - cfg_.speeds[speed_].stepFine,
577+
cfg_.ranges[range_].focusMin);
578+
scanStep_ = cfg_.speeds[speed_].stepFine;
579+
scanState_ = ScanState::Fine;
580+
}
581+
scanData_.clear();
582+
} else
583+
ftarget_ += scanStep_;
571584

572585
stepCount_ = (ftarget_ == fsmooth_) ? 0 : cfg_.speeds[speed_].stepFrames;
573586
}
@@ -622,7 +635,7 @@ void Af::doAF(double contrast, double phase, double conf)
622635
/* else fall through to waiting for a scene change */
623636
}
624637
}
625-
if (scanState_ < ScanState::Coarse && mode_ == AfModeContinuous) {
638+
if (scanState_ < ScanState::Coarse1 && mode_ == AfModeContinuous) {
626639
/*
627640
* In CAF mode, not in a scan, and PDAF is unavailable.
628641
* Wait for a scene change, followed by stability.
@@ -642,7 +655,7 @@ void Af::doAF(double contrast, double phase, double conf)
642655
sceneChangeCount_++;
643656
if (sceneChangeCount_ >= cfg_.speeds[speed_].retriggerDelay)
644657
startProgrammedScan();
645-
} else if (scanState_ >= ScanState::Coarse && fsmooth_ == ftarget_) {
658+
} else if (scanState_ >= ScanState::Coarse1 && fsmooth_ == ftarget_) {
646659
/*
647660
* CDAF-based scanning sequence.
648661
* Allow a delay between steps for CDAF FoM statistics to be
@@ -714,15 +727,27 @@ void Af::startAF()
714727
oldSceneContrast_ = 0.0;
715728
sceneChangeCount_ = 0;
716729
reportState_ = AfState::Scanning;
717-
} else
730+
} else {
718731
startProgrammedScan();
732+
updateLensPosition();
733+
}
719734
}
720735

721736
void Af::startProgrammedScan()
722737
{
723-
ftarget_ = cfg_.ranges[range_].focusMin;
724-
updateLensPosition();
725-
scanState_ = ScanState::Coarse;
738+
if (!initted_ || mode_ != AfModeContinuous ||
739+
fsmooth_ <= cfg_.ranges[range_].focusMin + 2.0 * cfg_.speeds[speed_].stepCoarse) {
740+
ftarget_ = cfg_.ranges[range_].focusMin;
741+
scanStep_ = cfg_.speeds[speed_].stepCoarse;
742+
scanState_ = ScanState::Coarse2;
743+
} else if (fsmooth_ >= cfg_.ranges[range_].focusMax - 2.0 * cfg_.speeds[speed_].stepCoarse) {
744+
ftarget_ = cfg_.ranges[range_].focusMax;
745+
scanStep_ = -cfg_.speeds[speed_].stepCoarse;
746+
scanState_ = ScanState::Coarse2;
747+
} else {
748+
scanStep_ = -cfg_.speeds[speed_].stepCoarse;
749+
scanState_ = ScanState::Coarse1;
750+
}
726751
scanMaxContrast_ = 0.0;
727752
scanMinContrast_ = 1.0e9;
728753
scanMaxIndex_ = 0;
@@ -785,7 +810,9 @@ void Af::prepare(Metadata *imageMetadata)
785810
else
786811
status.pauseState = AfPauseState::Running;
787812

788-
if (mode_ == AfModeAuto && scanState_ != ScanState::Idle)
813+
if (scanState_ == ScanState::Idle)
814+
status.state = AfState::Idle;
815+
else if (mode_ == AfModeAuto)
789816
status.state = AfState::Scanning;
790817
else
791818
status.state = reportState_;
@@ -907,7 +934,7 @@ void Af::setMode(AfAlgorithm::AfMode mode)
907934
pauseFlag_ = false;
908935
if (mode == AfModeContinuous)
909936
scanState_ = ScanState::Trigger;
910-
else if (mode != AfModeAuto || scanState_ < ScanState::Coarse)
937+
else if (mode != AfModeAuto || scanState_ < ScanState::Coarse1)
911938
goIdle();
912939
}
913940
}
@@ -923,11 +950,11 @@ void Af::pause(AfAlgorithm::AfPause pause)
923950
if (mode_ == AfModeContinuous) {
924951
if (pause == AfPauseResume && pauseFlag_) {
925952
pauseFlag_ = false;
926-
if (scanState_ < ScanState::Coarse)
953+
if (scanState_ < ScanState::Coarse1)
927954
scanState_ = ScanState::Trigger;
928955
} else if (pause != AfPauseResume && !pauseFlag_) {
929956
pauseFlag_ = true;
930-
if (pause == AfPauseImmediate || scanState_ < ScanState::Coarse)
957+
if (pause == AfPauseImmediate || scanState_ < ScanState::Coarse1)
931958
goIdle();
932959
}
933960
}

src/ipa/rpi/controller/rpi/af.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ class Af : public AfAlgorithm
7575
Idle = 0,
7676
Trigger,
7777
Pdaf,
78-
Coarse,
78+
Coarse1,
79+
Coarse2,
7980
Fine,
8081
Settle
8182
};
@@ -90,8 +91,8 @@ class Af : public AfAlgorithm
9091
};
9192

9293
struct SpeedDependentParams {
93-
double stepCoarse; /* used for scans */
94-
double stepFine; /* used for scans */
94+
double stepCoarse; /* in dioptres; used for scans */
95+
double stepFine; /* in dioptres; used for scans */
9596
double contrastRatio; /* used for scan termination and reporting */
9697
double retriggerRatio; /* contrast and RGB ratio for re-triggering */
9798
uint32_t retriggerDelay; /* frames of stability before re-triggering */
@@ -177,7 +178,7 @@ class Af : public AfAlgorithm
177178
unsigned sameSignCount_;
178179
unsigned sceneChangeCount_;
179180
unsigned scanMaxIndex_;
180-
double scanMaxContrast_, scanMinContrast_;
181+
double scanMaxContrast_, scanMinContrast_, scanStep_;
181182
std::vector<ScanRecord> scanData_;
182183
AfState reportState_;
183184
};

0 commit comments

Comments
 (0)