@@ -38,8 +38,9 @@ bool estimateBracketsFromSfmData(std::vector<std::vector<std::shared_ptr<sfmData
38
38
fnumbers.insert (view->getImage ().getMetadataFNumber ());
39
39
double exp = view->getImage ().getCameraExposureSetting ().getExposure ();
40
40
std::string path = view->getImage ().getImagePath ();
41
+ int64_t timestamp = view->getImage ().getMetadataDateTimestamp ();
41
42
42
- LuminanceInfo li (viewIt.first , path, exp );
43
+ LuminanceInfo li (viewIt.first , path, exp , timestamp );
43
44
luminances.push_back (li);
44
45
}
45
46
@@ -303,6 +304,97 @@ std::vector<std::vector<LuminanceInfo>> splitMonotonics(const std::vector<Lumina
303
304
return splitted;
304
305
}
305
306
307
+ std::vector<std::vector<LuminanceInfo>> splitTimes (const std::vector<LuminanceInfo> & luminanceInfos, int maxDeltaInABurst = 2 )
308
+ {
309
+ std::vector<std::vector<LuminanceInfo>> splitted;
310
+
311
+ if (luminanceInfos.size () == 0 )
312
+ {
313
+ return splitted;
314
+ }
315
+
316
+ // Split the luminanceInfos into groups which have close capture time (burst detection)
317
+ std::vector<LuminanceInfo> normedTimes (luminanceInfos);
318
+ // Sort luminanceinfos by timestamp
319
+ std::sort (normedTimes.begin (),
320
+ normedTimes.end (),
321
+ [](const LuminanceInfo& a, const LuminanceInfo& b) -> bool {
322
+ return (a.mtimestamp < b.mtimestamp );
323
+ });
324
+
325
+ const int histoSize = maxDeltaInABurst + 2 ;
326
+ std::vector<int > histo (histoSize, 0 );
327
+ for (int i = normedTimes.size () - 1 ; i >= 1 ; i--)
328
+ {
329
+ normedTimes[i].mtimestamp -= normedTimes[i - 1 ].mtimestamp ;
330
+ histo[std::min (maxDeltaInABurst + 1 , (int )normedTimes[i].mtimestamp )]++;
331
+ }
332
+ normedTimes[0 ].mtimestamp = 0 ;
333
+
334
+ // Check for outliers at both sides of the sequence.
335
+ // At the beginning an item is an outlier if the next one has been captured more than maxDeltaInABurst seconds after.
336
+ // At the end an item is an outlier if the previous one has been captured more than maxDeltaInABurst seconds before.
337
+ int firstIndexValid = 0 ;
338
+ while (normedTimes[firstIndexValid + 1 ].mtimestamp > maxDeltaInABurst && firstIndexValid < normedTimes.size () - 1 )
339
+ {
340
+ firstIndexValid++;
341
+ }
342
+ if (firstIndexValid == normedTimes.size () - 1 )
343
+ {
344
+ return splitted;
345
+ }
346
+ int LastIndexValid = normedTimes.size () - 1 ;
347
+ while (normedTimes[LastIndexValid].mtimestamp > maxDeltaInABurst && LastIndexValid > firstIndexValid)
348
+ {
349
+ LastIndexValid--;
350
+ }
351
+ if (LastIndexValid == firstIndexValid)
352
+ {
353
+ return splitted;
354
+ }
355
+
356
+ int outlierNumber = firstIndexValid + (normedTimes.size () - 1 - LastIndexValid);
357
+
358
+ int nbItemLow = 0 ;
359
+ for (int i = 0 ; i <= maxDeltaInABurst ; i++)
360
+ {
361
+ nbItemLow += histo[i];
362
+ }
363
+ const int nbItemHigh = histo.back ();
364
+
365
+ int nbGroup;
366
+ int groupSize;
367
+ if (nbItemLow % (nbItemHigh + 1 - outlierNumber) == 0 )
368
+ {
369
+ nbGroup = nbItemHigh + 1 - outlierNumber;
370
+ groupSize = (luminanceInfos.size () - outlierNumber) / nbGroup;
371
+ std::vector<LuminanceInfo> group;
372
+ std::map<float , int > mexposure;
373
+ for (int i = firstIndexValid; i <= LastIndexValid ; i++)
374
+ {
375
+ group.push_back (normedTimes[i]);
376
+ mexposure[normedTimes[i].mexposure ] = 0 ;
377
+ if (i % groupSize == groupSize - 1 )
378
+ {
379
+ if (mexposure.size () == groupSize)
380
+ {
381
+ // All group's exposures are different from each others
382
+ splitted.push_back (group);
383
+ group.clear ();
384
+ mexposure.clear ();
385
+ }
386
+ else
387
+ {
388
+ splitted.clear ();
389
+ break ;
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ return splitted;
396
+ }
397
+
306
398
/* *
307
399
* @brief assume ref is smaller than larger
308
400
* Try to find a subpart of larger which has the same set of exposures that smaller
@@ -349,11 +441,15 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
349
441
350
442
// Split and order the items using path
351
443
std::vector<std::vector<LuminanceInfo>> splitted = splitBasedir (luminanceInfos);
352
- // Create monotonic groups
444
+ // Create groups
353
445
std::vector<std::vector<LuminanceInfo>> monotonics;
354
446
for (const auto & luminanceInfoOneDir : splitted)
355
447
{
356
- std::vector<std::vector<LuminanceInfo>> lmonotonics = splitMonotonics (luminanceInfoOneDir);
448
+ std::vector<std::vector<LuminanceInfo>> lmonotonics = splitTimes (luminanceInfoOneDir);
449
+ if (lmonotonics.empty ())
450
+ {
451
+ lmonotonics = splitMonotonics (luminanceInfoOneDir);
452
+ }
357
453
monotonics.insert (monotonics.end (), lmonotonics.begin (), lmonotonics.end ());
358
454
}
359
455
@@ -426,7 +522,6 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
426
522
continue ;
427
523
}
428
524
429
-
430
525
// Compare with all valid monotonics
431
526
int offset = -1 ;
432
527
for (const auto & monotonic : monotonics)
@@ -484,7 +579,9 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
484
579
groups.push_back (group);
485
580
}
486
581
487
- ALICEVISION_LOG_INFO (" Groups found : " << monotonics.size ());
582
+ const int groupNumber = monotonics.size ();
583
+ const int outlierNumber = luminanceInfos.size () - groupNumber * bestBracketCount;
584
+ ALICEVISION_LOG_INFO (groupNumber << " group(s) of " << bestBracketCount << " bracket(s) and " << outlierNumber << " outlier(s) found." );
488
585
489
586
return groups;
490
587
}
0 commit comments