From b4c6eb06825dbadcc89379d44777be1662d3a845 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Wed, 14 Dec 2022 13:38:53 +0100 Subject: [PATCH] LdrToHdrCalibration: Computation of targeted view index for merging code 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. --- src/aliceVision/hdr/brackets.cpp | 60 +++++++-- src/aliceVision/hdr/brackets.hpp | 5 +- .../pipeline/main_LdrToHdrCalibration.cpp | 116 +++++++++--------- src/software/pipeline/main_LdrToHdrMerge.cpp | 23 +--- 4 files changed, 118 insertions(+), 86 deletions(-) diff --git a/src/aliceVision/hdr/brackets.cpp b/src/aliceVision/hdr/brackets.cpp index f1de890518..135e925af3 100644 --- a/src/aliceVision/hdr/brackets.cpp +++ b/src/aliceVision/hdr/brackets.cpp @@ -101,18 +101,62 @@ bool estimateBracketsFromSfmData(std::vector> & out_targetViews, const std::vector>> & groups, int offsetRefBracketIndex) +void selectTargetViews(std::vector> & out_targetViews, const std::vector>> & 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)) + { + ALICEVISION_LOG_INFO("Use offsetRefBracketIndex parameter"); + for(auto & group : groups) + { + out_targetViews.push_back(group[targetIndex]); + } + } + else // try to use indexes in the file { - // 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("offsetRefBracketIndex parameter out of range, read file containing target indexes"); + std::vector targetIndexes; + std::ifstream file(targetIndexesFilename, std::ios_base::in); + 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(); + + 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)); + } + } + } - out_targetViews.push_back(group[targetIndex]); + for (int i = 0; i < groups.size(); ++i) + { + out_targetViews.push_back(groups[i][targetIndexes[i]]); + } } + } } } diff --git a/src/aliceVision/hdr/brackets.hpp b/src/aliceVision/hdr/brackets.hpp index 490868bc99..d56a0973d6 100644 --- a/src/aliceVision/hdr/brackets.hpp +++ b/src/aliceVision/hdr/brackets.hpp @@ -25,8 +25,11 @@ bool estimateBracketsFromSfmData(std::vector> & out_targetViews, const std::vector>>& groups, int offsetRefBracketIndex); +void selectTargetViews(std::vector> & out_targetViews, const std::vector>>& groups, int offsetRefBracketIndex, const std::string& targetIndexesFilename = ""); } } diff --git a/src/software/pipeline/main_LdrToHdrCalibration.cpp b/src/software/pipeline/main_LdrToHdrCalibration.cpp index eb7e157f51..14c57741da 100644 --- a/src/software/pipeline/main_LdrToHdrCalibration.cpp +++ b/src/software/pipeline/main_LdrToHdrCalibration.cpp @@ -111,6 +111,60 @@ inline std::istream& operator>>(std::istream& in, ECalibrationMethod& calibratio return in; } +int computeMergingRefIndex(const std::vector& groupedExposure, const std::vector& samples, const double meanTargetedLuma) +{ + std::map> meanLum; + std::map> 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; @@ -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 @@ -145,8 +200,10 @@ int aliceVision_main(int argc, char** argv) ("channelQuantizationPower", po::value(&channelQuantizationPower)->default_value(channelQuantizationPower), "Quantization level like 8 bits or 10 bits.") ("maxTotalPoints", po::value(&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(&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" @@ -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) { @@ -284,58 +339,7 @@ int aliceVision_main(int argc, char** argv) sampling.analyzeSource(samples, channelQuantization, group_pos); - std::map> meanLum; - std::map> 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; } diff --git a/src/software/pipeline/main_LdrToHdrMerge.cpp b/src/software/pipeline/main_LdrToHdrMerge.cpp index bcb3002eef..bbbbcda987 100644 --- a/src/software/pipeline/main_LdrToHdrMerge.cpp +++ b/src/software/pipeline/main_LdrToHdrMerge.cpp @@ -175,29 +175,10 @@ int aliceVision_main(int argc, char** argv) } } std::vector> 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 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)