From c5b5f1b93d9dcbdf98910181d30dc470df12423d Mon Sep 17 00:00:00 2001 From: Clara Date: Thu, 20 Jun 2019 11:00:23 +0200 Subject: [PATCH] Correct images exposure in PrepareDenseScene add methods in sfmData to calculate exposure values + correct them during the PrepareDenseScene --- src/aliceVision/sfmData/SfMData.hpp | 20 ++++++ src/aliceVision/sfmData/View.hpp | 64 +++++++++++++++++++ .../pipeline/main_prepareDenseScene.cpp | 30 ++++++++- 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/src/aliceVision/sfmData/SfMData.hpp b/src/aliceVision/sfmData/SfMData.hpp index f916f36772..d7d37c998c 100644 --- a/src/aliceVision/sfmData/SfMData.hpp +++ b/src/aliceVision/sfmData/SfMData.hpp @@ -297,6 +297,26 @@ class SfMData return _rigs.at(view.getRigId()); } + /** + * @brief Get the median Exposure Value (Ev) of + * @return + */ + + float getMedianEv() const + { + std::vector evList; + evList.reserve(views.size()); + + for(const auto& view : views) + { + float ev = view.second->getEv(); + evList.emplace_back(ev); + } + std::nth_element(evList.begin(), evList.begin() + evList.size()/2, evList.end()); + float evMedian = evList[evList.size()/2]; + return evMedian; + } + /** * @brief Add the given \p folder to features folders. * @note If SfmData's absolutePath has been set, diff --git a/src/aliceVision/sfmData/View.hpp b/src/aliceVision/sfmData/View.hpp index ce7cc05f21..bf92a94f3f 100644 --- a/src/aliceVision/sfmData/View.hpp +++ b/src/aliceVision/sfmData/View.hpp @@ -191,6 +191,37 @@ class View return (!isPartOfRig() || _isIndependantPose); } + float getEv() const + { + const float shutter = getMetadataShutter(); + const float aperture = getMetadataAperture(); + const float iso = static_cast(getMetadataISO()); + + if(shutter < 0 || aperture < 0 || iso < 0) + return -1; + + // WIKIPEDIA : + log2f(iso/100.f) + float ev = log2f(std::pow(aperture, 2.0f) / shutter) - log2f(iso/100.f); + return ev; + } + + /** + * @brief Get the value of the gap bewteen the view's exposition and a reference exposition + * @param [refEv] the median exposition of all views + * @return the exposure compensation + */ + float getEvCompensation(float refEv) const + { + float evComp = 1.0f; + float comp = getEv() - refEv; + + if(getEv() != -1) + evComp = std::pow(2.0f, comp); + + return evComp; + } + + /** * @brief Return true if the given metadata name exists * @param[in] name The metadata name @@ -319,6 +350,39 @@ class View return -1; } + /** + * @brief Get the corresponding "ExposureTime" (shutter) metadata value + * @return the metadata value float or -1 if no corresponding value + */ + float getMetadataShutter() const + { + if(hasDigitMetadata("ExposureTime")) + return std::stof(getMetadata("ExposureTime")); + return -1; + } + + /** + * @brief Get the corresponding "FNumber" (aperture) metadata value + * @return the metadata value float or -1 if no corresponding value + */ + float getMetadataAperture() const + { + if(hasDigitMetadata("FNumber")) + return std::stof(getMetadata("FNumber")); + return -1; + } + + /** + * @brief Get the corresponding "PhotographicSensitivity" (ISO) metadata value + * @return the metadata value int or -1 if no corresponding value + */ + float getMetadataISO() const + { + if(hasDigitMetadata("Exif:PhotographicSensitivity")) + return std::stoi(getMetadata("Exif:PhotographicSensitivity")); + return -1; + } + /** * @brief Get the corresponding "Orientation" metadata value * @return the enum EEXIFOrientation diff --git a/src/software/pipeline/main_prepareDenseScene.cpp b/src/software/pipeline/main_prepareDenseScene.cpp index 81a11a07e4..39c737240b 100644 --- a/src/software/pipeline/main_prepareDenseScene.cpp +++ b/src/software/pipeline/main_prepareDenseScene.cpp @@ -44,7 +44,8 @@ bool prepareDenseScene(const SfMData& sfmData, const std::string& outFolder, image::EImageFileType outputFileType, bool saveMetadata, - bool saveMatricesFiles) + bool saveMatricesFiles, + bool evCorrection) { // defined view Ids std::set viewIds; @@ -76,6 +77,10 @@ bool prepareDenseScene(const SfMData& sfmData, // export data boost::progress_display progressBar(viewIds.size(), std::cout, "Exporting Scene Undistorted Images\n"); + // for exposure correction + const float medianEv = sfmData.getMedianEv(); + ALICEVISION_LOG_INFO("median Ev : " << medianEv); + #pragma omp parallel for num_threads(3) for(int i = 0; i < viewIds.size(); ++i) { @@ -188,6 +193,22 @@ bool prepareDenseScene(const SfMData& sfmData, Image image, image_ud; readImage(srcImage, image, image::EImageColorSpace::LINEAR); + + //exposure correction + if(evCorrection) + { + float exposureCompensation = view->getEvCompensation(medianEv); + + //metadata & log + metadata.push_back(oiio::ParamValue("AliceVision:EV", view->getEv())); + metadata.push_back(oiio::ParamValue("AliceVision:EVComp", exposureCompensation)); + ALICEVISION_LOG_INFO("image " + std::to_string(viewId) + " Ev : " + std::to_string(view->getEv())); + ALICEVISION_LOG_INFO("image " + std::to_string(viewId) + " Ev compensation : " + std::to_string(exposureCompensation)); + + for(int pix = 0; pix < image.Width() * image.Height(); ++pix) + image(pix) = image(pix) * exposureCompensation; + + } // undistort if(cam->isValid() && cam->have_disto()) @@ -222,6 +243,7 @@ int main(int argc, char *argv[]) int rangeSize = 1; bool saveMetadata = true; bool saveMatricesTxtFiles = false; + bool evCorrection = false; po::options_description allParams("AliceVision prepareDenseScene"); @@ -246,7 +268,9 @@ int main(int argc, char *argv[]) ("rangeStart", po::value(&rangeStart)->default_value(rangeStart), "Range image index start.") ("rangeSize", po::value(&rangeSize)->default_value(rangeSize), - "Range size."); + "Range size.") + ("evCorrection", po::value(&evCorrection)->default_value(evCorrection), + "Correct exposure value."); po::options_description logParams("Log parameters"); logParams.add_options() @@ -324,7 +348,7 @@ int main(int argc, char *argv[]) } // export - if(prepareDenseScene(sfmData, imagesFolders, rangeStart, rangeEnd, outFolder, outputFileType, saveMetadata, saveMatricesTxtFiles)) + if(prepareDenseScene(sfmData, imagesFolders, rangeStart, rangeEnd, outFolder, outputFileType, saveMetadata, saveMatricesTxtFiles, evCorrection)) return EXIT_SUCCESS; return EXIT_FAILURE;