From 8b81b6329a090c1d4ea190ec1a637438323a608c Mon Sep 17 00:00:00 2001 From: demoulinv Date: Mon, 2 May 2022 10:23:07 +0200 Subject: [PATCH 01/15] Add AliceVision Color Space metadata Add AliceVision:ColorSpace metadata when writing image. Manage AliceVision:ColorSpace metadata when reading image. * Renaming Complete renaming from outputColorSpace to workingColorSpace when using read image. * OIIO colorConfig object definition and initialization. OIIO colorConfig object is defined within io.cpp only. It is initialized with the default OCIO color config file that must be located in the directory src/aliceVision/image/share/aliceVision. A function declared in io.hpp is available to set another OCIO config file if needed. Search of OCIO config file strategy: First try with the ALICEVISION_OCIO env variable. If unsuccessful, second try with the standardized OCIO env variable. If unsuccessful, third try with ALICEVISION_ROOT env variable to extract the embedded config file. * image io Add log trace when OCIO config file found. Update OCIO config file by removing the possibility to call the OCIO V1 method to identify the color space from the file name. Default color space is still sRGB. When reading image, avoid searching input image color space if no conversion is needed. If conversion is needed, check color space validity after getting it from image metadate or image file name. Move config.ocio file in subdirectory to ease testing. Set ALICEVISION_ROOT environment variable in some tests related to image. * Workflow Add ALICEVISION_ROOT environment variable in continuous integration. * Working Color Space implementation in imageProcessing Transmit working color space to write image and convert to output color space if needed. Working color space is the color space in which the processing is done. Input images are converted in this color space by the readImage method. --- .github/workflows/continuous-integration.yml | 2 + src/CMakeLists.txt | 4 - src/aliceVision/hdr/sampling.cpp | 2 +- src/aliceVision/image/CMakeLists.txt | 2 +- src/aliceVision/image/io.cpp | 213 ++++++++++++++---- src/aliceVision/image/io.hpp | 23 +- src/aliceVision/image/io_test.cpp | 17 +- src/aliceVision/image/resampling_test.cpp | 1 + .../image/{ => share/aliceVision}/config.ocio | 2 +- src/software/pipeline/main_LdrToHdrMerge.cpp | 2 +- .../pipeline/main_panoramaPrepareImages.cpp | 2 +- .../utils/main_colorCheckerCorrection.cpp | 2 +- .../utils/main_colorCheckerDetection.cpp | 4 +- src/software/utils/main_imageProcessing.cpp | 22 +- 14 files changed, 226 insertions(+), 72 deletions(-) rename src/aliceVision/image/{ => share/aliceVision}/config.ocio (99%) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5c44c56846..4d01a57c70 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -27,6 +27,7 @@ jobs: DEPS_INSTALL_DIR: /opt/AliceVision_install BUILD_TYPE: Release CTEST_OUTPUT_ON_FAILURE: 1 + ALICEVISION_ROOT: ${{ github.workspace }}/../AV_install steps: - uses: actions/checkout@v1 @@ -106,6 +107,7 @@ jobs: # tripletPath: '${{ github.workspace }}\..\vcpkg\triplets\community\x64-windows-release.cmake' BUILD_TYPE: Release CTEST_OUTPUT_ON_FAILURE: 1 + ALICEVISION_ROOT: '${{ github.workspace }}/install' COMMIT_ID: 8e8a3d7c1a6f7f587b486663b1e814911e6f2342 steps: - name: Checkout diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2025349919..5adcf51e01 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -330,10 +330,6 @@ endif() find_package(OpenImageIO 2.0.9 REQUIRED) if(OPENIMAGEIO_FOUND OR OpenImageIO_FOUND) message(STATUS "OpenImageIO found.") - if(UNIX) - # Add DL dependency on linux - set(OPENIMAGEIO_LIBRARIES "${OPENIMAGEIO_LIBRARIES};dl") - endif() else() message(SEND_ERROR "Failed to find OpenImageIO.") endif() diff --git a/src/aliceVision/hdr/sampling.cpp b/src/aliceVision/hdr/sampling.cpp index b046721434..75a7694c10 100644 --- a/src/aliceVision/hdr/sampling.cpp +++ b/src/aliceVision/hdr/sampling.cpp @@ -172,7 +172,7 @@ bool Sampling::extractSamplesFromImages(std::vector& out_samples, c const double exposure = times[idBracket]; image::ImageReadOptions options; - options.outputColorSpace = colorspace; + options.workingColorSpace = colorspace; options.applyWhiteBalance = applyWhiteBalance; // Load image diff --git a/src/aliceVision/image/CMakeLists.txt b/src/aliceVision/image/CMakeLists.txt index 75dd52aa5e..e5b21403ed 100644 --- a/src/aliceVision/image/CMakeLists.txt +++ b/src/aliceVision/image/CMakeLists.txt @@ -45,7 +45,7 @@ alicevision_add_library(aliceVision_image ) # Install config.ocio -install(FILES config.ocio DESTINATION ${CMAKE_INSTALL_DATADIR}/aliceVision) +install(FILES ./share/aliceVision/config.ocio DESTINATION ${CMAKE_INSTALL_DATADIR}/aliceVision) # Unit tests alicevision_add_test(image_test.cpp NAME "image" LINKS aliceVision_image) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 03746ace9c..53a3c91dd9 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -26,15 +26,101 @@ namespace fs = boost::filesystem; +namespace +{ + std::string getDefaultColorConfigFilePath() + { + std::string configOCIOFilePath = ""; + + char const* ALICEVISION_OCIO = getenv("ALICEVISION_OCIO"); + if (ALICEVISION_OCIO != NULL) + { + configOCIOFilePath = std::string(ALICEVISION_OCIO); + if (fs::exists(configOCIOFilePath)) + { + ALICEVISION_LOG_TRACE("ALICEVISION_OCIO configuration file: '" << configOCIOFilePath << "' found."); + return configOCIOFilePath; + } + else if (configOCIOFilePath == "") + { + ALICEVISION_LOG_TRACE("ALICEVISION_OCIO is empty. Try OCIO..."); + } + else + { + ALICEVISION_LOG_TRACE("ALICEVISION_OCIO does not point to an existing file. Try OCIO..."); + } + } + + 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) + { + ALICEVISION_THROW_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); + } + configOCIOFilePath = std::string(ALICEVISION_ROOT); + configOCIOFilePath.append("/share/aliceVision/config.ocio"); + + if (!fs::exists(configOCIOFilePath)) + { + ALICEVISION_THROW_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); + configOCIOFilePath = ""; + } + else + { + ALICEVISION_LOG_TRACE("Embedded OCIO configuration file: '" << configOCIOFilePath << "' found."); + } + + return configOCIOFilePath; + } + oiio::ColorConfig colorConfigOCIO(getDefaultColorConfigFilePath()); +} + namespace aliceVision { namespace image { +void initColorConfigOCIO(const std::string& colorConfigFilePath) +{ + colorConfigOCIO.reset(colorConfigFilePath); + if (!colorConfigOCIO.supportsOpenColorIO()) + { + ALICEVISION_THROW_ERROR("OpenImageIO has not been compiled with OCIO."); + } + const std::string error = colorConfigOCIO.geterror(); + if (!error.empty()) + { + ALICEVISION_THROW_ERROR("Erroneous OCIO config file " << colorConfigFilePath << ":" << std::endl << error); + } + int ocioVersion = colorConfigOCIO.OpenColorIO_version_hex(); + int ocioMajor = (ocioVersion & 0xFF000000) >> 24; + int ocioMinor = (ocioVersion & 0x00FF0000) >> 16; + int ocioPatch = (ocioVersion & 0x0000FF00) >> 8; + ALICEVISION_LOG_INFO("OCIO color config initialized with OCIO version: " << ocioMajor << "." << ocioMinor << "." << ocioPatch); +} + std::string EImageColorSpace_informations() { return EImageColorSpace_enumToString(EImageColorSpace::AUTO) + ", " + EImageColorSpace_enumToString(EImageColorSpace::LINEAR) + ", " + EImageColorSpace_enumToString(EImageColorSpace::SRGB) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::ACES) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::ACES2065_1) + ", " + EImageColorSpace_enumToString(EImageColorSpace::ACEScg) + ", " + EImageColorSpace_enumToString(EImageColorSpace::LAB) + ", " + EImageColorSpace_enumToString(EImageColorSpace::XYZ) + ", " + @@ -51,8 +137,8 @@ EImageColorSpace EImageColorSpace_stringToEnum(const std::string& dataType) return EImageColorSpace::LINEAR; if(type == "srgb") return EImageColorSpace::SRGB; - if(type == "aces") - return EImageColorSpace::ACES; + if(type == "ACES2065-1") + return EImageColorSpace::ACES2065_1; if(type == "acescg") return EImageColorSpace::ACEScg; if(type == "lab") @@ -75,8 +161,8 @@ std::string EImageColorSpace_enumToString(const EImageColorSpace dataType) return "linear"; case EImageColorSpace::SRGB: return "srgb"; - case EImageColorSpace::ACES: - return "aces"; + case EImageColorSpace::ACES2065_1: + return "ACES2065-1"; case EImageColorSpace::ACEScg: return "acescg"; case EImageColorSpace::LAB: @@ -95,7 +181,7 @@ std::string EImageColorSpace_enumToOIIOString(const EImageColorSpace colorSpace) { case EImageColorSpace::SRGB: return "sRGB"; case EImageColorSpace::LINEAR: return "Linear"; - case EImageColorSpace::ACES: return "aces"; + case EImageColorSpace::ACES2065_1: return "aces2065-1"; case EImageColorSpace::ACEScg: return "ACEScg"; default: ; } @@ -107,7 +193,7 @@ EImageColorSpace EImageColorSpace_OIIOstringToEnum(const std::string& colorspace { if (colorspace == "Linear") return EImageColorSpace::LINEAR; if (colorspace == "sRGB") return EImageColorSpace::SRGB; - if (colorspace == "aces") return EImageColorSpace::ACES; + if (colorspace == "aces2065-1") return EImageColorSpace::ACES2065_1; if (colorspace == "ACEScg") return EImageColorSpace::ACEScg; throw std::out_of_range("No EImageColorSpace defined for string: " + colorspace); @@ -119,7 +205,7 @@ bool EImageColorSpace_isSupportedOIIOEnum(const EImageColorSpace& colorspace) { case EImageColorSpace::SRGB: return true; case EImageColorSpace::LINEAR: return true; - case EImageColorSpace::ACES: return true; + case EImageColorSpace::ACES2065_1: return true; case EImageColorSpace::ACEScg: return true; default: return false; } @@ -129,7 +215,7 @@ bool EImageColorSpace_isSupportedOIIOstring(const std::string& colorspace) { if (colorspace == "Linear") return true; if (colorspace == "sRGB") return true; - if (colorspace == "aces") return true; + if (colorspace == "aces2065-1") return true; if (colorspace == "ACEScg") return true; return false; } @@ -147,6 +233,52 @@ std::istream& operator>>(std::istream& in, EImageColorSpace& dataType) return in; } +EImageColorSpace getImageColorSpace(const std::string imagePath) +{ + oiio::ImageSpec metadataSpec; + + metadataSpec.extra_attribs = readImageMetadata(imagePath); + + std::string colorSpace = metadataSpec.get_string_attribute("AliceVision:ColorSpace", ""); // default image color space is empty + if (!colorSpace.empty()) + { + ALICEVISION_LOG_TRACE("Read image " << imagePath << " (encoded in " << colorSpace << " colorspace according to AliceVision:ColorSpace metadata)."); + } + else + { + colorSpace = metadataSpec.get_string_attribute("oiio:ColorSpace", ""); // Check oiio metadata + if ((colorSpace == "Linear") || (colorSpace == "")) + { + std::string colorSpaceFromFileName = colorConfigOCIO.getColorSpaceFromFilepath(imagePath); + if (!colorSpaceFromFileName.empty()) + { + ALICEVISION_LOG_TRACE("Read image " << imagePath << " (encoded in " << colorSpaceFromFileName << " colorspace according to file name)."); + colorSpace = colorSpaceFromFileName; + } + else if (!colorSpace.empty()) + { + ALICEVISION_LOG_TRACE("Read image " << imagePath << " (encoded in " << colorSpace << " colorspace according to oiio:ColorSpace metadata)."); + } + else + { + ALICEVISION_LOG_TRACE("Read image " << imagePath << " (no colorspace info, supposed to be encoded in sRGB)."); + colorSpace = "sRGB"; + } + } + } + + if (!EImageColorSpace_isSupportedOIIOstring(colorSpace)) + { + size_t npos = imagePath.find_last_of("."); + std::string ext = imagePath.substr(npos + 1); + std::string forcedColorSpace = (ext == "exr" || ext == "EXR") ? "linear" : "sRGB"; + + ALICEVISION_LOG_WARNING("The color space " << colorSpace << " detected for " << imagePath << " is not supported. Force Color space to " << forcedColorSpace << "."); + colorSpace = forcedColorSpace; + } + + return EImageColorSpace_stringToEnum(colorSpace); +} std::string EImageFileType_informations() { @@ -221,7 +353,6 @@ bool isSupported(const std::string& ext) return (std::find(start, end, boost::to_lower_copy(ext)) != end); } - std::string EStorageDataType_informations() { return EStorageDataType_enumToString(EStorageDataType::Float) + ", " + @@ -455,19 +586,19 @@ void readImage(const std::string& path, if (inBuf.spec().nchannels == 2) throw std::runtime_error("Load of 2 channels is not supported. Image file: '" + path + "'."); - // color conversion - if (imageReadOptions.outputColorSpace == EImageColorSpace::AUTO) - throw std::runtime_error("You must specify a requested color space for image file '" + path + "'."); + // color conversion + if(imageReadOptions.workingColorSpace == EImageColorSpace::AUTO) + throw std::runtime_error("You must specify a requested color space for image file '" + path + "'."); - // Get color space name. Default image color space is sRGB - const std::string& fromColorSpaceName = inBuf.spec().get_string_attribute("oiio:ColorSpace", "sRGB"); + // Get color space name. Default image color space is sRGB + const std::string& fromColorSpaceName = inBuf.spec().get_string_attribute("oiio:ColorSpace", "sRGB"); - ALICEVISION_LOG_TRACE("Read image " << path << " (encoded in " << fromColorSpaceName << " colorspace)."); + ALICEVISION_LOG_TRACE("Read image " << path << " (encoded in " << fromColorSpaceName << " colorspace)."); - if (imageReadOptions.outputColorSpace != image::EImageColorSpace::NO_CONVERSION) - { - imageAlgo::colorconvert(inBuf, fromColorSpaceName, imageReadOptions.outputColorSpace); - } + if (imageReadOptions.workingColorSpace != image::EImageColorSpace::NO_CONVERSION) + { + imageAlgo::colorconvert(inBuf, fromColorSpaceName, imageReadOptions.workingColorSpace); + } // convert to grayscale if needed if(nchannels == 1 && inBuf.spec().nchannels >= 3) @@ -479,7 +610,7 @@ void readImage(const std::string& path, // compute luminance via a weighted sum of R,G,B // (assuming Rec709 primaries and a linear scale) - const float weights[3] = {.2126f, .7152f, .0722f}; + const float weights[3] = {.2126f, .7152f, .0722f}; // To be changed if not sRGB Rec 709 Linear. oiio::ImageBuf grayscaleBuf; oiio::ImageBufAlgo::channel_sum(grayscaleBuf, inBuf, weights, convertionROI); inBuf.copy(grayscaleBuf); @@ -613,7 +744,10 @@ void writeImage(const std::string& path, { imageSpec.set_roi_full(roi); } + std::string currentColorSpace = imageSpec.get_string_attribute("AliceVision:ColorSpace", "Linear"); + imageSpec.attribute("AliceVision:ColorSpace", (colorspace.to == EImageColorSpace::NO_CONVERSION) ? currentColorSpace : EImageColorSpace_enumToString(colorspace.to)); + const oiio::ImageBuf imgBuf = oiio::ImageBuf(imageSpec, const_cast(image.data())); // original image buffer const oiio::ImageBuf* outBuf = &imgBuf; // buffer to write @@ -623,7 +757,7 @@ void writeImage(const std::string& path, // Do nothing. Note that calling imageAlgo::colorconvert() will copy the source buffer // even if no conversion is needed. } - else if((colorspace.to == EImageColorSpace::ACES) || (colorspace.to == EImageColorSpace::ACEScg)) + else if((colorspace.to == EImageColorSpace::ACES2065_1) || (colorspace.to == EImageColorSpace::ACEScg)) { const auto colorConfigPath = getAliceVisionOCIOConfig(); if (colorConfigPath.empty()) @@ -679,7 +813,7 @@ void writeImage(const std::string& path, // write image if(!outBuf->write(tmpPath)) - throw std::runtime_error("Can't write output image file '" + path + "'."); + ALICEVISION_THROW_ERROR("Can't write output image file '" + path + "'."); // rename temporary filename fs::rename(tmpPath, path); @@ -773,49 +907,49 @@ void readImage(const std::string& path, Image& image, const ImageReadO readImage(path, oiio::TypeDesc::UINT8, 3, image, imageReadOptions); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace,const oiio::ParamValueList& metadata) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace,const oiio::ParamValueList& metadata) { - writeImageNoFloat(path, oiio::TypeDesc::UINT8, image, imageColorSpace, metadata); + writeImageNoFloat(path, oiio::TypeDesc::UINT8, image, outputImageColorSpace, metadata); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata) { - writeImageNoFloat(path, oiio::TypeDesc::INT32, image, imageColorSpace, metadata); + writeImageNoFloat(path, oiio::TypeDesc::INT32, image, outputImageColorSpace, metadata); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata) { - writeImageNoFloat(path, oiio::TypeDesc::UINT32, image, imageColorSpace, metadata); + writeImageNoFloat(path, oiio::TypeDesc::UINT32, image, outputImageColorSpace, metadata); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata, const oiio::ROI& roi) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata, const oiio::ROI& roi) { writeImage(path, oiio::TypeDesc::FLOAT, 4, image, - OutputFileColorSpace{EImageColorSpace::LINEAR, imageColorSpace}, metadata,roi); + OutputFileColorSpace{EImageColorSpace::LINEAR, outputImageColorSpace }, metadata,roi); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace,const oiio::ParamValueList& metadata) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace,const oiio::ParamValueList& metadata) { writeImage(path, oiio::TypeDesc::UINT8, 4, image, - OutputFileColorSpace{EImageColorSpace::LINEAR, imageColorSpace}, metadata); + OutputFileColorSpace{EImageColorSpace::LINEAR, outputImageColorSpace }, metadata); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata, const oiio::ROI &roi) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata, const oiio::ROI &roi) { writeImage(path, oiio::TypeDesc::FLOAT, 3, image, - OutputFileColorSpace{EImageColorSpace::LINEAR, imageColorSpace}, metadata,roi); + OutputFileColorSpace{EImageColorSpace::LINEAR, outputImageColorSpace }, metadata,roi); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata, const oiio::ROI& roi) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata, const oiio::ROI& roi) { writeImage(path, oiio::TypeDesc::FLOAT, 1, image, - OutputFileColorSpace{EImageColorSpace::LINEAR, imageColorSpace}, metadata,roi); + OutputFileColorSpace{EImageColorSpace::LINEAR, outputImageColorSpace }, metadata,roi); } -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace,const oiio::ParamValueList& metadata) +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace,const oiio::ParamValueList& metadata) { writeImage(path, oiio::TypeDesc::UINT8, 3, image, - OutputFileColorSpace{EImageColorSpace::LINEAR, imageColorSpace}, metadata); + OutputFileColorSpace{EImageColorSpace::LINEAR, outputImageColorSpace }, metadata); } void writeImage(const std::string& path, const Image& image, OutputFileColorSpace colorspace, @@ -1049,7 +1183,6 @@ void writeImage(const std::string& path, colorspace.to = image::EImageColorSpace::LINEAR; } - ALICEVISION_LOG_DEBUG("[IO] Write Image: " << path << std::endl << "\t- width: " << width << std::endl << "\t- height: " << height << std::endl diff --git a/src/aliceVision/image/io.hpp b/src/aliceVision/image/io.hpp index 1e2f912489..678d4b8ad9 100644 --- a/src/aliceVision/image/io.hpp +++ b/src/aliceVision/image/io.hpp @@ -13,6 +13,7 @@ #include #include +#include #include @@ -32,7 +33,7 @@ enum class EImageColorSpace AUTO, LINEAR, SRGB, - ACES, + ACES2065_1, ACEScg, LAB, XYZ, @@ -88,11 +89,11 @@ enum class EImageFileType struct ImageReadOptions { ImageReadOptions(EImageColorSpace colorSpace = EImageColorSpace::AUTO, bool useWhiteBalance = true, const oiio::ROI & roi = oiio::ROI()) : - outputColorSpace(colorSpace), applyWhiteBalance(useWhiteBalance), subROI(roi) + workingColorSpace(colorSpace), applyWhiteBalance(useWhiteBalance), subROI(roi) { } - EImageColorSpace outputColorSpace; + EImageColorSpace workingColorSpace; bool applyWhiteBalance; //ROI for this image. @@ -305,14 +306,14 @@ void readImageDirect(const std::string& path, Image& image); * @param[in] path The given path to the image * @param[in] image The output image buffer */ -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace,const oiio::ParamValueList& metadata = oiio::ParamValueList(),const oiio::ROI& roi = oiio::ROI()); -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace,const oiio::ParamValueList& metadata = oiio::ParamValueList(),const oiio::ROI& roi = oiio::ROI()); -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace,const oiio::ParamValueList& metadata = oiio::ParamValueList(),const oiio::ROI& roi = oiio::ROI()); -void writeImage(const std::string& path, const Image& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace,const oiio::ParamValueList& metadata = oiio::ParamValueList(),const oiio::ROI& roi = oiio::ROI()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace,const oiio::ParamValueList& metadata = oiio::ParamValueList(),const oiio::ROI& roi = oiio::ROI()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace,const oiio::ParamValueList& metadata = oiio::ParamValueList(),const oiio::ROI& roi = oiio::ROI()); +void writeImage(const std::string& path, const Image& image, EImageColorSpace outputImageColorSpace, const oiio::ParamValueList& metadata = oiio::ParamValueList()); void writeImage(const std::string& path, const Image& image, OutputFileColorSpace imageColorSpace, diff --git a/src/aliceVision/image/io_test.cpp b/src/aliceVision/image/io_test.cpp index 6f01a2c509..e4c848e243 100644 --- a/src/aliceVision/image/io_test.cpp +++ b/src/aliceVision/image/io_test.cpp @@ -22,8 +22,23 @@ using namespace aliceVision; using namespace aliceVision::image; using std::string; +#ifdef WIN32 +int setenv(const char* name, const char* value, int overwrite) +{ + int errcode = 0; + if (!overwrite) { + size_t envsize = 0; + errcode = getenv_s(&envsize, NULL, 0, name); + if (errcode || envsize) return errcode; + } + return _putenv_s(name, value); +} +#endif + +int err = setenv("ALICEVISION_ROOT", std::string(THIS_SOURCE_DIR).c_str(), 1); + // tested extensions -static std::vector extensions = {"jpg", "png", "pgm", "ppm", "tiff", "exr"}; +static std::vector extensions = { "jpg", "png", "pgm", "ppm", "tiff", "exr" }; BOOST_AUTO_TEST_CASE(read_unexisting) { Image image; diff --git a/src/aliceVision/image/resampling_test.cpp b/src/aliceVision/image/resampling_test.cpp index 1a48513414..7fcfacd667 100644 --- a/src/aliceVision/image/resampling_test.cpp +++ b/src/aliceVision/image/resampling_test.cpp @@ -19,6 +19,7 @@ using namespace aliceVision; using namespace aliceVision::image; + BOOST_AUTO_TEST_CASE(Ressampling_SampleSamePosition) { Image image; diff --git a/src/aliceVision/image/config.ocio b/src/aliceVision/image/share/aliceVision/config.ocio similarity index 99% rename from src/aliceVision/image/config.ocio rename to src/aliceVision/image/share/aliceVision/config.ocio index 3c90c26ee8..a6969d5b04 100644 --- a/src/aliceVision/image/config.ocio +++ b/src/aliceVision/image/share/aliceVision/config.ocio @@ -64,7 +64,7 @@ file_rules: # # The next rule uses the OCIO v1 method of searching the path for all colorspaces in the config. # - - ! {name: ColorSpaceNamePathSearch} +# - ! {name: ColorSpaceNamePathSearch} # # The rules are ordered, highest priority first. OCIO takes the path to a file and applies # the rules one-by-one until there is a match. The last rule, "Default", always matches. diff --git a/src/software/pipeline/main_LdrToHdrMerge.cpp b/src/software/pipeline/main_LdrToHdrMerge.cpp index da87d7e379..2136f408be 100644 --- a/src/software/pipeline/main_LdrToHdrMerge.cpp +++ b/src/software/pipeline/main_LdrToHdrMerge.cpp @@ -280,7 +280,7 @@ int aliceVision_main(int argc, char** argv) ALICEVISION_LOG_INFO("Load " << filepath); image::ImageReadOptions options; - options.outputColorSpace = image::EImageColorSpace::SRGB; + options.workingColorSpace = image::EImageColorSpace::SRGB; options.applyWhiteBalance = group[i]->getApplyWhiteBalance(); image::readImage(filepath, images[i], options); diff --git a/src/software/pipeline/main_panoramaPrepareImages.cpp b/src/software/pipeline/main_panoramaPrepareImages.cpp index 14e55e55d2..5fa6ecf6cb 100644 --- a/src/software/pipeline/main_panoramaPrepareImages.cpp +++ b/src/software/pipeline/main_panoramaPrepareImages.cpp @@ -286,7 +286,7 @@ int aliceVision_main(int argc, char* argv[]) image::Image originalImage; image::ImageReadOptions options; - options.outputColorSpace = image::EImageColorSpace::LINEAR; + options.workingColorSpace = image::EImageColorSpace::LINEAR; options.applyWhiteBalance = v.second->getApplyWhiteBalance(); diff --git a/src/software/utils/main_colorCheckerCorrection.cpp b/src/software/utils/main_colorCheckerCorrection.cpp index 08a45607d2..1d1b524cc9 100644 --- a/src/software/utils/main_colorCheckerCorrection.cpp +++ b/src/software/utils/main_colorCheckerCorrection.cpp @@ -269,7 +269,7 @@ int aliceVision_main(int argc, char** argv) // Read image options and load image image::ImageReadOptions options; - options.outputColorSpace = image::EImageColorSpace::NO_CONVERSION; + options.workingColorSpace = image::EImageColorSpace::NO_CONVERSION; options.applyWhiteBalance = view.getApplyWhiteBalance(); image::Image image; diff --git a/src/software/utils/main_colorCheckerDetection.cpp b/src/software/utils/main_colorCheckerDetection.cpp index b956c5c90a..81e95b8103 100644 --- a/src/software/utils/main_colorCheckerDetection.cpp +++ b/src/software/utils/main_colorCheckerDetection.cpp @@ -498,7 +498,7 @@ int aliceVision_main(int argc, char** argv) std::to_string(view.getViewId()), view.getMetadataBodySerialNumber(), view.getMetadataLensSerialNumber() }; - imgOpt.readOptions.outputColorSpace = image::EImageColorSpace::SRGB; + imgOpt.readOptions.workingColorSpace = image::EImageColorSpace::SRGB; imgOpt.readOptions.applyWhiteBalance = view.getApplyWhiteBalance(); detectColorChecker(detectedCCheckers, imgOpt, settings); } @@ -546,7 +546,7 @@ int aliceVision_main(int argc, char** argv) ALICEVISION_LOG_INFO(++counter << "/" << size << " - Process image at: '" << imgSrcPath << "'."); ImageOptions imgOpt; imgOpt.imgFsPath = imgSrcPath; - imgOpt.readOptions.outputColorSpace = image::EImageColorSpace::SRGB; + imgOpt.readOptions.workingColorSpace = image::EImageColorSpace::SRGB; detectColorChecker(detectedCCheckers, imgOpt, settings); } diff --git a/src/software/utils/main_imageProcessing.cpp b/src/software/utils/main_imageProcessing.cpp index 7d627e9056..bbfb7c87cb 100644 --- a/src/software/utils/main_imageProcessing.cpp +++ b/src/software/utils/main_imageProcessing.cpp @@ -26,7 +26,7 @@ // These constants define the current software version. // They must be updated when the command line is changed. -#define ALICEVISION_SOFTWARE_VERSION_MAJOR 2 +#define ALICEVISION_SOFTWARE_VERSION_MAJOR 3 #define ALICEVISION_SOFTWARE_VERSION_MINOR 0 using namespace aliceVision; @@ -404,7 +404,7 @@ void processImage(image::Image& image, const ProcessingParams } void saveImage(image::Image& image, const std::string& inputPath, const std::string& outputPath, - const std::vector& metadataFolders, const EImageFormat outputFormat, + const std::vector& metadataFolders, const image::EImageColorSpace workingColorSpace, const EImageFormat outputFormat, const image::EImageColorSpace outputColorSpace, const image::EStorageDataType storageDataType) { // Read metadata path @@ -450,6 +450,8 @@ void saveImage(image::Image& image, const std::string& inputP oiio::ParamValueList metadata = image::readImageMetadata(metadataFilePath); + metadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", (workingColorSpace == image::EImageColorSpace::LINEAR) ? "Linear" : image::EImageColorSpace_enumToString(workingColorSpace))); + if(isEXR) { // Select storage data type @@ -486,6 +488,7 @@ int aliceVision_main(int argc, char * argv[]) std::vector metadataFolders; std::string outputPath; EImageFormat outputFormat = EImageFormat::RGBA; + image::EImageColorSpace workingColorSpace = image::EImageColorSpace::LINEAR; image::EImageColorSpace outputColorSpace = image::EImageColorSpace::LINEAR; image::EStorageDataType storageDataType = image::EStorageDataType::Float; std::string extension; @@ -562,6 +565,9 @@ int aliceVision_main(int argc, char * argv[]) " * A, B: parameters that have a different interpretation depending on the method chosen.\n" " * mono: If is true, a single noise value will be applied to all channels otherwise a separate noise value will be computed for each channel.") + ("workingColorSpace", po::value(&workingColorSpace)->default_value(workingColorSpace), + ("Working color space: " + image::EImageColorSpace_informations()).c_str()) + ("outputFormat", po::value(&outputFormat)->default_value(outputFormat), "Output image format (rgba, rgb, grayscale)") @@ -611,7 +617,7 @@ int aliceVision_main(int argc, char * argv[]) ALICEVISION_COUT("Program called with the following parameters:"); ALICEVISION_COUT(vm); - // Set verbose level + // Set verbose level system::Logger::get()->setLogLevel(verboseLevel); // check user choose at least one input option @@ -708,7 +714,7 @@ int aliceVision_main(int argc, char * argv[]) image::ImageReadOptions options; - options.outputColorSpace = image::EImageColorSpace::LINEAR; + options.workingColorSpace = workingColorSpace; options.applyWhiteBalance = view.getApplyWhiteBalance(); // Read original image @@ -733,7 +739,7 @@ int aliceVision_main(int argc, char * argv[]) processImage(image, pParams); // Save the image - saveImage(image, viewPath, outputfilePath, metadataFolders, outputFormat, outputColorSpace, storageDataType); + saveImage(image, viewPath, outputfilePath, metadataFolders, workingColorSpace, outputFormat, outputColorSpace, storageDataType); // Update view for this modification view.setImagePath(outputfilePath); @@ -810,7 +816,7 @@ int aliceVision_main(int argc, char * argv[]) } int i = 0; - for(const std::string& inputFilePath : filesStrPaths) + for (const std::string& inputFilePath : filesStrPaths) { const fs::path path = fs::path(inputFilePath); const std::string filename = path.stem().string(); @@ -822,13 +828,13 @@ int aliceVision_main(int argc, char * argv[]) // Read original image image::Image image; - image::readImage(inputFilePath, image, image::EImageColorSpace::LINEAR); + image::readImage(inputFilePath, image, workingColorSpace); // Image processing processImage(image, pParams); // Save the image - saveImage(image, inputFilePath, outputFilePath, metadataFolders, outputFormat, outputColorSpace, storageDataType); + saveImage(image, inputFilePath, outputFilePath, metadataFolders, workingColorSpace, outputFormat, outputColorSpace, storageDataType); } } From 00402102c174880c0270301fc3443eed33b3103a Mon Sep 17 00:00:00 2001 From: demoulinv Date: Tue, 4 Oct 2022 20:54:09 +0200 Subject: [PATCH 02/15] [software] Update some panorama nodes to enable computation in ACEScg. --- src/software/pipeline/main_LdrToHdrMerge.cpp | 1 + src/software/pipeline/main_panoramaCompositing.cpp | 9 ++++++++- src/software/pipeline/main_panoramaMerging.cpp | 7 ++++++- src/software/pipeline/main_panoramaWarping.cpp | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/software/pipeline/main_LdrToHdrMerge.cpp b/src/software/pipeline/main_LdrToHdrMerge.cpp index 2136f408be..1d6c8187d8 100644 --- a/src/software/pipeline/main_LdrToHdrMerge.cpp +++ b/src/software/pipeline/main_LdrToHdrMerge.cpp @@ -316,6 +316,7 @@ int aliceVision_main(int argc, char** argv) // Write an image with parameters from the target view oiio::ParamValueList targetMetadata = image::readImageMetadata(targetView->getImagePath()); targetMetadata.push_back(oiio::ParamValue("AliceVision:storageDataType", image::EStorageDataType_enumToString(storageDataType))); + targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", image::EImageColorSpace_enumToString(image::EImageColorSpace::LINEAR))); image::writeImage(hdrImagePath, HDRimage, image::EImageColorSpace::AUTO, targetMetadata); } diff --git a/src/software/pipeline/main_panoramaCompositing.cpp b/src/software/pipeline/main_panoramaCompositing.cpp index fa90959c5a..948fa2bf43 100644 --- a/src/software/pipeline/main_panoramaCompositing.cpp +++ b/src/software/pipeline/main_panoramaCompositing.cpp @@ -348,6 +348,12 @@ bool processImage(const PanoramaMap & panoramaMap, const std::string & composite bool hasFailed = false; + // Load metadata to get image color space + std::string colorSpace; + const std::string firstImagePath = (fs::path(warpingFolder) / (std::to_string(overlappingViews[0]) + ".exr")).string(); + oiio::ParamValueList srcMetadata = image::readImageMetadata(firstImagePath); + colorSpace = srcMetadata.get_string("AliceVision:ColorSpace", "Linear"); + #pragma omp parallel for for (int posCurrent = 0; posCurrent < overlappingViews.size(); posCurrent++) { @@ -538,8 +544,9 @@ bool processImage(const PanoramaMap & panoramaMap, const std::string & composite metadata.push_back(oiio::ParamValue("AliceVision:offsetY", int(referenceBoundingBox.top))); metadata.push_back(oiio::ParamValue("AliceVision:panoramaWidth", int(panoramaMap.getWidth()))); metadata.push_back(oiio::ParamValue("AliceVision:panoramaHeight", int(panoramaMap.getHeight()))); + metadata.push_back(oiio::ParamValue("AliceVision:ColorSpace", colorSpace)); - image::writeImage(outputFilePath, output, image::EImageColorSpace::LINEAR, metadata); + image::writeImage(outputFilePath, output, image::EImageColorSpace_stringToEnum(colorSpace), metadata); return true; } diff --git a/src/software/pipeline/main_panoramaMerging.cpp b/src/software/pipeline/main_panoramaMerging.cpp index 23db5665ec..260e645d53 100644 --- a/src/software/pipeline/main_panoramaMerging.cpp +++ b/src/software/pipeline/main_panoramaMerging.cpp @@ -116,6 +116,7 @@ int aliceVision_main(int argc, char** argv) bool first = true; image::Image panorama; + std::string colorSpace; for (auto viewItem : sfmData.getViews()) { @@ -136,6 +137,7 @@ int aliceVision_main(int argc, char** argv) if (first) { panorama = image::Image(panoramaWidth, panoramaHeight, true, image::RGBAfColor(0.0f, 0.0f, 0.f, 0.0f)); + colorSpace = metadata.find("AliceVision:ColorSpace")->get_string(); first = false; } @@ -162,9 +164,12 @@ int aliceVision_main(int argc, char** argv) } } + image::EImageColorSpace outputColorSpace = colorSpace.empty() ? image::EImageColorSpace::AUTO : image::EImageColorSpace_stringToEnum(colorSpace); + oiio::ParamValueList targetMetadata; targetMetadata.push_back(oiio::ParamValue("AliceVision:storageDataType", image::EStorageDataType_enumToString(storageDataType))); - image::writeImage(outputPanoramaPath, panorama, image::EImageColorSpace::AUTO, targetMetadata); + targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", colorSpace = colorSpace.empty() ? "Linear" : colorSpace)); + image::writeImage(outputPanoramaPath, panorama, outputColorSpace, targetMetadata); return EXIT_SUCCESS; } diff --git a/src/software/pipeline/main_panoramaWarping.cpp b/src/software/pipeline/main_panoramaWarping.cpp index 43877331c5..3d036464b1 100644 --- a/src/software/pipeline/main_panoramaWarping.cpp +++ b/src/software/pipeline/main_panoramaWarping.cpp @@ -356,7 +356,7 @@ int aliceVision_main(int argc, char** argv) std::string imagePath = view.getImagePath(); ALICEVISION_LOG_INFO("Load image with path " << imagePath); image::Image source; - image::readImage(imagePath, source, image::EImageColorSpace::LINEAR); + image::readImage(imagePath, source, image::EImageColorSpace::NO_CONVERSION); // Load metadata and update for output oiio::ParamValueList metadata = image::readImageMetadata(imagePath); From 77d8435399f17c47a0fa1c16c8da5644acb26a6a Mon Sep 17 00:00:00 2001 From: demoulinv Date: Wed, 5 Oct 2022 21:45:19 +0200 Subject: [PATCH 03/15] Update ocio config file. --- .../image/share/aliceVision/config.ocio | 466 ++---------------- 1 file changed, 38 insertions(+), 428 deletions(-) diff --git a/src/aliceVision/image/share/aliceVision/config.ocio b/src/aliceVision/image/share/aliceVision/config.ocio index a6969d5b04..01356a2d6a 100644 --- a/src/aliceVision/image/share/aliceVision/config.ocio +++ b/src/aliceVision/image/share/aliceVision/config.ocio @@ -11,7 +11,7 @@ name: OCIOv2-AliceVision # # This config does not require any external files. # -search_path: +search_path: "" # # Defining the environment (even if empty) in the config can be a performance boost. @@ -34,14 +34,14 @@ roles: # this config. # aces_interchange: ACES2065-1 - cie_xyz_d65_interchange: CIE-XYZ D65 + #cie_xyz_d65_interchange: CIE-XYZ D65 # # (As this is just a demo, not all the usual roles have been defined.) # - color_timing: ACEScct - compositing_log: ACEScct - data: Raw - default: sRGB + #color_timing: ACEScct + #compositing_log: ACEScct + #data: Raw + default: scene-linear Rec.709-sRGB scene_linear: scene-linear Rec.709-sRGB # @@ -49,22 +49,13 @@ roles: # file_rules: # - # The first rule says to assign the colorspace Raw to files with a .tx extension. - # The colorspace Raw, defined below, essentially means no color processing is applied. + # The next rule assigns the colorspace "ACEScg" to any files that contain "acescg" or "ACEScg" in the path. # - - ! {name: tx, colorspace: Raw, pattern: "*", extension: tx} + - ! {name: ACEScg, colorspace: ACEScg, regex: "acescg|ACEScg"} # - # The next rule assigns the colorspace "ARRI LogC" to any files that contain "LogC" in the path. + # The next rule assigns the colorspace "ACES" to any file that contain "aces or "ACES" in the path. # - - ! {name: LogC, colorspace: ARRI LogC, pattern: "*LogC*", extension: "*"} - # - # The next rule assigns the colorspace "sRGB" to any file that ends with .TIF or .TIFF. - # - - ! {name: TIFF, colorspace: sRGB, regex: ".*\\.TIF?F$"} - # - # The next rule uses the OCIO v1 method of searching the path for all colorspaces in the config. - # -# - ! {name: ColorSpaceNamePathSearch} + - ! {name: ACES, colorspace: ACES, regex: "aces|ACES"} # # The rules are ordered, highest priority first. OCIO takes the path to a file and applies # the rules one-by-one until there is a match. The last rule, "Default", always matches. @@ -72,287 +63,11 @@ file_rules: # - ! {name: Default, colorspace: default} -# -# The Viewing Rules allow applications to determine an appropriate default view for a given color -# space. This becomes important for applications that need to display images in a variety of color -# spaces. For example, an ACES Output Transform might be the ideal view for scene-linear or log -# encoded color spaces but not be appropriate for video color spaces. In OCIO v2, there is a new -# getView function that takes a display and a color space as arguments. OCIO uses the viewing rules -# (if present) to filter the list of views to those that are appropriate for the given color space. -# The rules shown here mostly use the new "encoding" property of color spaces but it is also possible -# for a rule to list color spaces directly. Any views that do not use a rule are always returned. -# The active_views list may be used to also sort the filtered views (or do further filtering). -# -viewing_rules: - # - # The first rule means the view will only be used with colorspaces that have an encoding set - # to "scene-linear". - # - - ! {name: scene-linear, encodings: scene-linear} - # - # The next rule is similar but is targeted at colorspaces that have an encoding of "data". - # - - ! {name: data, encodings: data} - # - # The next rule targets colorspaces that have an encoding of either "log" or "scene-linear". - # - - ! {name: log-or-linear, encodings: [ log, scene-linear ]} - # - # The next rule targets colorspaces that have an encoding of either "sdr-video" or "hdr-video". - # - - ! {name: video, encodings: [ sdr-video, hdr-video ]} - # - # The next rule is not used below but is an example of how a rule could target specific colorspaces. - # - - ! {name: film-log, colorspaces: Log film scan (ADX10)} - - -# -# The Shared Views allow you to define a view that will be reused for multiple displays. -# This can make the config easier to read and maintain. -# -shared_views: - # - # The first two shared views, "Log" and "Raw" have no actual dependence on the display, so they - # simply specify the colorspace that will be used to apply the view. - # - # Note that if the application implements support for viewing rules, the Log view will only be - # used with scene-linear colorspaces (it is typically of no value for colorspaces that are already - # logarithmic or that are video or data), and the Raw view will only be used with data colorspaces. - # (Simply removing the rule from the Raw view would make it be offered with all colorspaces, which - # might be preferred in some scenarios.) - # - - ! {name: Log, colorspace: ACEScct, rule: scene-linear} - - ! {name: Raw, colorspace: Raw, rule: data} - # - # The next shared views use a view_transform and display_colorspace rather than a simple colorspace - # because the view does depend on the display. By setting display_colorspace to "", - # the display_colorspace will be replaced by the display colorspace below that has the same name as - # the display. For example, when used with display "sRGB", the display_colorspace is set to "sRGB". - # - - ! - name: ACES 1.0 SDR-video - view_transform: ACES 1.0 SDR-video - display_colorspace: - rule: log-or-linear - # - # Note that YAML syntax allows views to be split onto multiple lines to make them easier to read. - # - # The ordering within the shared_views section is not significant. It is the order they appear - # below that determines the menu order (although active_views may be used to re-order them). - # - - ! - name: Un-tone-mapped - view_transform: Un-tone-mapped - display_colorspace: - rule: log-or-linear - # - # The "Un-tone-mapped" and "Video" views are functionally equivalent but the viewing rules allow - # different names to be used based on the colorspace being viewed. For example, when viewing - # video images, it's nicer to have a view called "Video" rather than "Un-tone-mapped" (the latter - # really only makes sense in the context of scene-referred images). - # - - ! - name: Video - view_transform: Un-tone-mapped - display_colorspace: - rule: video - - -# -# Displays -# displays: - # - # The first displays simply reference the shared views defined above. The ordering of the views - # determines the menu order (unless active_views is used to re-order them). - # - sRGB: - - ! [ ACES 1.0 SDR-video, Un-tone-mapped, Log, Video, Raw ] - Rec.1886 / Rec.709 video: - - ! [ ACES 1.0 SDR-video, Un-tone-mapped, Log, Video, Raw ] - # - # The next display uses a (non-shared) view as well as shared views. - # - Rec.2100-PQ: - - ! - name: ACES 1.1 HDR-video (1000 nits) - view_transform: ACES 1.1 HDR-video (1000 nits & Rec.2020 lim) - display_colorspace: Rec.2100-PQ - rule: log-or-linear - - ! [ Un-tone-mapped, Log, Video, Raw ] - - -# -# A Virtual Display allows an application to ask OCIO to instantiate a new display from an ICC -# monitor profile. The ICC monitor profile essentially becomes a new display colorspace and a -# new display is added for users, named after the ICC profile. The new display will inherit the -# views from the virtual display. -# -virtual_display: - - ! [ ACES 1.0 SDR-video, Un-tone-mapped, Log, Raw ] - - -# -# The default view transform is the one that will be used if ColorSpaceTransform needs to convert -# between a colorspace and a display colorspace. (In other words, one that uses the scene-referred -# reference space and one that uses the display-referred reference space.) -# -default_view_transform: Un-tone-mapped - -# -# This section of the config defines the View Transforms. A View Transform is a transform that -# converts between the scene-referred reference space and the display-referred reference space -# (which is new in OCIO v2). The View Transform is sometimes referred to by other names in -# various color science documents. For example, in ACES it is called a "rendering" and in the -# ITU standards for HDR television it is called an Opto-Optical Transfer Function (OOTF). It -# is also commonly referred to as a "tone-map". This is typically where the S-shape curve that -# avoids clipped highlights is applied, along with other adjustments necessary to adopt the -# latest color science best-practices. -# -view_transforms: - # - # This first view transform is simply a matrix to convert from the scene-referred reference space, - # which is ACES2065-1 in this config, to the display-referred reference space, which is CIE XYZ - # with a D65 adaptive whitepoint in this config. Rather than put the matrix coefficients in the - # config, it is easier to reference one of the existing BuiltinTransforms. A BuiltinTransform is - # another new OCIO v2 feature, it is essentially a well-known transform that OCIO knows how to - # construct at runtime. - # - - ! - name: Un-tone-mapped - description: | - Convert the scene colorimetry directly to display-referred with no tone-mapping. - This is often described as a "linear workflow." It is intended only for diagnostic purposes. - from_scene_reference: ! {style: "UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD"} - # - # The next view transform implements the bulk of the ACES Output Transform for SDR video. In ACES, - # the transform from scene-referred colorimetry to display-referred colorimetry is identical for - # a set of Output Transforms (e.g., sRGB and Rec.709). Only the final conversion from display - # colorimetry to display code values differs. That last part is implemented in OCIO as a display - # colorspace. The BuiltinTransform here applies the RRT and first half of the ODT. There are - # Builtins available in OCIO for all of the ACES Output Transforms (though for brevity only two - # of them are included in this demo config). - # - - ! - name: ACES 1.0 SDR-video - description: | - ACES Output Transform for SDR displays in a video viewing environment. ACES neutrals are at D65. - from_scene_reference: ! {style: "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-VIDEO_1.0"} - # - # The next view transform is very similar, implementing the bulk of the ACES Output Transform for - # 1000 nit HDR video. The output transform is completed via the addition of an HDR display colorspace - # defined below. - # - - ! - name: ACES 1.1 HDR-video (1000 nits & Rec.2020 lim) - description: | - ACES Output Transform for 1000 nit HDR displays. ACES neutrals are at D65. Gamut limit uses Rec.2020 primaries. - from_scene_reference: ! {style: "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-VIDEO-1000nit-15nit-REC2020lim_1.1"} - -# -# Looks -# -looks: - - - ! - name: ACES-LMT - Blue light artifact fix - description: | - LMT for desaturating blue hues to reduce clipping artifacts - process_space: ACES2065-1 - transform: ! {style: "ACES-LMT - BLUE_LIGHT_ARTIFACT_FIX"} - - -# -# The inactive colorspace list is another new OCIO v2 feature. It allows you to include colorspaces -# in the config but hide them from user menus. In this case, we want this colorspace in the config -# for use in the cie_xyz_d65_interchange role above, but we don't want users to be able to select it. -# Note that you may override the inactive list via an environment variable. -# -inactive_colorspaces: [ CIE-XYZ D65 ] - -# -# The Display Colorspaces are another new OCIO v2 feature. These are like traditional colorspaces -# but are defined in relation to a display-referred reference space rather than a scene-referred space. -# One of the benefits of this is that a ColorSpaceTransform may now convert between a pair of display -# colorspaces (e.g., from Rec.709 to sRGB) without needing to invert a tone-map all the way back to -# the scene-referred reference space. -# -display_colorspaces: - # - # The display-referred reference space for this config is CIE XYZ tristimulus values (colorimetry) - # with an adaptive white point of D65. As with the scene-referred reference space, no transforms - # are defined for it. - # - # This colorspace does not need to be exposed to users so it is in the inactive_colorspaces list - # above. Also, it does not have any categories, which also means it would not be exposed to users - # in applications that support categories. - # - - ! - name: CIE-XYZ D65 - family: - description: | - Display connection space, CIE XYZ with D65 adaptive white point - encoding: display-linear - isdata: false - categories: - # - # The next display colorspace is for sRGB. It simply applies a matrix and a gamma to convert from - # the desired display colorimetry (in CIE XYZ space) to display code values that may be sent to a - # monitor. Note that display colorspaces use the YAML keys "from_display_reference" and - # "to_display_reference" to specify their transforms. - # - - ! - name: sRGB - family: Displays/SDR - description: | - sRGB monitor (piecewise EOTF) - isdata: false - categories: [ file-io, basic-3d, advanced-3d, basic-2d, advanced-2d ] - encoding: sdr-video - from_display_reference: ! - children: - - ! {matrix: [ 3.240969941905, -1.537383177570, -0.498610760293, 0, -0.969243636281, 1.875967501508, 0.041555057407, 0, 0.055630079697, -0.203976958889, 1.056971514243, 0, 0, 0, 0, 1 ]} - - ! {gamma: 2.4, offset: 0.055, direction: inverse} - - ! {min_in_value: 0., min_out_value: 0., max_in_value: 1., max_out_value: 1.} - # - # For the purposes of the demo, the preceding and following colorspaces are implemented - # explicitly, but they could also have been implemented using BuiltinTransforms as: - # - ! {style: "DISPLAY - CIE-XYZ-D65_to_sRGB"} - # - ! {style: "DISPLAY - CIE-XYZ-D65_to_REC.1886-REC.709"} - # - - ! - name: Rec.1886 / Rec.709 video - aliases: [ rec709 ] - family: Displays/SDR - description: | - Rec.709 HD broadcast monitor with Rec.1886 EOTF (gamma 2.4) - isdata: false - categories: [ file-io, basic-3d, advanced-3d, basic-2d, advanced-2d ] - encoding: sdr-video - from_display_reference: ! - children: - - ! {matrix: [ 3.240969941905, -1.537383177570, -0.498610760293, 0, -0.969243636281, 1.875967501508, 0.041555057407, 0, 0.055630079697, -0.203976958889, 1.056971514243, 0, 0, 0, 0, 1 ]} - - ! {value: 2.4, direction: inverse} - - ! {min_in_value: 0., min_out_value: 0., max_in_value: 1., max_out_value: 1.} - # - # This next colorspace requires the PQ curve, which would require an external LUT file so the - # BuiltinTransform is used in this case. Note that the Builtin display transforms do not clamp, - # so it is followed by a RangeTransform which clamps to [0,1]. - # - - ! - name: Rec.2100-PQ - family: Displays/HDR - description: | - Rec.2100-PQ monitor with Rec.2020 primaries and ST-2084 EOTF - isdata: false - categories: [ file-io, advanced-3d, basic-2d, advanced-2d ] - encoding: hdr-video - from_display_reference: ! - children: - - ! {style: "DISPLAY - CIE-XYZ-D65_to_REC.2100-PQ"} - - ! {min_in_value: 0., min_out_value: 0., max_in_value: 1., max_out_value: 1.} - + linear: + - ! {name: Lin, colorspace: ACEScg} + log: + - ! {name: Log, colorspace: sRGB} # # The next config section is the traditional section for colorspaces that are defined relative to a @@ -376,15 +91,6 @@ colorspaces: # list of categories, so it will be up to application developers and config authors to determine # what strings to use. OCIO does however provide a specific list of allowed encoding strings. # - - ! - name: ACEScg - family: ACES - description: | - ACEScg working space - isdata: false - categories: [ file-io, working-space, basic-3d, advanced-3d, basic-2d, advanced-2d ] - encoding: scene-linear - to_scene_reference: ! {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]} # # OCIO v2 introduces an "aliases" property that may be used to define synonyms for the canonical # colorspace name. This may be used to define short names that are easier to embed in file paths @@ -399,11 +105,17 @@ colorspaces: isdata: false categories: [ file-io, basic-3d, advanced-3d, basic-2d, advanced-2d ] encoding: scene-linear - # - # Note that this section of the config uses "to_scene_reference" and "from_scene_reference" to - # specify the transforms, but "to_reference" and "from_reference" are also allowed for backwards - # compatibility with OCIO v1. - # + + - ! + name: ACEScg + family: ACES + description: | + ACEScg working space + isdata: false + categories: [ file-io, working-space, basic-3d, advanced-3d, basic-2d, advanced-2d ] + encoding: scene-linear + to_scene_reference: ! {style: ACEScg_to_ACES2065-1} + - ! name: scene-linear Rec.709-sRGB family: Linear @@ -413,122 +125,20 @@ colorspaces: categories: [ file-io, basic-3d, advanced-3d, advanced-2d ] encoding: scene-linear to_scene_reference: ! {matrix: [ 0.439632981919, 0.382988698152, 0.177378319929, 0, 0.089776442959, 0.813439428749, 0.096784128292, 0, 0.017541170383, 0.111546553302, 0.870912276314, 0, 0, 0, 0, 1 ]} - # - # Note that in OCIO v2 it is not necessary to include most keys if they have their default values. - # This also applies to properties such as the interpolation method for FileTransforms. - # - - ! - name: Raw - family: Data - description: | - Raw (no color processing) - isdata: true - categories: [ file-io, basic-3d, advanced-3d, basic-2d, advanced-2d ] - encoding: data - # - # The ACEScct transform could be implemented as a Builtin using style: "ACEScct_to_ACES2065-1", - # but the implementation here is an opportunity to demo the new LogCameraTransform, which may - # be used to implement most of the camera-log type transforms (and is used internally by the - # ACEScct BuiltinTransform implementation). - # - - ! - name: ACEScct - family: ACES - description: | - ACES camera log working space - isdata: false - categories: [ file-io, working-space, advanced-3d, basic-2d, advanced-2d ] - encoding: log - to_scene_reference: ! - children: - - ! - log_side_slope: 0.05707762557077626 - log_side_offset: 0.55479452054794520 - lin_side_slope: 1. - lin_side_offset: 0. - lin_side_break: 0.0078125 - base: 2 - direction: inverse - - ! {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]} - # - # The remaining colorspaces use the BuiltinTransforms for simplicity and readability. - # - - ! - name: ACEScc - family: ACES - description: | - ACES log working space - isdata: false - categories: [ file-io, advanced-2d ] - encoding: log - to_scene_reference: ! {style: "ACEScc_to_ACES2065-1"} - - - ! - name: ARRI LogC - family: Cameras/ARRI - description: | - Alexa-v3-LogC-EI800 (SUP v3 color science) - isdata: false - categories: [ file-io, advanced-3d, basic-2d, advanced-2d ] - encoding: log - to_scene_reference: ! {style: "ARRI_ALEXA-LOGC-EI800-AWG_to_ACES2065-1"} - ! - name: RED Log3G10 / REDWideGamutRGB - family: Cameras/RED - description: | - RED Log3G10 / REDWideGamutRGB - isdata: false - categories: [ file-io, basic-2d, advanced-2d ] - encoding: log - to_scene_reference: ! {style: "RED_LOG3G10-RWG_to_ACES2065-1"} - - - ! - name: Sony SLog3 / SGamut3 - family: Cameras/Sony - description: | - Sony SLog3 / SGamut3 - isdata: false - categories: [ file-io, basic-2d, advanced-2d ] - encoding: log - to_scene_reference: ! {style: "SONY_SLOG3-SGAMUT3_to_ACES2065-1"} - - - ! - name: Log film scan (ADX10) - aliases: [ ADX10 ] - family: ACES + name: sRGB + family: "" + bitdepth: 32f description: | - ADX10 Academy Density Exchange (10-bit printing density) + Convert ACES2065-1 to sRGB + CLFtransformID: urn:aswf:ocio:transformId:1.0:OCIO:Utility:AP0_to_Rec709-sRGB:1.0 isdata: false - categories: [ file-io, advanced-2d ] - encoding: log - to_scene_reference: ! {style: "ADX10_to_ACES2065-1"} - - -# -# Sometimes it is helpful to include one or more transforms in a config that are essentially -# stand-alone transforms that do not have a fixed relationship to a reference space or a -# process space. An example would be a "utility curve" transform where the intent is to -# simply apply a LUT1D without any conversion to a reference space. In these cases, a -# named_transforms section may be added to the config with one or more named transforms. -# -# Note that named transforms do not show up in color space menus by default, so the -# application developer must implement support to make them available to users. -# -# This feature may be used to emulate older methods of color management that ignored the -# RGB primaries and simply applied one-dimensional transformations. However, config authors -# are encouraged to implement transforms as normal OCIO color spaces wherever possible. -# -named_transforms: - - - ! - name: Utility Curve -- Cineon Log to Lin - description: | - Traditional Cineon-style log-to-lin with RefWhite=695, RefBlack=95, Gamma=0.6 - transform: ! - log_side_slope: 0.293255131965 - log_side_offset: 0.669599217986 - lin_side_slope: 0.989202248377 - lin_side_offset: 0.010797751623 - base: 10 - direction: inverse \ No newline at end of file + categories: [file-io] + encoding: sdr-video + allocation: uniform + from_scene_reference: ! + name: AP0 to Rec.709 - sRGB + children: + - ! {matrix: [2.52140088857822, -1.13399574938275, -0.387561856768867, 0, -0.276214061561748, 1.37259556630409, -0.0962823557364663, 0, -0.0153202000774786, -0.152992561800699, 1.16838719961932, 0, 0, 0, 0, 1]} + - ! {gamma: 2.4, offset: 0.055, direction: inverse} From 6ebaeebb15be4d0c24454322fdcc309481d1fab3 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 17 Oct 2022 16:37:14 +0200 Subject: [PATCH 04/15] [software] ImageProcessing: add option to keep image filename --- src/software/utils/main_imageProcessing.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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(); From c34872808d44d60714b75071d0f859a5faec2ecd Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 17 Oct 2022 16:38:10 +0200 Subject: [PATCH 05/15] [image] io: 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. --- src/aliceVision/image/io.cpp | 71 +++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 53a3c91dd9..5d27bba596 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -32,45 +32,59 @@ namespace { std::string configOCIOFilePath = ""; - char const* ALICEVISION_OCIO = getenv("ALICEVISION_OCIO"); + char const* ALICEVISION_OCIO = std::getenv("ALICEVISION_OCIO"); if (ALICEVISION_OCIO != NULL) { configOCIOFilePath = std::string(ALICEVISION_OCIO); 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") + { + ALICEVISION_LOG_TRACE("ALICEVISION_OCIO configuration file: '" << configOCIOFilePath << "' found."); + return configOCIOFilePath; + } + else + { + ALICEVISION_LOG_WARNING("ALICEVISION_OCIO configuration file is not valid: '" << configOCIOFilePath << "'.\n" + "The scene_linear role named \"scene-linear Rec.709-sRGB\" is required.\n" + "Skip this OCIO configuration file and use the embedded one."); + } } - else if (configOCIOFilePath == "") + else if (configOCIOFilePath.empty()) { - ALICEVISION_LOG_TRACE("ALICEVISION_OCIO is empty. Try OCIO..."); + ALICEVISION_LOG_TRACE("ALICEVISION_OCIO is empty."); } else { - ALICEVISION_LOG_TRACE("ALICEVISION_OCIO does not point to an existing file. Try OCIO..."); + ALICEVISION_LOG_WARNING("ALICEVISION_OCIO is defined but does not point to an existing file: '" << configOCIOFilePath << "'"); } } - 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"); + // 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 = std::getenv("ALICEVISION_ROOT"); if (ALICEVISION_ROOT == NULL) { ALICEVISION_THROW_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); @@ -81,7 +95,6 @@ namespace if (!fs::exists(configOCIOFilePath)) { ALICEVISION_THROW_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); - configOCIOFilePath = ""; } else { @@ -137,7 +150,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; @@ -162,7 +175,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::LAB: From 81dba0453f50ada4f892627c3a80424b1771b661 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Tue, 11 Oct 2022 20:05:36 +0200 Subject: [PATCH 06/15] [cmake] Update test environment: add env var ALICEVISION_ROOT definition for Windows in the alicevision_add_test cmake function. --- src/aliceVision/image/io_test.cpp | 15 --------------- .../compatibilityData/scene_v1.2.3.abc | Bin 412693 -> 412693 bytes src/cmake/Helpers.cmake | 4 ++++ 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/aliceVision/image/io_test.cpp b/src/aliceVision/image/io_test.cpp index e4c848e243..9bcb95ee3d 100644 --- a/src/aliceVision/image/io_test.cpp +++ b/src/aliceVision/image/io_test.cpp @@ -22,21 +22,6 @@ using namespace aliceVision; using namespace aliceVision::image; using std::string; -#ifdef WIN32 -int setenv(const char* name, const char* value, int overwrite) -{ - int errcode = 0; - if (!overwrite) { - size_t envsize = 0; - errcode = getenv_s(&envsize, NULL, 0, name); - if (errcode || envsize) return errcode; - } - return _putenv_s(name, value); -} -#endif - -int err = setenv("ALICEVISION_ROOT", std::string(THIS_SOURCE_DIR).c_str(), 1); - // tested extensions static std::vector extensions = { "jpg", "png", "pgm", "ppm", "tiff", "exr" }; diff --git a/src/aliceVision/sfmDataIO/compatibilityData/scene_v1.2.3.abc b/src/aliceVision/sfmDataIO/compatibilityData/scene_v1.2.3.abc index 068d2a25e1e0e6c8a3d1ae84791e33c08c7a9051..e31654fa6c583bb96a5cb11bbf67a09a88041e6e 100644 GIT binary patch delta 48 zcmbO_Lvrd2$%Yoj7N!>F7M2#)Eo_@SMS@cc6pYLjj0}v76bvk^42`TzjJF^2WbF7M2#)Eo_@SMSK%06^zUkj0}v76bucmj0~)dEVdu>Wb Date: Fri, 7 Oct 2022 12:13:21 +0200 Subject: [PATCH 07/15] [ci] Windows fix: add CMAKE_INSTALL_PREFIX --- .github/workflows/continuous-integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 4d01a57c70..174b1929ff 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -201,6 +201,7 @@ jobs: cmakeAppendedArgs: -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DBUILD_SHARED_LIBS:BOOL=ON -DTARGET_ARCHITECTURE=core + -DCMAKE_INSTALL_PREFIX:PATH=${{ env.ALICEVISION_ROOT }} -DALICEVISION_BUILD_TESTS:BOOL=ON -DALICEVISION_BUILD_EXAMPLES:BOOL=ON -DALICEVISION_USE_OPENCV:BOOL=ON From 1ffd64af815608645326cc5050b46cf55ee8efc4 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Thu, 13 Oct 2022 15:05:38 +0200 Subject: [PATCH 08/15] [ci] Add ALICEVISION_ROOT definition in ci/env.sh --- ci/env.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/env.sh b/ci/env.sh index 2353f31f64..ecca1add63 100755 --- a/ci/env.sh +++ b/ci/env.sh @@ -59,6 +59,7 @@ export ALICEVISION_BUILD="${TRAVIS_BUILD_DIR}/build" export ALICEVISION_INSTALL="${TRAVIS_BUILD_DIR}/install" export ALICEVISION_BUILD_AS3RDPARTY="${TRAVIS_BUILD_DIR}/buildAs3rdparty" export ALICEVISION_SAMPLE_AS3RDPARTY="${ALICEVISION_SOURCE}/src/samples/aliceVisionAs3rdParty/" +export ALICEVISION_ROOT="${ALICEVISION_INSTALL}" # GT datasets for tests export GT_TEST_ROOT="${TRAVIS_BUILD_DIR}/gt_test" export GT_TEST_SOURCE="${GT_TEST_ROOT}/gt_source" From 247c1f9afd535784781d4432240e43930e8104e6 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Mon, 17 Oct 2022 09:07:41 +0200 Subject: [PATCH 09/15] [ci] Add Argument CMAKE_INSTALL_PREFIX in the UnitTests step of the continuous integration github yml file. CMAKE_INSTALL_PREFIX definition is used by the Cmake function "alicevision_add_test" defined in Helpers.cmake to set the env var ALICEVISION_ROOT for the unitary target target RUN_TESTS. --- .github/workflows/continuous-integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 174b1929ff..74e6a30c14 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -222,6 +222,7 @@ jobs: cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' buildDirectory: ${{ env.buildDir }} buildWithCMakeArgs: '--config Release --target RUN_TESTS' + cmakeAppendedArgs: -DCMAKE_INSTALL_PREFIX:PATH=${{ env.ALICEVISION_ROOT }} # This input tells run-cmake to consume the vcpkg.cmake toolchain file set by run-vcpkg. cmakeBuildType: Release useVcpkgToolchainFile: true From b62aee30039478027631926c6082ffab4fa392ea Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 17 Oct 2022 19:36:33 +0200 Subject: [PATCH 10/15] [image] use disabled code instead of commented code --- src/aliceVision/image/io.cpp | 42 +++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 5d27bba596..5d042c3d7c 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -63,26 +63,28 @@ namespace } } - // 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..."); - // } - //} + // To be enabled if we decide to take OCIO env var in consideration before using the enbedded config file + if(false) + { + char const* OCIO = std::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 = std::getenv("ALICEVISION_ROOT"); if (ALICEVISION_ROOT == NULL) From c5aadf3b84ee8ac9115e4748a953d4b8526b3861 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 17 Oct 2022 19:37:30 +0200 Subject: [PATCH 11/15] [image] add log for errors --- src/aliceVision/image/io.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 5d042c3d7c..ef729dedfe 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -89,6 +89,8 @@ namespace char const* ALICEVISION_ROOT = std::getenv("ALICEVISION_ROOT"); if (ALICEVISION_ROOT == NULL) { + // Output message with logging before throw as this function could be called before main. + ALICEVISION_LOG_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); ALICEVISION_THROW_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); } configOCIOFilePath = std::string(ALICEVISION_ROOT); @@ -96,6 +98,7 @@ namespace if (!fs::exists(configOCIOFilePath)) { + ALICEVISION_LOG_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); ALICEVISION_THROW_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); } else From 57c557824f6692aa2ff80d9aa0f5f1b95287244e Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 17 Oct 2022 21:46:11 +0200 Subject: [PATCH 12/15] [ci] windows: add install target --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 74e6a30c14..6a38ba674c 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -197,7 +197,7 @@ jobs: cmakeListsOrSettingsJson: CMakeListsTxtAdvanced cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' buildDirectory: ${{ env.buildDir }} - buildWithCMakeArgs: '--config Release' + buildWithCMakeArgs: '--config Release --target install' cmakeAppendedArgs: -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DBUILD_SHARED_LIBS:BOOL=ON -DTARGET_ARCHITECTURE=core From 84e98523625e765ef9993034a624d1de4029c585 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 18 Oct 2022 07:45:00 +0200 Subject: [PATCH 13/15] [cmake] only deploy doc if it has been generated --- src/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5adcf51e01..716a9564a3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -878,7 +878,9 @@ else() PROPERTY FOLDER AliceVision ) - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc DESTINATION ${CMAKE_INSTALL_DOCDIR}) + if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/doc) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc DESTINATION ${CMAKE_INSTALL_DOCDIR}) + endif() endif() endif() From bbb3f33f735a21b774f0b144b60a8276dcb63d46 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 18 Oct 2022 12:45:25 +0200 Subject: [PATCH 14/15] [image] move colorspace code into dedicated file --- src/aliceVision/image/CMakeLists.txt | 2 + src/aliceVision/image/colorspace.cpp | 248 +++++++++++++++++++++++++++ src/aliceVision/image/colorspace.hpp | 50 ++++++ src/aliceVision/image/io.cpp | 235 +------------------------ src/aliceVision/image/io.hpp | 32 +--- 5 files changed, 311 insertions(+), 256 deletions(-) create mode 100644 src/aliceVision/image/colorspace.cpp create mode 100644 src/aliceVision/image/colorspace.hpp diff --git a/src/aliceVision/image/CMakeLists.txt b/src/aliceVision/image/CMakeLists.txt index e5b21403ed..60712926c6 100644 --- a/src/aliceVision/image/CMakeLists.txt +++ b/src/aliceVision/image/CMakeLists.txt @@ -5,6 +5,7 @@ set(image_files_headers all.hpp Image.hpp imageAlgo.hpp + colorspace.hpp concat.hpp convertion.hpp convolutionBase.hpp @@ -23,6 +24,7 @@ set(image_files_headers # Sources set(image_files_sources + colorspace.cpp convolution.cpp filtering.cpp io.cpp diff --git a/src/aliceVision/image/colorspace.cpp b/src/aliceVision/image/colorspace.cpp new file mode 100644 index 0000000000..0626e3b680 --- /dev/null +++ b/src/aliceVision/image/colorspace.cpp @@ -0,0 +1,248 @@ +// This file is part of the AliceVision project. +// Copyright (c) 2022 AliceVision contributors. +// This Source Code Form is subject to the terms of the Mozilla Public License, +// v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "colorspace.hpp" + +#include + +#include + +#include +#include + + +namespace fs = boost::filesystem; + +namespace aliceVision { +namespace image { + +namespace +{ + oiio::ColorConfig colorConfigOCIO(getDefaultColorConfigFilePath()); +} + +oiio::ColorConfig& getGlobalColorConfigOCIO() +{ + return colorConfigOCIO; +} + +std::string getDefaultColorConfigFilePath() +{ + std::string configOCIOFilePath = ""; + + char const* ALICEVISION_OCIO = std::getenv("ALICEVISION_OCIO"); + if (ALICEVISION_OCIO != NULL) + { + configOCIOFilePath = std::string(ALICEVISION_OCIO); + if (fs::exists(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") + { + ALICEVISION_LOG_TRACE("ALICEVISION_OCIO configuration file: '" << configOCIOFilePath << "' found."); + return configOCIOFilePath; + } + else + { + ALICEVISION_LOG_WARNING("ALICEVISION_OCIO configuration file is not valid: '" << configOCIOFilePath << "'.\n" + "The scene_linear role named \"scene-linear Rec.709-sRGB\" is required.\n" + "Skip this OCIO configuration file and use the embedded one."); + } + } + else if (configOCIOFilePath.empty()) + { + ALICEVISION_LOG_TRACE("ALICEVISION_OCIO is empty."); + } + else + { + ALICEVISION_LOG_WARNING("ALICEVISION_OCIO is defined but does not point to an existing file: '" << configOCIOFilePath << "'"); + } + } + + // To be enabled if we decide to take OCIO env var in consideration before using the enbedded config file + if(false) + { + char const* OCIO = std::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 = std::getenv("ALICEVISION_ROOT"); + if (ALICEVISION_ROOT == NULL) + { + // Output message with logging before throw as this function could be called before main. + ALICEVISION_LOG_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); + ALICEVISION_THROW_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); + } + configOCIOFilePath = std::string(ALICEVISION_ROOT); + configOCIOFilePath.append("/share/aliceVision/config.ocio"); + + if (!fs::exists(configOCIOFilePath)) + { + ALICEVISION_LOG_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); + ALICEVISION_THROW_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); + } + ALICEVISION_LOG_TRACE("Embedded OCIO configuration file: '" << configOCIOFilePath << "' found."); + + return configOCIOFilePath; +} + +void initColorConfigOCIO(const std::string& colorConfigFilePath) +{ + colorConfigOCIO.reset(colorConfigFilePath); + if (!colorConfigOCIO.supportsOpenColorIO()) + { + ALICEVISION_THROW_ERROR("OpenImageIO has not been compiled with OCIO."); + } + const std::string error = colorConfigOCIO.geterror(); + if (!error.empty()) + { + ALICEVISION_THROW_ERROR("Erroneous OCIO config file " << colorConfigFilePath << ":" << std::endl << error); + } + int ocioVersion = colorConfigOCIO.OpenColorIO_version_hex(); + int ocioMajor = (ocioVersion & 0xFF000000) >> 24; + int ocioMinor = (ocioVersion & 0x00FF0000) >> 16; + int ocioPatch = (ocioVersion & 0x0000FF00) >> 8; + ALICEVISION_LOG_INFO("OCIO color config initialized with OCIO version: " << ocioMajor << "." << ocioMinor << "." << ocioPatch); +} + +std::string EImageColorSpace_informations() +{ + return EImageColorSpace_enumToString(EImageColorSpace::AUTO) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::LINEAR) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::SRGB) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::ACES2065_1) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::ACEScg) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::LAB) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::XYZ) + ", " + + EImageColorSpace_enumToString(EImageColorSpace::NO_CONVERSION); +} + +EImageColorSpace EImageColorSpace_stringToEnum(const std::string& dataType) +{ + const std::string type = boost::to_lower_copy(dataType); + + if(type == "auto") + return EImageColorSpace::AUTO; + if(type == "linear") + return EImageColorSpace::LINEAR; + if(type == "srgb") + return EImageColorSpace::SRGB; + if(type == "aces2065-1") + return EImageColorSpace::ACES2065_1; + if(type == "acescg") + return EImageColorSpace::ACEScg; + if(type == "lab") + return EImageColorSpace::LAB; + if(type == "xyz") + return EImageColorSpace::XYZ; + if(type == "no_conversion") + return EImageColorSpace::NO_CONVERSION; + + throw std::out_of_range("Invalid EImageColorSpace: " + dataType); +} + +std::string EImageColorSpace_enumToString(const EImageColorSpace dataType) +{ + switch(dataType) + { + case EImageColorSpace::AUTO: + return "auto"; + case EImageColorSpace::LINEAR: + return "linear"; + case EImageColorSpace::SRGB: + return "srgb"; + case EImageColorSpace::ACES2065_1: + return "aces2065-1"; + case EImageColorSpace::ACEScg: + return "acescg"; + case EImageColorSpace::LAB: + return "lab"; + case EImageColorSpace::XYZ: + return "xyz"; + case EImageColorSpace::NO_CONVERSION: + return "no_conversion"; + } + throw std::out_of_range("Invalid EImageColorSpace enum"); +} + +std::string EImageColorSpace_enumToOIIOString(const EImageColorSpace colorSpace) +{ + switch(colorSpace) + { + case EImageColorSpace::SRGB: return "sRGB"; + case EImageColorSpace::LINEAR: return "Linear"; + case EImageColorSpace::ACES2065_1: return "aces2065-1"; + case EImageColorSpace::ACEScg: return "ACEScg"; + default: ; + } + throw std::out_of_range("No string defined for EImageColorSpace to OIIO conversion: " + + std::to_string(int(colorSpace))); +} + +EImageColorSpace EImageColorSpace_OIIOstringToEnum(const std::string& colorspace) +{ + if (colorspace == "Linear") return EImageColorSpace::LINEAR; + if (colorspace == "sRGB") return EImageColorSpace::SRGB; + if (colorspace == "aces2065-1") return EImageColorSpace::ACES2065_1; + if (colorspace == "ACEScg") return EImageColorSpace::ACEScg; + + throw std::out_of_range("No EImageColorSpace defined for string: " + colorspace); +} + +bool EImageColorSpace_isSupportedOIIOEnum(const EImageColorSpace& colorspace) +{ + switch(colorspace) + { + case EImageColorSpace::SRGB: return true; + case EImageColorSpace::LINEAR: return true; + case EImageColorSpace::ACES2065_1: return true; + case EImageColorSpace::ACEScg: return true; + default: return false; + } +} + +bool EImageColorSpace_isSupportedOIIOstring(const std::string& colorspace) +{ + if (colorspace == "Linear") return true; + if (colorspace == "sRGB") return true; + if (colorspace == "aces2065-1") return true; + if (colorspace == "ACEScg") return true; + return false; +} + +std::ostream& operator<<(std::ostream& os, EImageColorSpace dataType) +{ + return os << EImageColorSpace_enumToString(dataType); +} + +std::istream& operator>>(std::istream& in, EImageColorSpace& dataType) +{ + std::string token; + in >> token; + dataType = EImageColorSpace_stringToEnum(token); + return in; +} + +} +} diff --git a/src/aliceVision/image/colorspace.hpp b/src/aliceVision/image/colorspace.hpp new file mode 100644 index 0000000000..90eab91951 --- /dev/null +++ b/src/aliceVision/image/colorspace.hpp @@ -0,0 +1,50 @@ +// This file is part of the AliceVision project. +// Copyright (c) 2022 AliceVision contributors. +// This Source Code Form is subject to the terms of the Mozilla Public License, +// v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include +#include +#include + +#include + +namespace oiio = OIIO; + +namespace aliceVision { +namespace image { + +/** + * @brief Available image color space for pipeline input + */ +enum class EImageColorSpace +{ + AUTO, + LINEAR, + SRGB, + ACES2065_1, + ACEScg, + LAB, + XYZ, + NO_CONVERSION +}; + +std::string EImageColorSpace_informations(); +EImageColorSpace EImageColorSpace_stringToEnum(const std::string& dataType); +std::string EImageColorSpace_enumToString(const EImageColorSpace dataType); +std::string EImageColorSpace_enumToOIIOString(const EImageColorSpace colorSpace); +EImageColorSpace EImageColorSpace_OIIOstringToEnum(const std::string& colorspace); +bool EImageColorSpace_isSupportedOIIOEnum(const EImageColorSpace& colorspace); +bool EImageColorSpace_isSupportedOIIOstring(const std::string& colorspace); +std::ostream& operator<<(std::ostream& os, EImageColorSpace dataType); +std::istream& operator>>(std::istream& in, EImageColorSpace& dataType); + +std::string getDefaultColorConfigFilePath(); +void initColorConfigOCIO(const std::string& colorConfigFilePath); +oiio::ColorConfig& getGlobalColorConfigOCIO(); + +} +} diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index ef729dedfe..0dae40f6f0 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -5,9 +5,9 @@ // v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -#include #include +#include #include #include @@ -16,8 +16,8 @@ #include -#include #include +#include #include #include @@ -26,232 +26,11 @@ namespace fs = boost::filesystem; -namespace -{ - std::string getDefaultColorConfigFilePath() - { - std::string configOCIOFilePath = ""; - - char const* ALICEVISION_OCIO = std::getenv("ALICEVISION_OCIO"); - if (ALICEVISION_OCIO != NULL) - { - configOCIOFilePath = std::string(ALICEVISION_OCIO); - if (fs::exists(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") - { - ALICEVISION_LOG_TRACE("ALICEVISION_OCIO configuration file: '" << configOCIOFilePath << "' found."); - return configOCIOFilePath; - } - else - { - ALICEVISION_LOG_WARNING("ALICEVISION_OCIO configuration file is not valid: '" << configOCIOFilePath << "'.\n" - "The scene_linear role named \"scene-linear Rec.709-sRGB\" is required.\n" - "Skip this OCIO configuration file and use the embedded one."); - } - } - else if (configOCIOFilePath.empty()) - { - ALICEVISION_LOG_TRACE("ALICEVISION_OCIO is empty."); - } - else - { - ALICEVISION_LOG_WARNING("ALICEVISION_OCIO is defined but does not point to an existing file: '" << configOCIOFilePath << "'"); - } - } - - // To be enabled if we decide to take OCIO env var in consideration before using the enbedded config file - if(false) - { - char const* OCIO = std::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 = std::getenv("ALICEVISION_ROOT"); - if (ALICEVISION_ROOT == NULL) - { - // Output message with logging before throw as this function could be called before main. - ALICEVISION_LOG_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); - ALICEVISION_THROW_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); - } - configOCIOFilePath = std::string(ALICEVISION_ROOT); - configOCIOFilePath.append("/share/aliceVision/config.ocio"); - - if (!fs::exists(configOCIOFilePath)) - { - ALICEVISION_LOG_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); - ALICEVISION_THROW_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); - } - else - { - ALICEVISION_LOG_TRACE("Embedded OCIO configuration file: '" << configOCIOFilePath << "' found."); - } - - return configOCIOFilePath; - } - oiio::ColorConfig colorConfigOCIO(getDefaultColorConfigFilePath()); -} - namespace aliceVision { namespace image { -void initColorConfigOCIO(const std::string& colorConfigFilePath) -{ - colorConfigOCIO.reset(colorConfigFilePath); - if (!colorConfigOCIO.supportsOpenColorIO()) - { - ALICEVISION_THROW_ERROR("OpenImageIO has not been compiled with OCIO."); - } - const std::string error = colorConfigOCIO.geterror(); - if (!error.empty()) - { - ALICEVISION_THROW_ERROR("Erroneous OCIO config file " << colorConfigFilePath << ":" << std::endl << error); - } - int ocioVersion = colorConfigOCIO.OpenColorIO_version_hex(); - int ocioMajor = (ocioVersion & 0xFF000000) >> 24; - int ocioMinor = (ocioVersion & 0x00FF0000) >> 16; - int ocioPatch = (ocioVersion & 0x0000FF00) >> 8; - ALICEVISION_LOG_INFO("OCIO color config initialized with OCIO version: " << ocioMajor << "." << ocioMinor << "." << ocioPatch); -} - -std::string EImageColorSpace_informations() -{ - return EImageColorSpace_enumToString(EImageColorSpace::AUTO) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::LINEAR) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::SRGB) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::ACES2065_1) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::ACEScg) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::LAB) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::XYZ) + ", " + - EImageColorSpace_enumToString(EImageColorSpace::NO_CONVERSION); -} - -EImageColorSpace EImageColorSpace_stringToEnum(const std::string& dataType) -{ - const std::string type = boost::to_lower_copy(dataType); - - if(type == "auto") - return EImageColorSpace::AUTO; - if(type == "linear") - return EImageColorSpace::LINEAR; - if(type == "srgb") - return EImageColorSpace::SRGB; - if(type == "aces2065-1") - return EImageColorSpace::ACES2065_1; - if(type == "acescg") - return EImageColorSpace::ACEScg; - if(type == "lab") - return EImageColorSpace::LAB; - if(type == "xyz") - return EImageColorSpace::XYZ; - if(type == "no_conversion") - return EImageColorSpace::NO_CONVERSION; - - throw std::out_of_range("Invalid EImageColorSpace: " + dataType); -} - -std::string EImageColorSpace_enumToString(const EImageColorSpace dataType) -{ - switch(dataType) - { - case EImageColorSpace::AUTO: - return "auto"; - case EImageColorSpace::LINEAR: - return "linear"; - case EImageColorSpace::SRGB: - return "srgb"; - case EImageColorSpace::ACES2065_1: - return "aces2065-1"; - case EImageColorSpace::ACEScg: - return "acescg"; - case EImageColorSpace::LAB: - return "lab"; - case EImageColorSpace::XYZ: - return "xyz"; - case EImageColorSpace::NO_CONVERSION: - return "no_conversion"; - } - throw std::out_of_range("Invalid EImageColorSpace enum"); -} - -std::string EImageColorSpace_enumToOIIOString(const EImageColorSpace colorSpace) -{ - switch(colorSpace) - { - case EImageColorSpace::SRGB: return "sRGB"; - case EImageColorSpace::LINEAR: return "Linear"; - case EImageColorSpace::ACES2065_1: return "aces2065-1"; - case EImageColorSpace::ACEScg: return "ACEScg"; - default: ; - } - throw std::out_of_range("No string defined for EImageColorSpace to OIIO conversion: " + - std::to_string(int(colorSpace))); -} - -EImageColorSpace EImageColorSpace_OIIOstringToEnum(const std::string& colorspace) -{ - if (colorspace == "Linear") return EImageColorSpace::LINEAR; - if (colorspace == "sRGB") return EImageColorSpace::SRGB; - if (colorspace == "aces2065-1") return EImageColorSpace::ACES2065_1; - if (colorspace == "ACEScg") return EImageColorSpace::ACEScg; - - throw std::out_of_range("No EImageColorSpace defined for string: " + colorspace); -} - -bool EImageColorSpace_isSupportedOIIOEnum(const EImageColorSpace& colorspace) -{ - switch(colorspace) - { - case EImageColorSpace::SRGB: return true; - case EImageColorSpace::LINEAR: return true; - case EImageColorSpace::ACES2065_1: return true; - case EImageColorSpace::ACEScg: return true; - default: return false; - } -} - -bool EImageColorSpace_isSupportedOIIOstring(const std::string& colorspace) -{ - if (colorspace == "Linear") return true; - if (colorspace == "sRGB") return true; - if (colorspace == "aces2065-1") return true; - if (colorspace == "ACEScg") return true; - return false; -} - -std::ostream& operator<<(std::ostream& os, EImageColorSpace dataType) -{ - return os << EImageColorSpace_enumToString(dataType); -} - -std::istream& operator>>(std::istream& in, EImageColorSpace& dataType) -{ - std::string token; - in >> token; - dataType = EImageColorSpace_stringToEnum(token); - return in; -} -EImageColorSpace getImageColorSpace(const std::string imagePath) +EImageColorSpace getImageColorSpace(const std::string& imagePath) { oiio::ImageSpec metadataSpec; @@ -267,7 +46,7 @@ EImageColorSpace getImageColorSpace(const std::string imagePath) colorSpace = metadataSpec.get_string_attribute("oiio:ColorSpace", ""); // Check oiio metadata if ((colorSpace == "Linear") || (colorSpace == "")) { - std::string colorSpaceFromFileName = colorConfigOCIO.getColorSpaceFromFilepath(imagePath); + const std::string colorSpaceFromFileName = getGlobalColorConfigOCIO().getColorSpaceFromFilepath(imagePath); if (!colorSpaceFromFileName.empty()) { ALICEVISION_LOG_TRACE("Read image " << imagePath << " (encoded in " << colorSpaceFromFileName << " colorspace according to file name)."); @@ -287,9 +66,9 @@ EImageColorSpace getImageColorSpace(const std::string imagePath) if (!EImageColorSpace_isSupportedOIIOstring(colorSpace)) { - size_t npos = imagePath.find_last_of("."); - std::string ext = imagePath.substr(npos + 1); - std::string forcedColorSpace = (ext == "exr" || ext == "EXR") ? "linear" : "sRGB"; + const size_t npos = imagePath.find_last_of("."); + const std::string ext = imagePath.substr(npos + 1); + const std::string forcedColorSpace = (ext == "exr" || ext == "EXR") ? "linear" : "sRGB"; ALICEVISION_LOG_WARNING("The color space " << colorSpace << " detected for " << imagePath << " is not supported. Force Color space to " << forcedColorSpace << "."); colorSpace = forcedColorSpace; diff --git a/src/aliceVision/image/io.hpp b/src/aliceVision/image/io.hpp index 678d4b8ad9..3588b0ee14 100644 --- a/src/aliceVision/image/io.hpp +++ b/src/aliceVision/image/io.hpp @@ -7,8 +7,10 @@ #pragma once -#include -#include +#include "Image.hpp" +#include "pixelTypes.hpp" +#include "colorspace.hpp" + #include #include @@ -17,7 +19,6 @@ #include -namespace oiio = OIIO; namespace aliceVision { @@ -25,31 +26,6 @@ class rgb; namespace image { -/** - * @brief Available image color space for pipeline input - */ -enum class EImageColorSpace -{ - AUTO, - LINEAR, - SRGB, - ACES2065_1, - ACEScg, - LAB, - XYZ, - NO_CONVERSION -}; - -std::string EImageColorSpace_informations(); -EImageColorSpace EImageColorSpace_stringToEnum(const std::string& dataType); -std::string EImageColorSpace_enumToString(const EImageColorSpace dataType); -std::string EImageColorSpace_enumToOIIOString(const EImageColorSpace colorSpace); -EImageColorSpace EImageColorSpace_OIIOstringToEnum(const std::string& colorspace); -bool EImageColorSpace_isSupportedOIIOEnum(const EImageColorSpace& colorspace); -bool EImageColorSpace_isSupportedOIIOstring(const std::string& colorspace); -std::ostream& operator<<(std::ostream& os, EImageColorSpace dataType); -std::istream& operator>>(std::istream& in, EImageColorSpace& dataType); - struct OutputFileColorSpace { EImageColorSpace from{EImageColorSpace::LINEAR}; From 336e0450b243b300d679318fd041318f228f9811 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Tue, 18 Oct 2022 15:47:10 +0200 Subject: [PATCH 15/15] [image] ocio config: add fallback to source code file --- src/aliceVision/image/colorspace.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/aliceVision/image/colorspace.cpp b/src/aliceVision/image/colorspace.cpp index 0626e3b680..bc678e4df3 100644 --- a/src/aliceVision/image/colorspace.cpp +++ b/src/aliceVision/image/colorspace.cpp @@ -26,7 +26,13 @@ namespace oiio::ColorConfig& getGlobalColorConfigOCIO() { - return colorConfigOCIO; + return colorConfigOCIO; +} + +std::string getColorConfigFilePathFromSourceCode() +{ + const fs::path moduleFolder = fs::path(__FILE__).parent_path(); + return (moduleFolder / "share/aliceVision/config.ocio").string(); } std::string getDefaultColorConfigFilePath() @@ -90,6 +96,12 @@ std::string getDefaultColorConfigFilePath() char const* ALICEVISION_ROOT = std::getenv("ALICEVISION_ROOT"); if (ALICEVISION_ROOT == NULL) { + const std::string configFromSource = getColorConfigFilePathFromSourceCode(); + if(fs::exists(configFromSource)) + { + ALICEVISION_LOG_DEBUG("ALICEVISION_ROOT is not defined, use embedded OCIO config file from source code: " << configFromSource); + return configFromSource; + } // Output message with logging before throw as this function could be called before main. ALICEVISION_LOG_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); ALICEVISION_THROW_ERROR("ALICEVISION_ROOT is not defined, embedded OCIO config file cannot be accessed."); @@ -99,6 +111,12 @@ std::string getDefaultColorConfigFilePath() if (!fs::exists(configOCIOFilePath)) { + const std::string configFromSource = getColorConfigFilePathFromSourceCode(); + if(fs::exists(configFromSource)) + { + ALICEVISION_LOG_DEBUG("Embedded OCIO config file in ALICEVISION_ROOT does not exist, use config from source code: " << configFromSource); + return configFromSource; + } ALICEVISION_LOG_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); ALICEVISION_THROW_ERROR("Embedded OCIO configuration file: '" << configOCIOFilePath << "' cannot be accessed."); }