@@ -184,15 +184,8 @@ int selectTargetViews(std::vector<std::shared_ptr<sfmData::View>>& targetViews,
184184 return targetIndex;
185185}
186186
187- std::vector<std::vector< LuminanceInfo>> splitBasedir (const std::vector<LuminanceInfo> & luminanceInfos)
187+ std::vector<LuminanceInfo> correctPaths (const std::vector<LuminanceInfo> & luminanceInfos)
188188{
189- std::vector<std::vector<LuminanceInfo>> splitted;
190-
191- if (luminanceInfos.size () == 0 )
192- {
193- return splitted;
194- }
195-
196189 // Ignore non existing files
197190 // Remove relative paths
198191 // Remove symlinks
@@ -210,6 +203,19 @@ std::vector<std::vector<LuminanceInfo>> splitBasedir(const std::vector<Luminance
210203
211204 correctedPaths.push_back (corrected);
212205 }
206+ return correctedPaths;
207+ }
208+
209+ std::vector<std::vector<LuminanceInfo>> splitBasedir (const std::vector<LuminanceInfo> & luminanceInfos)
210+ {
211+ std::vector<std::vector<LuminanceInfo>> splitted;
212+
213+ if (luminanceInfos.size () == 0 )
214+ {
215+ return splitted;
216+ }
217+
218+ std::vector<LuminanceInfo> correctedPaths = correctPaths (luminanceInfos);
213219
214220 // Sort luminanceinfos by names
215221 std::sort (correctedPaths.begin (),
@@ -317,7 +323,7 @@ int extractIndex(const std::vector<LuminanceInfo> & smaller, const std::vector<L
317323 int diff = largerSize - smallerSize;
318324
319325 // For all continuous subparts of the erased sequence
320- for (int indexStart = 0 ; indexStart < diff; indexStart++)
326+ for (int indexStart = 0 ; indexStart <= diff; indexStart++)
321327 {
322328 // Check that the subpart is the same set of exposures
323329 bool allCorrect = true ;
@@ -450,27 +456,133 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
450456 }
451457 }
452458
453- // check coherency
454- bool coherency = true ;
455- for (int idref = 1 ; idref < monotonics.size (); ++idref)
459+ // In some cases (some Nikon cameras for instance) the medium exposure is at the first position of the ldr images group.
460+ // Check that case and try to insert the resulting luminanceInfos seen as outliers at the mid index in the correponding groups.
461+ if ((luminanceInfos.size () - monotonics.size () * monotonics[0 ].size () >= monotonics.size ()) && // at least as many remaining outliers as groups
462+ (monotonics[0 ].size () % 2 == 0 )) // Even number of ldr images in a group
456463 {
457- const int idprev = idref - 1 ;
458- for (int idExposure = 0 ; idExposure < monotonics[idref].size (); ++idExposure)
464+
465+ // Sort luminanceinfos by names
466+ std::vector<LuminanceInfo> LumInfoCorrectPath = correctPaths (luminanceInfos);
467+ std::sort (LumInfoCorrectPath.begin (),
468+ LumInfoCorrectPath.end (),
469+ [](const LuminanceInfo& a, const LuminanceInfo& b) -> bool {
470+ return (a.mpath < b.mpath );
471+ });
472+
473+ // Extract remaining outliers (all the images in the original list that don't belong to a group)
474+ std::vector<LuminanceInfo> outliers;
475+ for (const auto & li: LumInfoCorrectPath)
476+ {
477+ bool notInMonotonics = true ;
478+ int idx = 0 ;
479+ while (notInMonotonics && idx < monotonics.size ())
480+ {
481+ int idxl = 0 ;
482+ while (notInMonotonics && idxl < monotonics[idx].size ())
483+ {
484+ notInMonotonics = !(monotonics[idx][idxl].mpath == li.mpath );
485+ idxl++;
486+ }
487+ idx++;
488+ }
489+ if (notInMonotonics)
490+ {
491+ outliers.push_back (li);
492+ }
493+ }
494+
495+ // Check if for all groups we can find an outlier located just before the first item of the group in the global list
496+ // sorted by name and with a mexposure in between the two middle items of the group
497+
498+ std::vector<int > firstGroupItemPositions;
499+ for (int idxg = 0 ; idxg < monotonics.size (); ++idxg)
459500 {
460- if (!(monotonics[idref][idExposure].mexposure == monotonics[idprev][idExposure].mexposure ))
501+ int pos = 0 ;
502+ while (LumInfoCorrectPath[pos].mpath != monotonics[idxg][0 ].mpath && pos < LumInfoCorrectPath.size ())
461503 {
462- ALICEVISION_LOG_WARNING (" Non consistent exposures between poses have been detected.\
463- Most likely the dataset has been captured with an automatic exposure mode enabled.\
464- Final result can be impacted." );
465- coherency = false ;
466-
467- break ;
504+ pos++;
468505 }
506+ firstGroupItemPositions.push_back (pos);
469507 }
508+ // The nth item of firstGroupItemPositions is the position in the global list sorted by name of the first element of the nth group
509+
470510
471- if (!coherency)
511+ LuminanceInfo emptyLumInfo (0 , " " , 0.0 );
512+ std::vector<LuminanceInfo> lumInfosToBeAdded (monotonics.size (), emptyLumInfo);
513+
514+ for (const auto & item: outliers)
472515 {
473- break ;
516+ int pos = 0 ;
517+ while (LumInfoCorrectPath[pos].mpath != item.mpath && pos < LumInfoCorrectPath.size ())
518+ {
519+ pos++;
520+ }
521+ int idx = 0 ;
522+ while (firstGroupItemPositions[idx] != pos + 1 && idx < firstGroupItemPositions.size ())
523+ {
524+ idx++;
525+ }
526+ if (idx < firstGroupItemPositions.size ())
527+ {
528+ lumInfosToBeAdded[idx] = item;
529+ }
530+ }
531+
532+ // Check that all candidate have the same mexposure value in the right range
533+ const float mexpRef = lumInfosToBeAdded[0 ].mexposure ;
534+ const int groupSize = monotonics[0 ].size ();
535+ const float mexpMin = monotonics[0 ][groupSize/2 - 1 ].mexposure ;
536+ const float mexpMax = monotonics[0 ][groupSize/2 ].mexposure ;
537+ bool lumInfosToBeAddedIsValid = mexpMin < mexpRef && mexpRef < mexpMax;
538+ if (lumInfosToBeAddedIsValid)
539+ {
540+ for (int idx = 1 ; idx < lumInfosToBeAdded.size (); ++idx)
541+ {
542+ lumInfosToBeAddedIsValid = lumInfosToBeAddedIsValid && lumInfosToBeAdded[idx].mexposure == mexpRef;
543+ }
544+ if (lumInfosToBeAddedIsValid)
545+ {
546+ // Add candidate outliers at the mid position of the corresponding group
547+ for (int idx = 0 ; idx < lumInfosToBeAdded.size (); ++idx)
548+ {
549+ std::vector<LuminanceInfo>::iterator mid = monotonics[idx].begin () + groupSize / 2 ;
550+ monotonics[idx].insert (mid, lumInfosToBeAdded[idx]);
551+ }
552+ }
553+ }
554+ }
555+
556+ // check coherency
557+ bool coherency = monotonics.size () * monotonics[0 ].size () <= luminanceInfos.size ();
558+ if (!coherency)
559+ {
560+ ALICEVISION_LOG_WARNING (" Non coherent number of ldr images per group.\
561+ Most likely the original ldr image set was split incorrectly.\
562+ Final result can be impacted." );
563+ }
564+ else
565+ {
566+ for (int idref = 1 ; idref < monotonics.size (); ++idref)
567+ {
568+ const int idprev = idref - 1 ;
569+ for (int idExposure = 0 ; idExposure < monotonics[idref].size (); ++idExposure)
570+ {
571+ if (!(monotonics[idref][idExposure].mexposure == monotonics[idprev][idExposure].mexposure ))
572+ {
573+ ALICEVISION_LOG_WARNING (" Non consistent exposures between poses have been detected.\
574+ Most likely the dataset has been captured with an automatic exposure mode enabled.\
575+ Final result can be impacted." );
576+ coherency = false ;
577+
578+ break ;
579+ }
580+ }
581+
582+ if (!coherency)
583+ {
584+ break ;
585+ }
474586 }
475587 }
476588
@@ -484,7 +596,7 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
484596 groups.push_back (group);
485597 }
486598
487- ALICEVISION_LOG_INFO (" Groups found : " << monotonics.size ());
599+ ALICEVISION_LOG_INFO (monotonics. size () << " group(s) of " << monotonics[ 0 ] .size () << " bracket(s) found " );
488600
489601 return groups;
490602}
0 commit comments