@@ -38,8 +38,9 @@ bool estimateBracketsFromSfmData(std::vector<std::vector<std::shared_ptr<sfmData
3838 fnumbers.insert (view->getImage ().getMetadataFNumber ());
3939 double exp = view->getImage ().getCameraExposureSetting ().getExposure ();
4040 std::string path = view->getImage ().getImagePath ();
41+ int64_t timestamp = view->getImage ().getMetadataDateTimestamp ();
4142
42- LuminanceInfo li (viewIt.first , path, exp);
43+ LuminanceInfo li (viewIt.first , path, exp, timestamp );
4344 luminances.push_back (li);
4445 }
4546
@@ -303,6 +304,97 @@ std::vector<std::vector<LuminanceInfo>> splitMonotonics(const std::vector<Lumina
303304 return splitted;
304305}
305306
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+
306398/* *
307399* @brief assume ref is smaller than larger
308400* 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>
349441
350442 // Split and order the items using path
351443 std::vector<std::vector<LuminanceInfo>> splitted = splitBasedir (luminanceInfos);
352- // Create monotonic groups
444+ // Create groups
353445 std::vector<std::vector<LuminanceInfo>> monotonics;
354446 for (const auto & luminanceInfoOneDir : splitted)
355447 {
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+ }
357453 monotonics.insert (monotonics.end (), lmonotonics.begin (), lmonotonics.end ());
358454 }
359455
@@ -426,7 +522,6 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
426522 continue ;
427523 }
428524
429-
430525 // Compare with all valid monotonics
431526 int offset = -1 ;
432527 for (const auto & monotonic : monotonics)
@@ -484,7 +579,9 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
484579 groups.push_back (group);
485580 }
486581
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." );
488585
489586 return groups;
490587}
0 commit comments