From 3e995ffc02df9499c9492d49c3e0ef3adbdf2faa Mon Sep 17 00:00:00 2001 From: demoulinv Date: Fri, 7 Oct 2022 18:53:29 +0200 Subject: [PATCH] Update color space metadata extraction from read image. First, search AliceVision:ColorSpace metadata in oiio read buf. If non-existent or invalid search oiio:ColorSpace metadata in read buf. If still non-existent or invalid use filename to guess the color space by using the oiio::readmetadata function and then the OCIO configuration file if any. ImageProcessing: add option to keep image filename. --- src/aliceVision/image/io.cpp | 87 +++++++++++++++------ src/aliceVision/image/io.hpp | 2 - src/software/utils/main_imageProcessing.cpp | 9 ++- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 1210fb7a07..aca15d535d 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -39,7 +39,18 @@ namespace if (fs::exists(configOCIOFilePath)) { ALICEVISION_LOG_TRACE("ALICEVISION_OCIO configuration file: '" << configOCIOFilePath << "' found."); - return configOCIOFilePath; + // Check if a sRGB linear color space named "scene-linear Rec.709-sRGB" is present and set as scene_linear role + oiio::ColorConfig colorConfig(configOCIOFilePath); + const std::string linearColorSpace = colorConfig.getColorSpaceNameByRole("scene_linear"); + if (linearColorSpace == "scene-linear Rec.709-sRGB") + { + return configOCIOFilePath; + } + else + { + ALICEVISION_LOG_TRACE("But does not contain a scene_linear role named \"scene-linear Rec.709-sRGB\"."); + ALICEVISION_LOG_TRACE("Use embedded config."); + } } else if (configOCIOFilePath == "") { @@ -51,24 +62,26 @@ namespace } } - char const* OCIO = getenv("OCIO"); - if (OCIO != NULL) - { - configOCIOFilePath = std::string(OCIO); - if (fs::exists(configOCIOFilePath)) - { - ALICEVISION_LOG_TRACE("OCIO configuration file: '" << configOCIOFilePath << "' found."); - return configOCIOFilePath; - } - else if (configOCIOFilePath == "") - { - ALICEVISION_LOG_TRACE("OCIO is empty. Use embedded config..."); - } - else - { - ALICEVISION_LOG_TRACE("OCIO does not point to an existing file. Use embedded config..."); - } - } + // To be uncommented to take OCIO env var in consideration before using the enbedded config file + // + //char const* OCIO = getenv("OCIO"); + //if (OCIO != NULL) + //{ + // configOCIOFilePath = std::string(OCIO); + // if (fs::exists(configOCIOFilePath)) + // { + // ALICEVISION_LOG_TRACE("OCIO configuration file: '" << configOCIOFilePath << "' found."); + // return configOCIOFilePath; + // } + // else if (configOCIOFilePath == "") + // { + // ALICEVISION_LOG_TRACE("OCIO is empty. Use embedded config..."); + // } + // else + // { + // ALICEVISION_LOG_TRACE("OCIO does not point to an existing file. Use embedded config..."); + // } + //} char const* ALICEVISION_ROOT = getenv("ALICEVISION_ROOT"); if (ALICEVISION_ROOT == NULL) @@ -135,7 +148,7 @@ EImageColorSpace EImageColorSpace_stringToEnum(const std::string& dataType) return EImageColorSpace::LINEAR; if(type == "srgb") return EImageColorSpace::SRGB; - if(type == "ACES2065-1") + if(type == "aces2065-1") return EImageColorSpace::ACES2065_1; if(type == "acescg") return EImageColorSpace::ACEScg; @@ -156,7 +169,7 @@ std::string EImageColorSpace_enumToString(const EImageColorSpace dataType) case EImageColorSpace::SRGB: return "srgb"; case EImageColorSpace::ACES2065_1: - return "ACES2065-1"; + return "aces2065-1"; case EImageColorSpace::ACEScg: return "acescg"; case EImageColorSpace::NO_CONVERSION: @@ -169,7 +182,7 @@ bool isValidColorSpace(std::string colorSpace) { const std::string CSlc = boost::to_lower_copy(colorSpace); - return (CSlc == "auto") || (CSlc == "linear") || (CSlc == "srgb") || (CSlc == "aces") || (CSlc == "acescg") || (CSlc == "no_conversion"); + return (CSlc == "auto") || (CSlc == "linear") || (CSlc == "srgb") || (CSlc == "aces2065-1") || (CSlc == "acescg") || (CSlc == "no_conversion"); } std::ostream& operator<<(std::ostream& os, EImageColorSpace dataType) @@ -367,6 +380,16 @@ oiio::ParamValueList readImageMetadata(const std::string& path, int& width, int& if(!in) throw std::runtime_error("Can't find/open image file '" + path + "'."); +#if OIIO_VERSION <= (10000 * 2 + 100 * 0 + 8) // OIIO_VERSION <= 2.0.8 + const std::string formatStr = in->format_name(); + if(formatStr == "raw") + { + // For the RAW plugin: override colorspace as linear (as the content is linear with sRGB primaries but declared as sRGB) + spec.attribute("oiio:ColorSpace", "Linear"); + ALICEVISION_LOG_TRACE("OIIO workaround: RAW input image " << path << " is in Linear."); + } +#endif + width = spec.width; height = spec.height; @@ -460,7 +483,13 @@ void readImage(const std::string& path, configSpec.attribute("raw:use_camera_wb", (imageReadOptions.applyWhiteBalance?1:0)); // white balance correction // use_camera_matrix: Whether to use the embedded color profile, if it is present: 0=never, 1 (default)=only for DNG files, 3=always configSpec.attribute("raw:use_camera_matrix", 3); // use embeded color profile + +#if OIIO_VERSION <= (10000 * 2 + 100 * 0 + 8) // OIIO_VERSION <= 2.0.8 + // In old versions of oiio, there was no Linear option + configSpec.attribute("raw:ColorSpace", "sRGB"); // use colorspace sRGB +#else configSpec.attribute("raw:ColorSpace", "Linear"); // use linear colorspace with sRGB primaries +#endif oiio::ImageBuf inBuf(path, 0, 0, NULL, &configSpec); @@ -479,9 +508,17 @@ void readImage(const std::string& path, if (imageReadOptions.workingColorSpace != EImageColorSpace::NO_CONVERSION) { - std::string inputColorSpace; - inputColorSpace = EImageColorSpace_enumToString(getImageColorSpace(path)); - if (EImageColorSpace_stringToEnum(boost::to_lower_copy(inputColorSpace)) != imageReadOptions.workingColorSpace) + std::string inputColorSpace = inBuf.spec().get_string_attribute("AliceVision:ColorSpace", ""); + if ((inputColorSpace.empty()) || !isValidColorSpace(inputColorSpace)) + { + inputColorSpace = inBuf.spec().get_string_attribute("oiio:ColorSpace", ""); + if ((inputColorSpace.empty()) || !isValidColorSpace(inputColorSpace)) + { + // Try to get color space using filename + inputColorSpace = EImageColorSpace_enumToString(getImageColorSpace(path)); + } + } + if ((EImageColorSpace_stringToEnum(inputColorSpace) != imageReadOptions.workingColorSpace) && isValidColorSpace(inputColorSpace)) { std::string outputColorSpace = (imageReadOptions.workingColorSpace == EImageColorSpace::LINEAR) ? "linear" : EImageColorSpace_enumToString(imageReadOptions.workingColorSpace); oiio::ImageBufAlgo::colorconvert(inBuf, inBuf, inputColorSpace, outputColorSpace, true, "", "", &colorConfigOCIO); diff --git a/src/aliceVision/image/io.hpp b/src/aliceVision/image/io.hpp index 5f6a3e1013..22f8d6ce55 100644 --- a/src/aliceVision/image/io.hpp +++ b/src/aliceVision/image/io.hpp @@ -43,8 +43,6 @@ std::istream& operator>>(std::istream& in, EImageColorSpace& dataType); void initColorConfigOCIO(const std::string& colorConfigFilePath); -EImageColorSpace getImageColorSpace(const std::string imagePath); - /** * @brief Available image file type for pipeline output */ diff --git a/src/software/utils/main_imageProcessing.cpp b/src/software/utils/main_imageProcessing.cpp index bbfb7c87cb..8ec03c4b5e 100644 --- a/src/software/utils/main_imageProcessing.cpp +++ b/src/software/utils/main_imageProcessing.cpp @@ -513,7 +513,10 @@ int aliceVision_main(int argc, char * argv[]) po::options_description optionalParams("Optional parameters"); optionalParams.add_options() ("metadataFolders", po::value>(&metadataFolders)->multitoken(), - "Use images metadata from specific folder(s) instead of those specified in the input images.") + "Use images metadata from specific folder(s) instead of those specified in the input images.") + + ("keepImageFilename", po::value(&pParams.keepImageFilename)->default_value(pParams.keepImageFilename), + "Use original image names instead of view names when saving.") ("reconstructedViewsOnly", po::value(&pParams.reconstructedViewsOnly)->default_value(pParams.reconstructedViewsOnly), "Process only recontructed views or all views.") @@ -706,13 +709,13 @@ int aliceVision_main(int argc, char * argv[]) sfmData::View& view = sfmData.getView(viewId); const fs::path fsPath = viewPath; + const std::string fileName = fsPath.stem().string(); const std::string fileExt = fsPath.extension().string(); const std::string outputExt = extension.empty() ? fileExt : (std::string(".") + extension); - const std::string outputfilePath = (fs::path(outputPath) / (std::to_string(viewId) + outputExt)).generic_string(); + const std::string outputfilePath = (fs::path(outputPath) / ((pParams.keepImageFilename ? fileName : std::to_string(viewId)) + outputExt)).generic_string(); ALICEVISION_LOG_INFO(++i << "/" << size << " - Process view '" << viewId << "'."); - image::ImageReadOptions options; options.workingColorSpace = workingColorSpace; options.applyWhiteBalance = view.getApplyWhiteBalance();