@@ -46,6 +46,8 @@ Af::SpeedDependentParams::SpeedDependentParams()
46
46
: stepCoarse(1.0 ),
47
47
stepFine(0.25 ),
48
48
contrastRatio(0.75 ),
49
+ retriggerRatio(0.75 ),
50
+ retriggerDelay(10 ),
49
51
pdafGain(-0.02 ),
50
52
pdafSquelch(0.125 ),
51
53
maxSlew(2.0 ),
@@ -60,6 +62,7 @@ Af::CfgParams::CfgParams()
60
62
confThresh(16 ),
61
63
confClip(512 ),
62
64
skipFrames(5 ),
65
+ checkForIR(false ),
63
66
map()
64
67
{
65
68
}
@@ -87,6 +90,8 @@ void Af::SpeedDependentParams::read(const libcamera::YamlObject ¶ms)
87
90
readNumber<double >(stepCoarse, params, " step_coarse" );
88
91
readNumber<double >(stepFine, params, " step_fine" );
89
92
readNumber<double >(contrastRatio, params, " contrast_ratio" );
93
+ readNumber<double >(retriggerRatio, params, " retrigger_ratio" );
94
+ readNumber<uint32_t >(retriggerDelay, params, " retrigger_delay" );
90
95
readNumber<double >(pdafGain, params, " pdaf_gain" );
91
96
readNumber<double >(pdafSquelch, params, " pdaf_squelch" );
92
97
readNumber<double >(maxSlew, params, " max_slew" );
@@ -137,6 +142,7 @@ int Af::CfgParams::read(const libcamera::YamlObject ¶ms)
137
142
readNumber<uint32_t >(confThresh, params, " conf_thresh" );
138
143
readNumber<uint32_t >(confClip, params, " conf_clip" );
139
144
readNumber<uint32_t >(skipFrames, params, " skip_frames" );
145
+ readNumber<bool >(checkForIR, params, " check_for_ir" );
140
146
141
147
if (params.contains (" map" ))
142
148
map = params[" map" ].get <ipa::Pwl>(ipa::Pwl{});
@@ -176,29 +182,37 @@ Af::Af(Controller *controller)
176
182
useWindows_(false ),
177
183
phaseWeights_(),
178
184
contrastWeights_(),
185
+ awbWeights_(),
179
186
scanState_(ScanState::Idle),
180
187
initted_(false ),
188
+ irFlag_(false ),
181
189
ftarget_(-1.0 ),
182
190
fsmooth_(-1.0 ),
183
191
prevContrast_(0.0 ),
192
+ oldSceneContrast_(0.0 ),
193
+ prevAverage_{ 0.0 , 0.0 , 0.0 },
194
+ oldSceneAverage_{ 0.0 , 0.0 , 0.0 },
184
195
prevPhase_ (0.0 ),
185
196
skipCount_(0 ),
186
197
stepCount_(0 ),
187
198
dropCount_(0 ),
188
199
sameSignCount_(0 ),
200
+ sceneChangeCount_(0 ),
189
201
scanMaxContrast_(0.0 ),
190
202
scanMinContrast_(1.0e9 ),
191
203
scanData_(),
192
204
reportState_(AfState::Idle)
193
205
{
194
206
/*
195
- * Reserve space for data, to reduce memory fragmentation. It's too early
196
- * to query the size of the PDAF (from camera) and Contrast (from ISP)
197
- * statistics, but these are plausible upper bounds.
207
+ * Reserve space for data structures, to reduce memory fragmentation.
208
+ * It's too early to query the size of the PDAF sensor data, so guess.
198
209
*/
210
+ windows_.reserve (1 );
199
211
phaseWeights_.w .reserve (16 * 12 );
200
212
contrastWeights_.w .reserve (getHardwareConfig ().focusRegions .width *
201
213
getHardwareConfig ().focusRegions .height );
214
+ contrastWeights_.w .reserve (getHardwareConfig ().awbRegions .width *
215
+ getHardwareConfig ().awbRegions .height );
202
216
scanData_.reserve (32 );
203
217
}
204
218
@@ -309,6 +323,7 @@ void Af::invalidateWeights()
309
323
{
310
324
phaseWeights_.sum = 0 ;
311
325
contrastWeights_.sum = 0 ;
326
+ awbWeights_.sum = 0 ;
312
327
}
313
328
314
329
bool Af::getPhase (PdafRegions const ®ions, double &phase, double &conf)
@@ -365,6 +380,54 @@ double Af::getContrast(const FocusRegions &focusStats)
365
380
return (contrastWeights_.sum > 0 ) ? ((double )sumWc / (double )contrastWeights_.sum ) : 0.0 ;
366
381
}
367
382
383
+ /*
384
+ * Get the average R, G, B values in AF window[s] (from AWB statistics).
385
+ * Optionally, check if all of {R,G,B} are within 4:5 of each other
386
+ * across more than 50% of the counted area and within the AF window:
387
+ * for an RGB sensor this strongly suggests that IR lighting is in use.
388
+ */
389
+
390
+ bool Af::getAverageAndTestIr (const RgbyRegions &awbStats, double rgb[3 ])
391
+ {
392
+ libcamera::Size size = awbStats.size ();
393
+ if (size.height != awbWeights_.rows ||
394
+ size.width != awbWeights_.cols || awbWeights_.sum == 0 ) {
395
+ LOG (RPiAf, Debug) << " Recompute RGB weights " << size.width << ' x' << size.height ;
396
+ computeWeights (&awbWeights_, size.height , size.width );
397
+ }
398
+
399
+ uint64_t sr = 0 , sg = 0 , sb = 0 , sw = 1 ;
400
+ uint64_t greyCount = 0 , allCount = 0 ;
401
+ for (unsigned i = 0 ; i < awbStats.numRegions (); ++i) {
402
+ uint64_t r = awbStats.get (i).val .rSum ;
403
+ uint64_t g = awbStats.get (i).val .gSum ;
404
+ uint64_t b = awbStats.get (i).val .bSum ;
405
+ uint64_t w = awbWeights_.w [i];
406
+ if (w) {
407
+ sw += w;
408
+ sr += w * r;
409
+ sg += w * g;
410
+ sb += w * b;
411
+ }
412
+ if (cfg_.checkForIR ) {
413
+ if (4 * r < 5 * b && 4 * b < 5 * r &&
414
+ 4 * r < 5 * g && 4 * g < 5 * r &&
415
+ 4 * b < 5 * g && 4 * g < 5 * b)
416
+ greyCount += awbStats.get (i).counted ;
417
+ allCount += awbStats.get (i).counted ;
418
+ }
419
+ }
420
+
421
+ rgb[0 ] = sr / (double )sw;
422
+ rgb[1 ] = sg / (double )sw;
423
+ rgb[2 ] = sb / (double )sw;
424
+
425
+ return (cfg_.checkForIR && 2 * greyCount > allCount &&
426
+ 4 * sr < 5 * sb && 4 * sb < 5 * sr &&
427
+ 4 * sr < 5 * sg && 4 * sg < 5 * sr &&
428
+ 4 * sb < 5 * sg && 4 * sg < 5 * sb);
429
+ }
430
+
368
431
void Af::doPDAF (double phase, double conf)
369
432
{
370
433
/* Apply loop gain */
@@ -473,6 +536,8 @@ void Af::doScan(double contrast, double phase, double conf)
473
536
if (scanData_.empty () || contrast > scanMaxContrast_) {
474
537
scanMaxContrast_ = contrast;
475
538
scanMaxIndex_ = scanData_.size ();
539
+ if (scanState_ != ScanState::Fine)
540
+ std::copy (prevAverage_, prevAverage_ + 3 , oldSceneAverage_);
476
541
}
477
542
if (contrast < scanMinContrast_)
478
543
scanMinContrast_ = contrast;
@@ -523,27 +588,63 @@ void Af::doAF(double contrast, double phase, double conf)
523
588
sameSignCount_++;
524
589
prevPhase_ = phase;
525
590
591
+ if (mode_ == AfModeManual)
592
+ return ; /* nothing to do */
593
+
526
594
if (scanState_ == ScanState::Pdaf) {
527
595
/*
528
596
* Use PDAF closed-loop control whenever available, in both CAF
529
597
* mode and (for a limited number of iterations) when triggered.
530
- * If PDAF fails (due to poor contrast, noise or large defocus),
531
- * fall back to a CDAF-based scan. To avoid "nuisance" scans,
532
- * scan only after a number of frames with low PDAF confidence .
598
+ * If PDAF fails (due to poor contrast, noise or large defocus)
599
+ * for at least dropoutFrames, fall back to a CDAF-based scan
600
+ * immediately (in triggered-auto) or on scene change (in CAF) .
533
601
*/
534
- if (conf > (dropCount_ ? 1.0 : 0.25 ) * cfg_.confEpsilon ) {
602
+ if (conf >= cfg_.confEpsilon ) {
535
603
if (mode_ == AfModeAuto || sameSignCount_ >= 3 )
536
604
doPDAF (phase, conf);
537
605
if (stepCount_ > 0 )
538
606
stepCount_--;
539
607
else if (mode_ != AfModeContinuous)
540
608
scanState_ = ScanState::Idle;
609
+ oldSceneContrast_ = contrast;
610
+ std::copy (prevAverage_, prevAverage_ + 3 , oldSceneAverage_);
611
+ sceneChangeCount_ = 0 ;
541
612
dropCount_ = 0 ;
542
- } else if (++dropCount_ == cfg_.speeds [speed_].dropoutFrames )
613
+ return ;
614
+ } else {
615
+ dropCount_++;
616
+ if (dropCount_ < cfg_.speeds [speed_].dropoutFrames )
617
+ return ;
618
+ if (mode_ != AfModeContinuous) {
619
+ startProgrammedScan ();
620
+ return ;
621
+ }
622
+ /* else fall through to waiting for a scene change */
623
+ }
624
+ }
625
+ if (scanState_ < ScanState::Coarse && mode_ == AfModeContinuous) {
626
+ /*
627
+ * In CAF mode, not in a scan, and PDAF is unavailable.
628
+ * Wait for a scene change, followed by stability.
629
+ */
630
+ if (contrast + 1.0 < cfg_.speeds [speed_].retriggerRatio * oldSceneContrast_ ||
631
+ oldSceneContrast_ + 1.0 < cfg_.speeds [speed_].retriggerRatio * contrast ||
632
+ prevAverage_[0 ] + 1.0 < cfg_.speeds [speed_].retriggerRatio * oldSceneAverage_[0 ] ||
633
+ oldSceneAverage_[0 ] + 1.0 < cfg_.speeds [speed_].retriggerRatio * prevAverage_[0 ] ||
634
+ prevAverage_[1 ] + 1.0 < cfg_.speeds [speed_].retriggerRatio * oldSceneAverage_[1 ] ||
635
+ oldSceneAverage_[1 ] + 1.0 < cfg_.speeds [speed_].retriggerRatio * prevAverage_[1 ] ||
636
+ prevAverage_[2 ] + 1.0 < cfg_.speeds [speed_].retriggerRatio * oldSceneAverage_[2 ] ||
637
+ oldSceneAverage_[2 ] + 1.0 < cfg_.speeds [speed_].retriggerRatio * prevAverage_[2 ]) {
638
+ oldSceneContrast_ = contrast;
639
+ std::copy (prevAverage_, prevAverage_ + 3 , oldSceneAverage_);
640
+ sceneChangeCount_ = 1 ;
641
+ } else if (sceneChangeCount_)
642
+ sceneChangeCount_++;
643
+ if (sceneChangeCount_ >= cfg_.speeds [speed_].retriggerDelay )
543
644
startProgrammedScan ();
544
645
} else if (scanState_ >= ScanState::Coarse && fsmooth_ == ftarget_) {
545
646
/*
546
- * Scanning sequence. This means PDAF has become unavailable .
647
+ * CDAF-based scanning sequence .
547
648
* Allow a delay between steps for CDAF FoM statistics to be
548
649
* updated, and a "settling time" at the end of the sequence.
549
650
* [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)
562
663
scanState_ = ScanState::Pdaf;
563
664
else
564
665
scanState_ = ScanState::Idle;
666
+ dropCount_ = 0 ;
667
+ sceneChangeCount_ = 0 ;
668
+ oldSceneContrast_ = std::max (scanMaxContrast_, prevContrast_);
565
669
scanData_.clear ();
566
670
} else if (conf >= cfg_.confThresh && earlyTerminationByPhase (phase)) {
671
+ std::copy (prevAverage_, prevAverage_ + 3 , oldSceneAverage_);
567
672
scanState_ = ScanState::Settle;
568
- stepCount_ = (mode_ == AfModeContinuous) ? 0
569
- : cfg_.speeds [speed_].stepFrames ;
673
+ stepCount_ = (mode_ == AfModeContinuous) ? 0 : cfg_.speeds [speed_].stepFrames ;
570
674
} else
571
675
doScan (contrast, phase, conf);
572
676
}
@@ -596,7 +700,8 @@ void Af::updateLensPosition()
596
700
void Af::startAF ()
597
701
{
598
702
/* Use PDAF if the tuning file allows it; else CDAF. */
599
- if (cfg_.speeds [speed_].dropoutFrames > 0 &&
703
+ if (cfg_.speeds [speed_].pdafGain != 0.0 &&
704
+ cfg_.speeds [speed_].dropoutFrames > 0 &&
600
705
(mode_ == AfModeContinuous || cfg_.speeds [speed_].pdafFrames > 0 )) {
601
706
if (!initted_) {
602
707
ftarget_ = cfg_.ranges [range_].focusDefault ;
@@ -606,6 +711,8 @@ void Af::startAF()
606
711
scanState_ = ScanState::Pdaf;
607
712
scanData_.clear ();
608
713
dropCount_ = 0 ;
714
+ oldSceneContrast_ = 0.0 ;
715
+ sceneChangeCount_ = 0 ;
609
716
reportState_ = AfState::Scanning;
610
717
} else
611
718
startProgrammedScan ();
@@ -656,7 +763,7 @@ void Af::prepare(Metadata *imageMetadata)
656
763
uint32_t oldSt = stepCount_;
657
764
if (imageMetadata->get (" pdaf.regions" , regions) == 0 )
658
765
getPhase (regions, phase, conf);
659
- doAF (prevContrast_, phase, conf);
766
+ doAF (prevContrast_, phase, irFlag_ ? 0 : conf);
660
767
updateLensPosition ();
661
768
LOG (RPiAf, Debug) << std::fixed << std::setprecision (2 )
662
769
<< static_cast <unsigned int >(reportState_)
@@ -666,7 +773,8 @@ void Af::prepare(Metadata *imageMetadata)
666
773
<< " ft" << oldFt << " ->" << ftarget_
667
774
<< " fs" << oldFs << " ->" << fsmooth_
668
775
<< " cont=" << (int )prevContrast_
669
- << " phase=" << (int )phase << " conf=" << (int )conf;
776
+ << " phase=" << (int )phase << " conf=" << (int )conf
777
+ << (irFlag_ ? " IR" : " " );
670
778
}
671
779
672
780
/* Report status and produce new lens setting */
@@ -690,6 +798,7 @@ void Af::process(StatisticsPtr &stats, [[maybe_unused]] Metadata *imageMetadata)
690
798
{
691
799
(void )imageMetadata;
692
800
prevContrast_ = getContrast (stats->focusRegions );
801
+ irFlag_ = getAverageAndTestIr (stats->awbRegions , prevAverage_);
693
802
}
694
803
695
804
/* Controls */
0 commit comments