Skip to content

Commit

Permalink
LdrToHdrCalibration: Computation of targeted view index for merging c…
Browse files Browse the repository at this point in the history
…ode refactoring.

LdrToHdrMerging: Use offsetRefBracketIndex parameter if it is in a suitable range regarding the number of views in a group. If not, use the indexes computed in the calibration node.
  • Loading branch information
demoulinv committed Dec 14, 2022
1 parent 44ae001 commit ce5b808
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 86 deletions.
62 changes: 54 additions & 8 deletions src/aliceVision/hdr/brackets.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "brackets.hpp"

#include <fstream>

#include <aliceVision/numeric/numeric.hpp>

#include <boost/filesystem.hpp>
Expand Down Expand Up @@ -101,18 +103,62 @@ bool estimateBracketsFromSfmData(std::vector<std::vector<std::shared_ptr<sfmData
return true;
}

void selectTargetViews(std::vector<std::shared_ptr<sfmData::View>> & out_targetViews, const std::vector<std::vector<std::shared_ptr<sfmData::View>>> & groups, int offsetRefBracketIndex)
void selectTargetViews(std::vector<std::shared_ptr<sfmData::View>> & out_targetViews, const std::vector<std::vector<std::shared_ptr<sfmData::View>>> & groups, int offsetRefBracketIndex, const std::string& targetIndexesFilename)
{
for(auto & group : groups)
// If targetIndexesFilename cannot be opened or is not valid target views are derived from the middle exposed views
// For odd number, there is no ambiguity on the middle image.
// For even number, we arbitrarily choose the more exposed view (as we usually have more under-exposed images than over-exposed).
const int viewNumberPerGroup = groups[0].size();
const int middleIndex = viewNumberPerGroup / 2;
const int targetIndex = middleIndex + offsetRefBracketIndex;

if ((targetIndex >= 0) && (targetIndex < viewNumberPerGroup))
{
// Target views are the middle exposed views
// For add number, there is no ambiguity on the middle image.
// For even number, we arbitrarily choose the more exposed view (as we usually have more under-exposed images than over-exposed).
const int middleIndex = int(group.size()) / 2;
const int targetIndex = clamp(middleIndex + offsetRefBracketIndex, 0, int(group.size()) - 1);
ALICEVISION_LOG_INFO("Use offsetRefBracketIndex parameter");
for(auto & group : groups)
{
out_targetViews.push_back(group[targetIndex]);
}
}
else // try to use indexes in the file
{
ALICEVISION_LOG_INFO("offsetRefBracketIndex parameter out of range, read file containing target indexes");
std::vector<int> targetIndexes;
std::ifstream file(targetIndexesFilename);
if (!file)
{
ALICEVISION_LOG_WARNING("Unable to open the file " << targetIndexesFilename << " with the selection of exposures. This file would be needed to select the optimal exposure for the creation of the HDR images. Use clamped offsetRefBracketIndex parameter.");
for (int i = 0; i < groups.size(); ++i)
{
targetIndexes.push_back(clamp(targetIndex, 0, int(groups[i].size()) - 1));
}
}
else
{
while (file)
{
std::string line;
if (!getline(file, line)) break;
targetIndexes.push_back(atoi(line.c_str()));
}
file.close();

out_targetViews.push_back(group[targetIndex]);
if (targetIndexes.size() != groups.size())
{
ALICEVISION_LOG_WARNING("Non consistent number of reference indexes in file " << targetIndexesFilename << ", use clamped offsetRefBracketIndex parameter");
for (int i = 0; i < groups.size(); ++i)
{
targetIndexes.push_back(clamp(targetIndex, 0, int(groups[i].size()) - 1));
}
}
}

for (int i = 0; i < groups.size(); ++i)
{
out_targetViews.push_back(groups[i][targetIndexes[i]]);
}
}

}
}
}
5 changes: 4 additions & 1 deletion src/aliceVision/hdr/brackets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ bool estimateBracketsFromSfmData(std::vector<std::vector<std::shared_ptr<sfmData
* @param[out] targetViews: estimated target views
* @param[in] groups: groups of Views corresponding to multi-bracketing. Warning: Needs be sorted by exposure time.
* @param[in] offsetRefBracketIndex: 0 mean center bracket and you can choose +N/-N to select the reference bracket
* @param[in] targetIndexesFilename: in case offsetRefBracketIndex is out of range the number of views in a group target indexes can be read from a text file
* if the file cannot be read or does not contain the expected number of values (same as view group number) and
* if offsetRefBracketIndex is out of range the number of views then a clamped values of offsetRefBracketIndex is considered
*/
void selectTargetViews(std::vector<std::shared_ptr<sfmData::View>> & out_targetViews, const std::vector<std::vector<std::shared_ptr<sfmData::View>>>& groups, int offsetRefBracketIndex);
void selectTargetViews(std::vector<std::shared_ptr<sfmData::View>> & out_targetViews, const std::vector<std::vector<std::shared_ptr<sfmData::View>>>& groups, int offsetRefBracketIndex, const std::string& targetIndexesFilename = "");

}
}
116 changes: 60 additions & 56 deletions src/software/pipeline/main_LdrToHdrCalibration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,60 @@ inline std::istream& operator>>(std::istream& in, ECalibrationMethod& calibratio
return in;
}

int computeMergingRefIndex(const std::vector<double>& groupedExposure, const std::vector<hdr::ImageSample>& samples, const double meanTargetedLuma)
{
std::map<int, std::pair<int, double>> meanLum;
std::map<int, std::pair<double, double>> rangeLum;
for (int i = 0; i < groupedExposure.size(); i++)
{
meanLum[(int)(groupedExposure[i] * 1000)].first = 0;
meanLum[(int)(groupedExposure[i] * 1000)].second = 0.0;
rangeLum[(int)(groupedExposure[i] * 1000)].first = 1000.0;
rangeLum[(int)(groupedExposure[i] * 1000)].second = 0.0;
}
for (int i = 0; i < samples.size(); i++)
{
for (int j = 0; j < samples[i].descriptions.size(); j++)
{
double lum = image::Rgb2GrayLinear(samples[i].descriptions[j].mean[0], samples[i].descriptions[j].mean[1], samples[i].descriptions[j].mean[2]);
meanLum[(int)(samples[i].descriptions[j].exposure * 1000)].second += lum;
meanLum[(int)(samples[i].descriptions[j].exposure * 1000)].first++;
if (lum < rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].first)
{
rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].first = lum;
}
if (lum > rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].second)
{
rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].second = lum;
}
}
}

double minDiffWithLumaTarget = 1000.0;
int minDiffWithLumaTargetIdx = 0;

int k = 0;
for (const auto& n : meanLum)
{
double lumaMean = n.second.second / (double)n.second.first;

ALICEVISION_LOG_DEBUG('[' << n.first << "] = " << lumaMean);

if (fabs(lumaMean - meanTargetedLuma) < minDiffWithLumaTarget)
{
minDiffWithLumaTarget = fabs(lumaMean - meanTargetedLuma);
minDiffWithLumaTargetIdx = k;
}
++k;
}
for (const auto& n : rangeLum)
{
ALICEVISION_LOG_DEBUG('[' << n.first << " , " << n.second << "]");
}

return minDiffWithLumaTargetIdx;
}

int aliceVision_main(int argc, char** argv)
{
std::string sfmInputDataFilename;
Expand All @@ -121,6 +175,7 @@ int aliceVision_main(int argc, char** argv)
int nbBrackets = 0;
int channelQuantizationPower = 10;
size_t maxTotalPoints = 1000000;
double meanTargetedLumaForMerging = 0.4;

// Command line parameters

Expand All @@ -145,8 +200,10 @@ int aliceVision_main(int argc, char** argv)
("channelQuantizationPower", po::value<int>(&channelQuantizationPower)->default_value(channelQuantizationPower),
"Quantization level like 8 bits or 10 bits.")
("maxTotalPoints", po::value<size_t>(&maxTotalPoints)->default_value(maxTotalPoints),
"Max number of points used from the sampling. This ensures that the number of pixels values extracted by the sampling "
"can be managed by the calibration step (in term of computation time and memory usage).")
"Max number of points used from the sampling. This ensures that the number of pixels values extracted by the sampling "
"can be managed by the calibration step (in term of computation time and memory usage).")
("meanTargetedLumaForMerging", po::value<double>(&meanTargetedLumaForMerging)->default_value(meanTargetedLumaForMerging),
"Mean expected luminance after merging step. Must be in the range [0, 1].")
;

CmdLine cmdline("This program recovers the Camera Response Function (CRF) from samples extracted from LDR images with multi-bracketing.\n"
Expand Down Expand Up @@ -259,8 +316,6 @@ int aliceVision_main(int argc, char** argv)
size_t group_pos = 0;
hdr::Sampling sampling;

double meanTargetedLuma = 0.4; // should be a parameter

ALICEVISION_LOG_INFO("Analyzing samples for each group");
for(auto & group : groupedViews)
{
Expand All @@ -284,58 +339,7 @@ int aliceVision_main(int argc, char** argv)

sampling.analyzeSource(samples, channelQuantization, group_pos);

std::map<int, std::pair<int, double>> meanLum;
std::map<int, std::pair<double, double>> rangeLum;
for (int i = 0; i < groupedExposures[group_pos].size(); i++)
{
meanLum[(int)(groupedExposures[group_pos][i] * 1000)].first = 0;
meanLum[(int)(groupedExposures[group_pos][i] * 1000)].second = 0.0;
rangeLum[(int)(groupedExposures[group_pos][i] * 1000)].first = 1000.0;
rangeLum[(int)(groupedExposures[group_pos][i] * 1000)].second = 0.0;
}
for (int i = 0; i < samples.size(); i++)
{
for (int j = 0; j < samples[i].descriptions.size(); j++)
{
double lum = 0.2126 * samples[i].descriptions[j].mean[0] + 0.7152 * samples[i].descriptions[j].mean[1] + 0.0722 * samples[i].descriptions[j].mean[2];
meanLum[(int)(samples[i].descriptions[j].exposure * 1000)].second += lum;
meanLum[(int)(samples[i].descriptions[j].exposure * 1000)].first++;
if (lum < rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].first)
{
rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].first = lum;
}
if (lum > rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].second)
{
rangeLum[(int)(samples[i].descriptions[j].exposure * 1000)].second = lum;
}
}
}

double minDiffWithLumaTarget = 1000.0;
int minDiffWithLumaTargetIdx = 0;

int k = 0;
for (const auto& n : meanLum)
{
double lumaMean = n.second.second / (double)n.second.first;

std::cout << '[' << n.first << "] = " << lumaMean << std::endl;

if (fabs(lumaMean - meanTargetedLuma) < minDiffWithLumaTarget)
{
minDiffWithLumaTarget = fabs(lumaMean - meanTargetedLuma);
minDiffWithLumaTargetIdx = k;
}
++k;
}
std::cout << std::endl;
for (const auto& n : rangeLum)
{
std::cout << '[' << n.first << " , " << n.second << "]" << std::endl;
}
std::cout << std::endl;

refIndexes.push_back(minDiffWithLumaTargetIdx);
refIndexes.push_back(computeMergingRefIndex(groupedExposures[group_pos], samples, meanTargetedLumaForMerging));

++group_pos;
}
Expand Down
23 changes: 2 additions & 21 deletions src/software/pipeline/main_LdrToHdrMerge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,29 +175,10 @@ int aliceVision_main(int argc, char** argv)
}
}
std::vector<std::shared_ptr<sfmData::View>> targetViews;
//hdr::selectTargetViews(targetViews, groupedViews, offsetRefBracketIndex);

const std::string targetIndexFilename = (fs::path(inputResponsePath).parent_path() / (std::string("exposureRefIndexes") + std::string(".txt"))).string();
const fs::path targetIndexFilepath(fs::path(inputResponsePath).parent_path() / (std::string("exposureRefIndexes.txt")));

std::ifstream file(targetIndexFilename);
std::vector<int> targetIndexes;
if (!file)
{
throw std::logic_error("Can't open target indexes file");
}
//create fileData
while (file)
{
std::string line;
if (!getline(file, line)) break;
targetIndexes.push_back(atoi(line.c_str()));
}
file.close();

for (int i = 0; i < groupedViews.size(); ++i)
{
targetViews.push_back(groupedViews[i][targetIndexes[i]]);
}
hdr::selectTargetViews(targetViews, groupedViews, offsetRefBracketIndex, targetIndexFilepath.string());

// Define range to compute
if(rangeStart != -1)
Expand Down

0 comments on commit ce5b808

Please sign in to comment.