Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split LDR image set using capturing time #1843

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 102 additions & 5 deletions src/aliceVision/hdr/brackets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ bool estimateBracketsFromSfmData(std::vector<std::vector<std::shared_ptr<sfmData
fnumbers.insert(view->getImage().getMetadataFNumber());
double exp = view->getImage().getCameraExposureSetting().getExposure();
std::string path = view->getImage().getImagePath();
int64_t timestamp = view->getImage().getMetadataDateTimestamp();

LuminanceInfo li(viewIt.first, path, exp);
LuminanceInfo li(viewIt.first, path, exp, timestamp);
luminances.push_back(li);
}

Expand Down Expand Up @@ -303,6 +304,97 @@ std::vector<std::vector<LuminanceInfo>> splitMonotonics(const std::vector<Lumina
return splitted;
}

std::vector<std::vector<LuminanceInfo>> splitTimes(const std::vector<LuminanceInfo> & luminanceInfos, int maxDeltaInABurst = 2)
{
std::vector<std::vector<LuminanceInfo>> splitted;

if (luminanceInfos.size() == 0)
{
return splitted;
}

// Split the luminanceInfos into groups which have close capture time (burst detection)
std::vector<LuminanceInfo> normedTimes(luminanceInfos);
// Sort luminanceinfos by timestamp
std::sort(normedTimes.begin(),
normedTimes.end(),
[](const LuminanceInfo& a, const LuminanceInfo& b) -> bool {
return (a.mtimestamp < b.mtimestamp);
});

const int histoSize = maxDeltaInABurst + 2;
std::vector<int> histo(histoSize, 0);
for (int i = normedTimes.size() - 1; i >= 1; i--)
{
normedTimes[i].mtimestamp -= normedTimes[i - 1].mtimestamp;
histo[std::min(maxDeltaInABurst + 1, (int)normedTimes[i].mtimestamp)]++;
}
normedTimes[0].mtimestamp = 0;

// Check for outliers at both sides of the sequence.
// At the beginning an item is an outlier if the next one has been captured more than maxDeltaInABurst seconds after.
// At the end an item is an outlier if the previous one has been captured more than maxDeltaInABurst seconds before.
int firstIndexValid = 0;
while (normedTimes[firstIndexValid + 1].mtimestamp > maxDeltaInABurst && firstIndexValid < normedTimes.size() - 1)
{
firstIndexValid++;
}
if (firstIndexValid == normedTimes.size() - 1)
{
return splitted;
}
int LastIndexValid = normedTimes.size() - 1;
while (normedTimes[LastIndexValid].mtimestamp > maxDeltaInABurst && LastIndexValid > firstIndexValid)
{
LastIndexValid--;
}
if (LastIndexValid == firstIndexValid)
{
return splitted;
}

int outlierNumber = firstIndexValid + (normedTimes.size() - 1 - LastIndexValid);

int nbItemLow = 0;
for (int i = 0; i <= maxDeltaInABurst ; i++)
{
nbItemLow += histo[i];
}
const int nbItemHigh = histo.back();

int nbGroup;
int groupSize;
if (nbItemLow % (nbItemHigh + 1 - outlierNumber) == 0)
{
nbGroup = nbItemHigh + 1 - outlierNumber;
groupSize = (luminanceInfos.size() - outlierNumber) / nbGroup;
std::vector<LuminanceInfo> group;
std::map<float, int> mexposure;
for (int i = firstIndexValid; i <= LastIndexValid ; i++)
{
group.push_back(normedTimes[i]);
mexposure[normedTimes[i].mexposure] = 0;
if (i % groupSize == groupSize - 1)
{
if (mexposure.size() == groupSize)
{
// All group's exposures are different from each others
splitted.push_back(group);
group.clear();
mexposure.clear();
}
else
{
splitted.clear();
break;
}
}
}
}

return splitted;
}

/**
* @brief assume ref is smaller than larger
* Try to find a subpart of larger which has the same set of exposures that smaller
Expand Down Expand Up @@ -349,11 +441,15 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>

//Split and order the items using path
std::vector<std::vector<LuminanceInfo>> splitted = splitBasedir(luminanceInfos);
//Create monotonic groups
//Create groups
std::vector<std::vector<LuminanceInfo>> monotonics;
for (const auto & luminanceInfoOneDir : splitted)
{
std::vector<std::vector<LuminanceInfo>> lmonotonics = splitMonotonics(luminanceInfoOneDir);
std::vector<std::vector<LuminanceInfo>> lmonotonics = splitTimes(luminanceInfoOneDir);
if (lmonotonics.empty())
{
lmonotonics = splitMonotonics(luminanceInfoOneDir);
}
monotonics.insert(monotonics.end(), lmonotonics.begin(), lmonotonics.end());
}

Expand Down Expand Up @@ -426,7 +522,6 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
continue;
}


//Compare with all valid monotonics
int offset = -1;
for (const auto& monotonic : monotonics)
Expand Down Expand Up @@ -484,7 +579,9 @@ std::vector<std::vector<IndexT>> estimateGroups(const std::vector<LuminanceInfo>
groups.push_back(group);
}

ALICEVISION_LOG_INFO("Groups found : " << monotonics.size());
const int groupNumber = monotonics.size();
const int outlierNumber = luminanceInfos.size() - groupNumber * bestBracketCount;
ALICEVISION_LOG_INFO(groupNumber << " group(s) of " << bestBracketCount << " bracket(s) and " << outlierNumber << " outlier(s) found.");

return groups;
}
Expand Down
14 changes: 12 additions & 2 deletions src/aliceVision/hdr/brackets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ struct LuminanceInfo
aliceVision::IndexT mviewId;
std::string mpath;
float mexposure;
int64_t mtimestamp;

LuminanceInfo() = default;

LuminanceInfo(aliceVision::IndexT vid, const std::string & path, float exposure):
LuminanceInfo(aliceVision::IndexT vid, const std::string & path, float exposure, int64_t timestamp):
mviewId(vid),
mpath(path),
mexposure(exposure)
mexposure(exposure),
mtimestamp(timestamp)
{

}
Expand Down Expand Up @@ -100,6 +102,14 @@ inline std::istream& operator>>(std::istream& in, ECalibrationMethod& calibratio

/**
* @brief Estimate the brackets information from the SfM data
* The bracket groups are estimated using the capturing time metadata of each picture.
* if the duration between 2 consecutive pictures is less than 2.5 seconds the 2 pictures are considered to be part of the
* same brackecting group.In case several single pictures, located at the beginning or at the end of the image set after
* it has been sorted, they are considered as outliers and they won't be added to any returned group.
* With the remaining pictures, a check is done to be sure that every groups contain the same number of pictures. If this
* is not the case, this first tentative of splitting aborts. A second method is then applied. It consists to group pictures
* with monotonic exposure variation after sorting them in the alphabetic order. Outliers can be removed at the beginiing
* and at the end of the sorted pictures or between 2 groups.
* @param[out] groups the estimated groups
* @param[in] sfmData SfM data to estimate the brackets from
* @param[in] countBrackets the number of brackets (optional, 0 means that it will be guessed)
Expand Down
Loading