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> Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: Naushir Patuck <naush@raspberrypi.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
parent
686f88707c
commit
ea5f451c56
2 changed files with 67 additions and 39 deletions
|
@ -200,6 +200,7 @@ Af::Af(Controller *controller)
|
||||||
sceneChangeCount_(0),
|
sceneChangeCount_(0),
|
||||||
scanMaxContrast_(0.0),
|
scanMaxContrast_(0.0),
|
||||||
scanMinContrast_(1.0e9),
|
scanMinContrast_(1.0e9),
|
||||||
|
scanStep_(0.0),
|
||||||
scanData_(),
|
scanData_(),
|
||||||
reportState_(AfState::Idle)
|
reportState_(AfState::Idle)
|
||||||
{
|
{
|
||||||
|
@ -251,13 +252,14 @@ void Af::switchMode(CameraMode const &cameraMode, [[maybe_unused]] Metadata *met
|
||||||
<< statsRegion_.height;
|
<< statsRegion_.height;
|
||||||
invalidateWeights();
|
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
|
* If a scan was in progress, re-start it, as CDAF statistics
|
||||||
* may have changed. Though if the application is just about
|
* may have changed. Though if the application is just about
|
||||||
* to take a still picture, this will not help...
|
* to take a still picture, this will not help...
|
||||||
*/
|
*/
|
||||||
startProgrammedScan();
|
startProgrammedScan();
|
||||||
|
updateLensPosition();
|
||||||
}
|
}
|
||||||
skipCount_ = cfg_.skipFrames;
|
skipCount_ = cfg_.skipFrames;
|
||||||
}
|
}
|
||||||
|
@ -543,31 +545,42 @@ void Af::doScan(double contrast, double phase, double conf)
|
||||||
scanMinContrast_ = contrast;
|
scanMinContrast_ = contrast;
|
||||||
scanData_.emplace_back(ScanRecord{ ftarget_, contrast, phase, conf });
|
scanData_.emplace_back(ScanRecord{ ftarget_, contrast, phase, conf });
|
||||||
|
|
||||||
if (scanState_ == ScanState::Coarse) {
|
if ((scanStep_ >= 0.0 && ftarget_ >= cfg_.ranges[range_].focusMax) ||
|
||||||
if (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_) {
|
contrast < cfg_.speeds[speed_].contrastRatio * scanMaxContrast_) {
|
||||||
|
double pk = findPeak(scanMaxIndex_);
|
||||||
/*
|
/*
|
||||||
* Finished course scan, or termination based on contrast.
|
* Finished a scan, by hitting a limit or due to constrast dropping off.
|
||||||
* Jump to just after max contrast and start fine scan.
|
* 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.
|
||||||
*/
|
*/
|
||||||
ftarget_ = std::min(ftarget_, findPeak(scanMaxIndex_) +
|
if (scanState_ == ScanState::Coarse1 &&
|
||||||
2.0 * cfg_.speeds[speed_].stepFine);
|
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 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;
|
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();
|
scanData_.clear();
|
||||||
} else
|
} else
|
||||||
ftarget_ += cfg_.speeds[speed_].stepCoarse;
|
ftarget_ += scanStep_;
|
||||||
} 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_);
|
|
||||||
scanState_ = ScanState::Settle;
|
|
||||||
} else
|
|
||||||
ftarget_ -= cfg_.speeds[speed_].stepFine;
|
|
||||||
}
|
|
||||||
|
|
||||||
stepCount_ = (ftarget_ == fsmooth_) ? 0 : cfg_.speeds[speed_].stepFrames;
|
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 */
|
/* 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.
|
* In CAF mode, not in a scan, and PDAF is unavailable.
|
||||||
* Wait for a scene change, followed by stability.
|
* Wait for a scene change, followed by stability.
|
||||||
|
@ -642,7 +655,7 @@ void Af::doAF(double contrast, double phase, double conf)
|
||||||
sceneChangeCount_++;
|
sceneChangeCount_++;
|
||||||
if (sceneChangeCount_ >= cfg_.speeds[speed_].retriggerDelay)
|
if (sceneChangeCount_ >= cfg_.speeds[speed_].retriggerDelay)
|
||||||
startProgrammedScan();
|
startProgrammedScan();
|
||||||
} else if (scanState_ >= ScanState::Coarse && fsmooth_ == ftarget_) {
|
} else if (scanState_ >= ScanState::Coarse1 && fsmooth_ == ftarget_) {
|
||||||
/*
|
/*
|
||||||
* CDAF-based scanning sequence.
|
* CDAF-based scanning sequence.
|
||||||
* Allow a delay between steps for CDAF FoM statistics to be
|
* Allow a delay between steps for CDAF FoM statistics to be
|
||||||
|
@ -714,15 +727,27 @@ void Af::startAF()
|
||||||
oldSceneContrast_ = 0.0;
|
oldSceneContrast_ = 0.0;
|
||||||
sceneChangeCount_ = 0;
|
sceneChangeCount_ = 0;
|
||||||
reportState_ = AfState::Scanning;
|
reportState_ = AfState::Scanning;
|
||||||
} else
|
} else {
|
||||||
startProgrammedScan();
|
startProgrammedScan();
|
||||||
|
updateLensPosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Af::startProgrammedScan()
|
void Af::startProgrammedScan()
|
||||||
{
|
{
|
||||||
|
if (!initted_ || mode_ != AfModeContinuous ||
|
||||||
|
fsmooth_ <= cfg_.ranges[range_].focusMin + 2.0 * cfg_.speeds[speed_].stepCoarse) {
|
||||||
ftarget_ = cfg_.ranges[range_].focusMin;
|
ftarget_ = cfg_.ranges[range_].focusMin;
|
||||||
updateLensPosition();
|
scanStep_ = cfg_.speeds[speed_].stepCoarse;
|
||||||
scanState_ = ScanState::Coarse;
|
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;
|
scanMaxContrast_ = 0.0;
|
||||||
scanMinContrast_ = 1.0e9;
|
scanMinContrast_ = 1.0e9;
|
||||||
scanMaxIndex_ = 0;
|
scanMaxIndex_ = 0;
|
||||||
|
@ -785,7 +810,9 @@ void Af::prepare(Metadata *imageMetadata)
|
||||||
else
|
else
|
||||||
status.pauseState = AfPauseState::Running;
|
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;
|
status.state = AfState::Scanning;
|
||||||
else
|
else
|
||||||
status.state = reportState_;
|
status.state = reportState_;
|
||||||
|
@ -907,7 +934,7 @@ void Af::setMode(AfAlgorithm::AfMode mode)
|
||||||
pauseFlag_ = false;
|
pauseFlag_ = false;
|
||||||
if (mode == AfModeContinuous)
|
if (mode == AfModeContinuous)
|
||||||
scanState_ = ScanState::Trigger;
|
scanState_ = ScanState::Trigger;
|
||||||
else if (mode != AfModeAuto || scanState_ < ScanState::Coarse)
|
else if (mode != AfModeAuto || scanState_ < ScanState::Coarse1)
|
||||||
goIdle();
|
goIdle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -923,11 +950,11 @@ void Af::pause(AfAlgorithm::AfPause pause)
|
||||||
if (mode_ == AfModeContinuous) {
|
if (mode_ == AfModeContinuous) {
|
||||||
if (pause == AfPauseResume && pauseFlag_) {
|
if (pause == AfPauseResume && pauseFlag_) {
|
||||||
pauseFlag_ = false;
|
pauseFlag_ = false;
|
||||||
if (scanState_ < ScanState::Coarse)
|
if (scanState_ < ScanState::Coarse1)
|
||||||
scanState_ = ScanState::Trigger;
|
scanState_ = ScanState::Trigger;
|
||||||
} else if (pause != AfPauseResume && !pauseFlag_) {
|
} else if (pause != AfPauseResume && !pauseFlag_) {
|
||||||
pauseFlag_ = true;
|
pauseFlag_ = true;
|
||||||
if (pause == AfPauseImmediate || scanState_ < ScanState::Coarse)
|
if (pause == AfPauseImmediate || scanState_ < ScanState::Coarse1)
|
||||||
goIdle();
|
goIdle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,8 @@ private:
|
||||||
Idle = 0,
|
Idle = 0,
|
||||||
Trigger,
|
Trigger,
|
||||||
Pdaf,
|
Pdaf,
|
||||||
Coarse,
|
Coarse1,
|
||||||
|
Coarse2,
|
||||||
Fine,
|
Fine,
|
||||||
Settle
|
Settle
|
||||||
};
|
};
|
||||||
|
@ -90,8 +91,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpeedDependentParams {
|
struct SpeedDependentParams {
|
||||||
double stepCoarse; /* used for scans */
|
double stepCoarse; /* in dioptres; used for scans */
|
||||||
double stepFine; /* used for scans */
|
double stepFine; /* in dioptres; used for scans */
|
||||||
double contrastRatio; /* used for scan termination and reporting */
|
double contrastRatio; /* used for scan termination and reporting */
|
||||||
double retriggerRatio; /* contrast and RGB ratio for re-triggering */
|
double retriggerRatio; /* contrast and RGB ratio for re-triggering */
|
||||||
uint32_t retriggerDelay; /* frames of stability before re-triggering */
|
uint32_t retriggerDelay; /* frames of stability before re-triggering */
|
||||||
|
@ -177,7 +178,7 @@ private:
|
||||||
unsigned sameSignCount_;
|
unsigned sameSignCount_;
|
||||||
unsigned sceneChangeCount_;
|
unsigned sceneChangeCount_;
|
||||||
unsigned scanMaxIndex_;
|
unsigned scanMaxIndex_;
|
||||||
double scanMaxContrast_, scanMinContrast_;
|
double scanMaxContrast_, scanMinContrast_, scanStep_;
|
||||||
std::vector<ScanRecord> scanData_;
|
std::vector<ScanRecord> scanData_;
|
||||||
AfState reportState_;
|
AfState reportState_;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue