Skip to content

Commit

Permalink
Update color space metadata extraction from read image.
Browse files Browse the repository at this point in the history
First, search AliceVision:ColorSpace metadata in oiio read buf.
If non-existent or invalid search oiio:ColorSpace metadata in read buf.
If still non-existent or invalid use filename to guess the color space by using the oiio::readmetadata function and then the OCIO configuration file if any.

ImageProcessing: add option to keep image filename.
  • Loading branch information
demoulinv committed Oct 10, 2022
1 parent 9ae2217 commit 3e995ff
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 30 deletions.
87 changes: 62 additions & 25 deletions src/aliceVision/image/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,18 @@ namespace
if (fs::exists(configOCIOFilePath))
{
ALICEVISION_LOG_TRACE("ALICEVISION_OCIO configuration file: '" << configOCIOFilePath << "' found.");
return configOCIOFilePath;
// Check if a sRGB linear color space named "scene-linear Rec.709-sRGB" is present and set as scene_linear role
oiio::ColorConfig colorConfig(configOCIOFilePath);
const std::string linearColorSpace = colorConfig.getColorSpaceNameByRole("scene_linear");
if (linearColorSpace == "scene-linear Rec.709-sRGB")
{
return configOCIOFilePath;
}
else
{
ALICEVISION_LOG_TRACE("But does not contain a scene_linear role named \"scene-linear Rec.709-sRGB\".");
ALICEVISION_LOG_TRACE("Use embedded config.");
}
}
else if (configOCIOFilePath == "")
{
Expand All @@ -51,24 +62,26 @@ namespace
}
}

char const* OCIO = getenv("OCIO");
if (OCIO != NULL)
{
configOCIOFilePath = std::string(OCIO);
if (fs::exists(configOCIOFilePath))
{
ALICEVISION_LOG_TRACE("OCIO configuration file: '" << configOCIOFilePath << "' found.");
return configOCIOFilePath;
}
else if (configOCIOFilePath == "")
{
ALICEVISION_LOG_TRACE("OCIO is empty. Use embedded config...");
}
else
{
ALICEVISION_LOG_TRACE("OCIO does not point to an existing file. Use embedded config...");
}
}
// To be uncommented to take OCIO env var in consideration before using the enbedded config file
//
//char const* OCIO = getenv("OCIO");
//if (OCIO != NULL)
//{
// configOCIOFilePath = std::string(OCIO);
// if (fs::exists(configOCIOFilePath))
// {
// ALICEVISION_LOG_TRACE("OCIO configuration file: '" << configOCIOFilePath << "' found.");
// return configOCIOFilePath;
// }
// else if (configOCIOFilePath == "")
// {
// ALICEVISION_LOG_TRACE("OCIO is empty. Use embedded config...");
// }
// else
// {
// ALICEVISION_LOG_TRACE("OCIO does not point to an existing file. Use embedded config...");
// }
//}

char const* ALICEVISION_ROOT = getenv("ALICEVISION_ROOT");
if (ALICEVISION_ROOT == NULL)
Expand Down Expand Up @@ -135,7 +148,7 @@ EImageColorSpace EImageColorSpace_stringToEnum(const std::string& dataType)
return EImageColorSpace::LINEAR;
if(type == "srgb")
return EImageColorSpace::SRGB;
if(type == "ACES2065-1")
if(type == "aces2065-1")
return EImageColorSpace::ACES2065_1;
if(type == "acescg")
return EImageColorSpace::ACEScg;
Expand All @@ -156,7 +169,7 @@ std::string EImageColorSpace_enumToString(const EImageColorSpace dataType)
case EImageColorSpace::SRGB:
return "srgb";
case EImageColorSpace::ACES2065_1:
return "ACES2065-1";
return "aces2065-1";
case EImageColorSpace::ACEScg:
return "acescg";
case EImageColorSpace::NO_CONVERSION:
Expand All @@ -169,7 +182,7 @@ bool isValidColorSpace(std::string colorSpace)
{
const std::string CSlc = boost::to_lower_copy(colorSpace);

return (CSlc == "auto") || (CSlc == "linear") || (CSlc == "srgb") || (CSlc == "aces") || (CSlc == "acescg") || (CSlc == "no_conversion");
return (CSlc == "auto") || (CSlc == "linear") || (CSlc == "srgb") || (CSlc == "aces2065-1") || (CSlc == "acescg") || (CSlc == "no_conversion");
}

std::ostream& operator<<(std::ostream& os, EImageColorSpace dataType)
Expand Down Expand Up @@ -367,6 +380,16 @@ oiio::ParamValueList readImageMetadata(const std::string& path, int& width, int&
if(!in)
throw std::runtime_error("Can't find/open image file '" + path + "'.");

#if OIIO_VERSION <= (10000 * 2 + 100 * 0 + 8) // OIIO_VERSION <= 2.0.8
const std::string formatStr = in->format_name();
if(formatStr == "raw")
{
// For the RAW plugin: override colorspace as linear (as the content is linear with sRGB primaries but declared as sRGB)
spec.attribute("oiio:ColorSpace", "Linear");
ALICEVISION_LOG_TRACE("OIIO workaround: RAW input image " << path << " is in Linear.");
}
#endif

width = spec.width;
height = spec.height;

Expand Down Expand Up @@ -460,7 +483,13 @@ void readImage(const std::string& path,
configSpec.attribute("raw:use_camera_wb", (imageReadOptions.applyWhiteBalance?1:0)); // white balance correction
// use_camera_matrix: Whether to use the embedded color profile, if it is present: 0=never, 1 (default)=only for DNG files, 3=always
configSpec.attribute("raw:use_camera_matrix", 3); // use embeded color profile

#if OIIO_VERSION <= (10000 * 2 + 100 * 0 + 8) // OIIO_VERSION <= 2.0.8
// In old versions of oiio, there was no Linear option
configSpec.attribute("raw:ColorSpace", "sRGB"); // use colorspace sRGB
#else
configSpec.attribute("raw:ColorSpace", "Linear"); // use linear colorspace with sRGB primaries
#endif

oiio::ImageBuf inBuf(path, 0, 0, NULL, &configSpec);

Expand All @@ -479,9 +508,17 @@ void readImage(const std::string& path,

if (imageReadOptions.workingColorSpace != EImageColorSpace::NO_CONVERSION)
{
std::string inputColorSpace;
inputColorSpace = EImageColorSpace_enumToString(getImageColorSpace(path));
if (EImageColorSpace_stringToEnum(boost::to_lower_copy(inputColorSpace)) != imageReadOptions.workingColorSpace)
std::string inputColorSpace = inBuf.spec().get_string_attribute("AliceVision:ColorSpace", "");
if ((inputColorSpace.empty()) || !isValidColorSpace(inputColorSpace))
{
inputColorSpace = inBuf.spec().get_string_attribute("oiio:ColorSpace", "");
if ((inputColorSpace.empty()) || !isValidColorSpace(inputColorSpace))
{
// Try to get color space using filename
inputColorSpace = EImageColorSpace_enumToString(getImageColorSpace(path));
}
}
if ((EImageColorSpace_stringToEnum(inputColorSpace) != imageReadOptions.workingColorSpace) && isValidColorSpace(inputColorSpace))
{
std::string outputColorSpace = (imageReadOptions.workingColorSpace == EImageColorSpace::LINEAR) ? "linear" : EImageColorSpace_enumToString(imageReadOptions.workingColorSpace);
oiio::ImageBufAlgo::colorconvert(inBuf, inBuf, inputColorSpace, outputColorSpace, true, "", "", &colorConfigOCIO);
Expand Down
2 changes: 0 additions & 2 deletions src/aliceVision/image/io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ std::istream& operator>>(std::istream& in, EImageColorSpace& dataType);

void initColorConfigOCIO(const std::string& colorConfigFilePath);

EImageColorSpace getImageColorSpace(const std::string imagePath);

/**
* @brief Available image file type for pipeline output
*/
Expand Down
9 changes: 6 additions & 3 deletions src/software/utils/main_imageProcessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,10 @@ int aliceVision_main(int argc, char * argv[])
po::options_description optionalParams("Optional parameters");
optionalParams.add_options()
("metadataFolders", po::value<std::vector<std::string>>(&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<bool>(&pParams.keepImageFilename)->default_value(pParams.keepImageFilename),
"Use original image names instead of view names when saving.")

("reconstructedViewsOnly", po::value<bool>(&pParams.reconstructedViewsOnly)->default_value(pParams.reconstructedViewsOnly),
"Process only recontructed views or all views.")
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 3e995ff

Please sign in to comment.