From 1976f0ffb2ba148472761ad84541565b04d9a660 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Wed, 1 Feb 2023 07:44:47 +0100 Subject: [PATCH 01/14] [Raw] Add options in imageProcessing --- src/aliceVision/image/dcp.cpp | 20 +++--- src/aliceVision/image/dcp.hpp | 4 +- src/aliceVision/image/io.cpp | 67 +++++++++++++++++++-- src/aliceVision/image/io.hpp | 10 ++- src/software/utils/main_imageProcessing.cpp | 28 ++++++++- 5 files changed, 108 insertions(+), 21 deletions(-) diff --git a/src/aliceVision/image/dcp.cpp b/src/aliceVision/image/dcp.cpp index 45079d7813..ec4ec0ecdf 100644 --- a/src/aliceVision/image/dcp.cpp +++ b/src/aliceVision/image/dcp.cpp @@ -2106,10 +2106,12 @@ DCPProfile::Matrix DCPProfile::getCameraToSrgbLinearMatrix(const double x, const return cameraToSrgbLinear; } -DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeutral, const bool sourceIsRaw) const +DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeutral, const bool sourceIsRaw, const bool useColorMatrixOnly) const { + const Triple asShotNeutralInv = { 1.0 / asShotNeutral[0] , 1.0 / asShotNeutral[1] , 1.0 / asShotNeutral[2] }; + double x, y; - getChromaticityCoordinatesFromCameraNeutral(IdentityMatrix, asShotNeutral, x, y); + getChromaticityCoordinatesFromCameraNeutral(IdentityMatrix, asShotNeutralInv, x, y); double cct, tint; setChromaticityCoordinates(x, y, cct, tint); @@ -2119,14 +2121,14 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu if (sourceIsRaw) { - neutral[0][0] = 1.0 / asShotNeutral[0]; - neutral[1][1] = 1.0 / asShotNeutral[1]; - neutral[2][2] = 1.0 / asShotNeutral[2]; + neutral[0][0] = asShotNeutral[0]; + neutral[1][1] = asShotNeutral[1]; + neutral[2][2] = asShotNeutral[2]; } Matrix cameraToXyzD50 = IdentityMatrix; - if ((!info.has_forward_matrix_1) && (!info.has_forward_matrix_2)) + if (useColorMatrixOnly || ((!info.has_forward_matrix_1) && (!info.has_forward_matrix_2))) { Matrix xyzToCamera = IdentityMatrix; if (info.has_color_matrix_1 && info.has_color_matrix_2) @@ -2268,9 +2270,11 @@ void DCPProfile::setMatricesFromStrings(const std::string& type, std::vector cam_mul not applied) */ - void applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const bool sourceIsRaw = false) const; + void applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const bool sourceIsRaw = false, const bool useColorMatrixOnly = false) const; /** * @brief applyLinear applies the linear part of a DCP profile on an aliceVision image @@ -270,7 +270,7 @@ class DCPProfile final Matrix getChromaticAdaptationMatrix(const Triple& xyzSource, const Triple& xyzTarget) const; Matrix getCameraToXyzD50Matrix(const double x, const double y) const; Matrix getCameraToSrgbLinearMatrix(const double x, const double y) const; - Matrix getCameraToACES2065Matrix(const Triple& asShotNeutral, const bool sourceIsRaw = false) const; + Matrix getCameraToACES2065Matrix(const Triple& asShotNeutral, const bool sourceIsRaw = false, const bool useColorMatrixOnly = false) const; Matrix ws_sRGB; // working color space to sRGB Matrix sRGB_ws; // sRGB to working color space diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 7cbded20db..a03a46b1ac 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -436,9 +436,39 @@ void readImage(const std::string& path, oiio::ImageSpec configSpec; const bool isRawImage = isRawFormat(path); + image::DCPProfile::Triple neutral = {1.0,1.0,1.0}; if (isRawImage) { + if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing) + { + oiio::ParamValueList imgMetadata = readImageMetadata(path); + std::string cam_mul = ""; + if (!imgMetadata.getattribute("raw:cam_mul", cam_mul)) + { + cam_mul = "{1024, 1024, 1024, 1024}"; + ALICEVISION_LOG_WARNING("[readImage]: cam_mul metadata not available, the openImageIO version might be too old (>= 2.4.5.0 requested for dcp management)."); + } + + std::vector v_mult; + size_t last = 1; + size_t next = 1; + while ((next = cam_mul.find(",", last)) != std::string::npos) + { + v_mult.push_back(std::stof(cam_mul.substr(last, next - last).c_str())); + last = next + 1; + } + v_mult.push_back(std::stof(cam_mul.substr(last, cam_mul.find("}", last) - last).c_str())); + + for (int i = 0; i < 3; i++) + { + //neutral[i] = v_mult[1] / v_mult[i]; + neutral[i] = v_mult[i] / v_mult[1]; + } + } + + ALICEVISION_LOG_INFO("Neutral from camera = {" << neutral[0] << ", " << neutral[1] << ", " << neutral[2] << "}"); + // libRAW configuration // See https://openimageio.readthedocs.io/en/master/builtinplugins.html#raw-digital-camera-files @@ -457,6 +487,7 @@ void readImage(const std::string& path, configSpec.attribute("raw:use_camera_matrix", 0); // do not use embeded color profile if any configSpec.attribute("raw:ColorSpace", "raw"); // use raw data configSpec.attribute("raw:HighlightMode", 1); // unclip + configSpec.attribute("raw:Demosaic", "DHT"); // DHT algorithm } else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::LibRawNoWhiteBalancing) { @@ -478,13 +509,25 @@ void readImage(const std::string& path, { ALICEVISION_THROW_ERROR("A DCP color profile is required but cannot be found"); } - float user_mul[4] = { 1,1,1,1 }; + ALICEVISION_LOG_INFO("Raw demosaicing algo: " << imageReadOptions.demosaicingAlgo); + ALICEVISION_LOG_INFO("WB after demosaicing: " << (imageReadOptions.doWBAfterDemosaicing ? "True" : "False")); + ALICEVISION_LOG_INFO("Highlight mode: " << (imageReadOptions.highlightMode==0 ? "Clip" : (imageReadOptions.highlightMode == 1 ? "Unclip" : "Blend"))); + float user_mul[4] = { neutral[0],neutral[1],neutral[2],neutral[1] }; + if (imageReadOptions.doWBAfterDemosaicing) + { + for (int i = 0; i < 4; ++i) + { + user_mul[i] = 1.0; + } + } configSpec.attribute("raw:auto_bright", 0); // disable exposure correction - configSpec.attribute("raw:use_camera_wb", 0); // no white balance correction - configSpec.attribute("raw:user_mul", oiio::TypeDesc(oiio::TypeDesc::FLOAT, 4), user_mul); // no neutralization + configSpec.attribute("raw:use_camera_wb", 0); // No White balance correction => user_mul is used + configSpec.attribute("raw:user_mul", oiio::TypeDesc(oiio::TypeDesc::FLOAT, 4), user_mul); configSpec.attribute("raw:use_camera_matrix", 0); // do not use embeded color profile if any configSpec.attribute("raw:ColorSpace", "raw"); + configSpec.attribute("raw:HighlightMode", imageReadOptions.highlightMode); + configSpec.attribute("raw:Demosaic", imageReadOptions.demosaicingAlgo); } else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpMetadata) { @@ -492,14 +535,25 @@ void readImage(const std::string& path, { ALICEVISION_THROW_ERROR("A DCP color profile is required but cannot be found"); } - float user_mul[4] = { 1,1,1,1 }; + ALICEVISION_LOG_INFO("Raw demosaicing algo: " << imageReadOptions.demosaicingAlgo); + ALICEVISION_LOG_INFO("WB after demosaicing: " << (imageReadOptions.doWBAfterDemosaicing ? "True" : "False")); + ALICEVISION_LOG_INFO("Highlight mode: " << (imageReadOptions.highlightMode == 0 ? "Clip" : (imageReadOptions.highlightMode == 1 ? "Unclip" : "Blend"))); + float user_mul[4] = { neutral[0],neutral[1],neutral[2],neutral[1] }; + if (imageReadOptions.doWBAfterDemosaicing) + { + for (int i = 0; i < 4; ++i) + { + user_mul[i] = 1.0; + } + } configSpec.attribute("raw:auto_bright", 0); // disable exposure correction configSpec.attribute("raw:use_camera_wb", 0); // no white balance correction configSpec.attribute("raw:user_mul", oiio::TypeDesc(oiio::TypeDesc::FLOAT, 4), user_mul); // no neutralization configSpec.attribute("raw:use_camera_matrix", 0); // do not use embeded color profile if any configSpec.attribute("raw:ColorSpace", "raw"); // use raw data - configSpec.attribute("raw:HighlightMode", 1); // unclip + configSpec.attribute("raw:HighlightMode", imageReadOptions.highlightMode); + configSpec.attribute("raw:Demosaic", imageReadOptions.demosaicingAlgo); } else { @@ -526,6 +580,7 @@ void readImage(const std::string& path, { image::DCPProfile dcpProfile(imageReadOptions.colorProfileFileName); + oiio::ParamValueList imgMetadata = readImageMetadata(path); std::string cam_mul = ""; if (!imgMetadata.getattribute("raw:cam_mul", cam_mul)) @@ -552,7 +607,7 @@ void readImage(const std::string& path, ALICEVISION_LOG_TRACE("Apply DCP Linear processing with neutral = {" << neutral[0] << ", " << neutral[1] << ", " << neutral[2] << "}"); - dcpProfile.applyLinear(inBuf, neutral, true); + dcpProfile.applyLinear(inBuf, neutral, imageReadOptions.doWBAfterDemosaicing, imageReadOptions.useDCPColorMatrixOnly); } // color conversion diff --git a/src/aliceVision/image/io.hpp b/src/aliceVision/image/io.hpp index 78d75ac3c2..00ff31962f 100644 --- a/src/aliceVision/image/io.hpp +++ b/src/aliceVision/image/io.hpp @@ -183,15 +183,19 @@ struct ImageReadOptions { ImageReadOptions(EImageColorSpace colorSpace = EImageColorSpace::AUTO, ERawColorInterpretation rawColorInterpretation = ERawColorInterpretation::LibRawWhiteBalancing, - const std::string& colorProfile = "", const oiio::ROI& roi = oiio::ROI()) : - workingColorSpace(colorSpace), rawColorInterpretation(rawColorInterpretation), colorProfileFileName(colorProfile), subROI(roi) + const std::string& colorProfile = "", const bool useDCPColorMatrixOnly = false, const oiio::ROI& roi = oiio::ROI()) : + workingColorSpace(colorSpace), rawColorInterpretation(rawColorInterpretation), colorProfileFileName(colorProfile), useDCPColorMatrixOnly(useDCPColorMatrixOnly), + doWBAfterDemosaicing(false), demosaicingAlgo("AHD"), highlightMode(0), subROI(roi) { } EImageColorSpace workingColorSpace; ERawColorInterpretation rawColorInterpretation; std::string colorProfileFileName; - + bool useDCPColorMatrixOnly; + bool doWBAfterDemosaicing; + std::string demosaicingAlgo; + int highlightMode; //ROI for this image. //If the image contains an roi, this is the roi INSIDE the roi. oiio::ROI subROI; diff --git a/src/software/utils/main_imageProcessing.cpp b/src/software/utils/main_imageProcessing.cpp index 3389f80c4c..c15d2ba37a 100644 --- a/src/software/utils/main_imageProcessing.cpp +++ b/src/software/utils/main_imageProcessing.cpp @@ -660,6 +660,10 @@ int aliceVision_main(int argc, char * argv[]) image::ERawColorInterpretation rawColorInterpretation = image::ERawColorInterpretation::LibRawNoWhiteBalancing; std::string colorProfileDatabaseDirPath = ""; bool errorOnMissingColorProfile = true; + bool useDCPColorMatrixOnly = false; + bool doWBAfterDemosaicing = false; + std::string demosaicingAlgo = "AHD"; + int highlightMode = 0; ProcessingParams pParams; @@ -755,10 +759,22 @@ int aliceVision_main(int argc, char * argv[]) "Apply after all processings a linear dcp profile generated from the image DCP metadata if any") ("colorProfileDatabase,c", po::value(&colorProfileDatabaseDirPath)->default_value(""), - "DNG Color Profiles (DCP) database path.") + "DNG Color Profiles (DCP) database path.") ("errorOnMissingColorProfile", po::value(&errorOnMissingColorProfile)->default_value(errorOnMissingColorProfile), - "Rise an error if a DCP color profiles database is specified but no DCP file matches with the camera model (maker+name) extracted from metadata (Only for raw images)") + "Rise an error if a DCP color profiles database is specified but no DCP file matches with the camera model (maker+name) extracted from metadata (Only for raw images)") + + ("useDCPColorMatrixOnly", po::value(&useDCPColorMatrixOnly)->default_value(useDCPColorMatrixOnly), + "Use only Color matrices of DCP profile, ignoring Forward matrices if any.") + + ("doWBAfterDemosaicing", po::value(&doWBAfterDemosaicing)->default_value(doWBAfterDemosaicing), + "Do not use libRaw white balancing. White balance applied just before DCP profile") + + ("demosaicingAlgo", po::value(&demosaicingAlgo)->default_value(demosaicingAlgo), + "Demosaicing algorithm (see libRaw documentation).") + + ("highlightMode", po::value(&highlightMode)->default_value(highlightMode), + "Highlight management (see libRaw documentation).") ("storageDataType", po::value(&storageDataType)->default_value(storageDataType), ("Storage data type: " + image::EStorageDataType_informations()).c_str()) @@ -880,6 +896,10 @@ int aliceVision_main(int argc, char * argv[]) options.rawColorInterpretation = rawColorInterpretation; } options.colorProfileFileName = view.getColorProfileFileName(); + options.useDCPColorMatrixOnly = useDCPColorMatrixOnly; + options.doWBAfterDemosaicing = doWBAfterDemosaicing; + options.demosaicingAlgo = demosaicingAlgo; + options.highlightMode = highlightMode; // Read original image image::Image image; @@ -1061,6 +1081,10 @@ int aliceVision_main(int argc, char * argv[]) readOptions.rawColorInterpretation = rawColorInterpretation; } readOptions.workingColorSpace = workingColorSpace; + readOptions.useDCPColorMatrixOnly = useDCPColorMatrixOnly; + readOptions.doWBAfterDemosaicing = doWBAfterDemosaicing; + readOptions.demosaicingAlgo = demosaicingAlgo; + readOptions.highlightMode = highlightMode; // Read original image image::Image image; From a612825b89fee19e51606fb2d00c2ece81ab8655 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Thu, 2 Feb 2023 10:50:34 +0100 Subject: [PATCH 02/14] [dcp & RAW] Update rawInterpretation "None" by adding parameters Remove White Balancing if done by libRaw in DCP ColorMatrixOnly mode --- src/aliceVision/image/dcp.cpp | 12 +++++++++++- src/aliceVision/image/io.cpp | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/aliceVision/image/dcp.cpp b/src/aliceVision/image/dcp.cpp index ec4ec0ecdf..eb84e518bb 100644 --- a/src/aliceVision/image/dcp.cpp +++ b/src/aliceVision/image/dcp.cpp @@ -2139,7 +2139,17 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu { xyzToCamera = color_matrix_1; } - const Matrix cameraToXyz = matInv(xyzToCamera); + + Matrix wbInv = IdentityMatrix; + if (!sourceIsRaw) + { + // White balancing has been applied before demosaicing but color matrix is supposed to work on non white balanced data + // The white balance operation must be reversed + wbInv[0][0] = asShotNeutralInv[0]; + wbInv[1][1] = asShotNeutralInv[1]; + wbInv[2][2] = asShotNeutralInv[2]; + } + const Matrix cameraToXyz = matMult(matInv(xyzToCamera), wbInv); const double D50_cct = 5000.706605070579; // const double D50_tint = 9.562965495510433; // Using x, y = 0.3457, 0.3585 diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index a03a46b1ac..52e9e39426 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -486,8 +486,8 @@ void readImage(const std::string& path, configSpec.attribute("raw:user_mul", oiio::TypeDesc(oiio::TypeDesc::FLOAT, 4), user_mul); // no neutralization configSpec.attribute("raw:use_camera_matrix", 0); // do not use embeded color profile if any configSpec.attribute("raw:ColorSpace", "raw"); // use raw data - configSpec.attribute("raw:HighlightMode", 1); // unclip - configSpec.attribute("raw:Demosaic", "DHT"); // DHT algorithm + configSpec.attribute("raw:HighlightMode", imageReadOptions.highlightMode); + configSpec.attribute("raw:Demosaic", imageReadOptions.demosaicingAlgo); } else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::LibRawNoWhiteBalancing) { From 42aa74a53926e51ae3578e9f54ac76177b554b47 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Fri, 3 Feb 2023 14:41:22 +0100 Subject: [PATCH 03/14] [raw dcpMetadata] Allow white balancing before demosaicing if option is enabled. --- src/aliceVision/image/io.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 52e9e39426..8c061eb4df 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -440,7 +440,8 @@ void readImage(const std::string& path, if (isRawImage) { - if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing) + if ((imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing) || + (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpMetadata)) { oiio::ParamValueList imgMetadata = readImageMetadata(path); std::string cam_mul = ""; From 20c43f3a85b002a06d4a05385afaa8ead5689fd3 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Tue, 21 Feb 2023 15:39:00 +0100 Subject: [PATCH 04/14] [dcp] Add verbosity --- src/aliceVision/image/dcp.cpp | 29 +++++++++++++++++++++++++++-- src/aliceVision/image/io.cpp | 9 ++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/aliceVision/image/dcp.cpp b/src/aliceVision/image/dcp.cpp index eb84e518bb..c820d41713 100644 --- a/src/aliceVision/image/dcp.cpp +++ b/src/aliceVision/image/dcp.cpp @@ -2112,9 +2112,14 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu double x, y; getChromaticityCoordinatesFromCameraNeutral(IdentityMatrix, asShotNeutralInv, x, y); + + ALICEVISION_LOG_INFO("Chroma Coord (x; y) : (" << x << "; " << y << ")"); + double cct, tint; setChromaticityCoordinates(x, y, cct, tint); + ALICEVISION_LOG_INFO("ColorMatrix1 : " << color_matrix_1); + ALICEVISION_LOG_INFO("ColorMatrix2 : " << color_matrix_2); ALICEVISION_LOG_INFO("Estimated illuminant (cct; tint) : (" << cct << "; " << tint << ")"); Matrix neutral = IdentityMatrix; @@ -2140,6 +2145,8 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu xyzToCamera = color_matrix_1; } + ALICEVISION_LOG_INFO("xyzToCameraMatrix : " << xyzToCamera); + Matrix wbInv = IdentityMatrix; if (!sourceIsRaw) { @@ -2148,22 +2155,40 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu wbInv[0][0] = asShotNeutralInv[0]; wbInv[1][1] = asShotNeutralInv[1]; wbInv[2][2] = asShotNeutralInv[2]; + //wbInv[0][0] = asShotNeutral[0]; + //wbInv[1][1] = asShotNeutral[1]; + //wbInv[2][2] = asShotNeutral[2]; + ALICEVISION_LOG_INFO("wbInv : " << wbInv); } - const Matrix cameraToXyz = matMult(matInv(xyzToCamera), wbInv); + //ALICEVISION_LOG_INFO("cameraToXyzMatrix : " << matInv(xyzToCamera)); + + //const Matrix cameraToXyz = matMult(matInv(xyzToCamera), wbInv); + const Matrix cameraToXyz = matMult(matInv(xyzToCamera), IdentityMatrix); + + ALICEVISION_LOG_INFO("cameraToXyzMatrix : " << cameraToXyz); const double D50_cct = 5000.706605070579; // const double D50_tint = 9.562965495510433; // Using x, y = 0.3457, 0.3585 const Matrix cat = getChromaticAdaptationMatrix(getXyzFromChromaticityCoordinates(x, y), getXyzFromTemperature(D50_cct, D50_tint)); - cameraToXyzD50 = matMult(cat, cameraToXyz); + + ALICEVISION_LOG_INFO("CATmatrix : " << cat); + + cameraToXyzD50 = matMult(matMult(cat, cameraToXyz), wbInv); + //cameraToXyzD50 = matMult(cat, cameraToXyz); } else if ((info.has_forward_matrix_1) && (info.has_forward_matrix_2)) { + ALICEVISION_LOG_INFO("ForwardMatrix1 : " << forward_matrix_1); + ALICEVISION_LOG_INFO("ForwardMatrix2 : " << forward_matrix_2); cameraToXyzD50 = matMult(getInterpolatedMatrix(cct, "forward"), neutral); } else if (info.has_forward_matrix_1) { cameraToXyzD50 = matMult(forward_matrix_1, neutral); } + + ALICEVISION_LOG_INFO("cameraToXyzD50Matrix : " << cameraToXyzD50); + Matrix cameraToACES2065 = matMult(xyzD50ToACES2065Matrix, cameraToXyzD50); return cameraToACES2065; diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 8c061eb4df..38e8eed890 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -512,7 +512,8 @@ void readImage(const std::string& path, } ALICEVISION_LOG_INFO("Raw demosaicing algo: " << imageReadOptions.demosaicingAlgo); ALICEVISION_LOG_INFO("WB after demosaicing: " << (imageReadOptions.doWBAfterDemosaicing ? "True" : "False")); - ALICEVISION_LOG_INFO("Highlight mode: " << (imageReadOptions.highlightMode==0 ? "Clip" : (imageReadOptions.highlightMode == 1 ? "Unclip" : "Blend"))); + ALICEVISION_LOG_INFO("Highlight mode: " << (imageReadOptions.highlightMode == 0 ? "Clip" : (imageReadOptions.highlightMode == 1 ? "Unclip" : "Blend"))); + ALICEVISION_LOG_INFO("DCP mode: " << (imageReadOptions.useDCPColorMatrixOnly ? "Color Matrix Only" : "Full")); float user_mul[4] = { neutral[0],neutral[1],neutral[2],neutral[1] }; if (imageReadOptions.doWBAfterDemosaicing) @@ -539,6 +540,7 @@ void readImage(const std::string& path, ALICEVISION_LOG_INFO("Raw demosaicing algo: " << imageReadOptions.demosaicingAlgo); ALICEVISION_LOG_INFO("WB after demosaicing: " << (imageReadOptions.doWBAfterDemosaicing ? "True" : "False")); ALICEVISION_LOG_INFO("Highlight mode: " << (imageReadOptions.highlightMode == 0 ? "Clip" : (imageReadOptions.highlightMode == 1 ? "Unclip" : "Blend"))); + ALICEVISION_LOG_INFO("DCP mode: " << (imageReadOptions.useDCPColorMatrixOnly ? "Color Matrix Only" : "Full")); float user_mul[4] = { neutral[0],neutral[1],neutral[2],neutral[1] }; if (imageReadOptions.doWBAfterDemosaicing) @@ -603,10 +605,11 @@ void readImage(const std::string& path, image::DCPProfile::Triple neutral; for (int i = 0; i < 3; i++) { - neutral[i] = v_mult[1] / v_mult[i]; + //neutral[i] = v_mult[1] / v_mult[i]; + neutral[i] = v_mult[i] / v_mult[1]; } - ALICEVISION_LOG_TRACE("Apply DCP Linear processing with neutral = {" << neutral[0] << ", " << neutral[1] << ", " << neutral[2] << "}"); + ALICEVISION_LOG_TRACE("Apply DCP Linear processing with neutral = " << neutral); dcpProfile.applyLinear(inBuf, neutral, imageReadOptions.doWBAfterDemosaicing, imageReadOptions.useDCPColorMatrixOnly); } From 901af96308a12f7107b7287d0bc5cf20afee6151 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Wed, 22 Feb 2023 17:29:14 +0100 Subject: [PATCH 05/14] [IO and DCP] Code cleaning For both libraw raw interpretation (w/wo white balancing) consider camera color matrix when reading dng files. --- src/aliceVision/image/dcp.cpp | 25 ++----------------------- src/aliceVision/image/io.cpp | 8 +++----- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/aliceVision/image/dcp.cpp b/src/aliceVision/image/dcp.cpp index c820d41713..7f2f6fd27b 100644 --- a/src/aliceVision/image/dcp.cpp +++ b/src/aliceVision/image/dcp.cpp @@ -2112,14 +2112,9 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu double x, y; getChromaticityCoordinatesFromCameraNeutral(IdentityMatrix, asShotNeutralInv, x, y); - - ALICEVISION_LOG_INFO("Chroma Coord (x; y) : (" << x << "; " << y << ")"); - double cct, tint; setChromaticityCoordinates(x, y, cct, tint); - ALICEVISION_LOG_INFO("ColorMatrix1 : " << color_matrix_1); - ALICEVISION_LOG_INFO("ColorMatrix2 : " << color_matrix_2); ALICEVISION_LOG_INFO("Estimated illuminant (cct; tint) : (" << cct << "; " << tint << ")"); Matrix neutral = IdentityMatrix; @@ -2145,8 +2140,6 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu xyzToCamera = color_matrix_1; } - ALICEVISION_LOG_INFO("xyzToCameraMatrix : " << xyzToCamera); - Matrix wbInv = IdentityMatrix; if (!sourceIsRaw) { @@ -2155,31 +2148,17 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu wbInv[0][0] = asShotNeutralInv[0]; wbInv[1][1] = asShotNeutralInv[1]; wbInv[2][2] = asShotNeutralInv[2]; - //wbInv[0][0] = asShotNeutral[0]; - //wbInv[1][1] = asShotNeutral[1]; - //wbInv[2][2] = asShotNeutral[2]; - ALICEVISION_LOG_INFO("wbInv : " << wbInv); } - //ALICEVISION_LOG_INFO("cameraToXyzMatrix : " << matInv(xyzToCamera)); - - //const Matrix cameraToXyz = matMult(matInv(xyzToCamera), wbInv); - const Matrix cameraToXyz = matMult(matInv(xyzToCamera), IdentityMatrix); - - ALICEVISION_LOG_INFO("cameraToXyzMatrix : " << cameraToXyz); + const Matrix cameraToXyz = matMult(matInv(xyzToCamera), wbInv); const double D50_cct = 5000.706605070579; // const double D50_tint = 9.562965495510433; // Using x, y = 0.3457, 0.3585 const Matrix cat = getChromaticAdaptationMatrix(getXyzFromChromaticityCoordinates(x, y), getXyzFromTemperature(D50_cct, D50_tint)); - ALICEVISION_LOG_INFO("CATmatrix : " << cat); - - cameraToXyzD50 = matMult(matMult(cat, cameraToXyz), wbInv); - //cameraToXyzD50 = matMult(cat, cameraToXyz); + cameraToXyzD50 = matMult(cat, cameraToXyz); } else if ((info.has_forward_matrix_1) && (info.has_forward_matrix_2)) { - ALICEVISION_LOG_INFO("ForwardMatrix1 : " << forward_matrix_1); - ALICEVISION_LOG_INFO("ForwardMatrix2 : " << forward_matrix_2); cameraToXyzD50 = matMult(getInterpolatedMatrix(cct, "forward"), neutral); } else if (info.has_forward_matrix_1) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 38e8eed890..3b9e8e630f 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -463,7 +463,6 @@ void readImage(const std::string& path, for (int i = 0; i < 3; i++) { - //neutral[i] = v_mult[1] / v_mult[i]; neutral[i] = v_mult[i] / v_mult[1]; } } @@ -494,14 +493,14 @@ void readImage(const std::string& path, { configSpec.attribute("raw:auto_bright", 0); // disable exposure correction configSpec.attribute("raw:use_camera_wb", 0); // white balance correction - configSpec.attribute("raw:use_camera_matrix", 0); // do not use embeded color profile if any + configSpec.attribute("raw:use_camera_matrix", 1); // do not use embeded color profile if any except for dng files configSpec.attribute("raw:ColorSpace", "Linear"); // use linear colorspace with sRGB primaries } else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::LibRawWhiteBalancing) { configSpec.attribute("raw:auto_bright", 0); // disable exposure correction configSpec.attribute("raw:use_camera_wb", 1); // white balance correction - configSpec.attribute("raw:use_camera_matrix", 0); // do not use embeded color profile if any + configSpec.attribute("raw:use_camera_matrix", 1); // do not use embeded color profile if any except for dng files configSpec.attribute("raw:ColorSpace", "Linear"); // use linear colorspace with sRGB primaries } else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing) @@ -583,13 +582,12 @@ void readImage(const std::string& path, { image::DCPProfile dcpProfile(imageReadOptions.colorProfileFileName); - oiio::ParamValueList imgMetadata = readImageMetadata(path); std::string cam_mul = ""; if (!imgMetadata.getattribute("raw:cam_mul", cam_mul)) { cam_mul = "{1024, 1024, 1024, 1024}"; - ALICEVISION_LOG_WARNING("[readImage]: cam_mul metadata not availbale, the openImageIO version might be too old (>= 2.4.5.0 requested for dcp management)."); + ALICEVISION_LOG_WARNING("[readImage]: cam_mul metadata not available, the openImageIO version might be too old (>= 2.4.5.0 requested for dcp management)."); } std::vector v_mult; From d49188167eb3904fd5cf93f003fab6cc053cb48a Mon Sep 17 00:00:00 2001 From: demoulinv Date: Wed, 1 Mar 2023 16:53:38 +0100 Subject: [PATCH 06/14] [imageProcessing dcpMetadata interpretation] Align handling of raw color interpretation case of dcpMetadata, whether the imageProcessing node uses a view from an sfmData or an input image file. Add AliceVision:ColorSpace in view metadata. Force workingColorSpace to 'no_conversion' if applyDCPMetadata option is enabled. --- src/aliceVision/image/dcp.cpp | 7 +- src/aliceVision/image/dcp.hpp | 4 +- src/aliceVision/image/io.cpp | 3 +- src/software/utils/main_imageProcessing.cpp | 87 +++++++++++++++------ 4 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/aliceVision/image/dcp.cpp b/src/aliceVision/image/dcp.cpp index 7f2f6fd27b..0b94d74ba5 100644 --- a/src/aliceVision/image/dcp.cpp +++ b/src/aliceVision/image/dcp.cpp @@ -2118,7 +2118,6 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu ALICEVISION_LOG_INFO("Estimated illuminant (cct; tint) : (" << cct << "; " << tint << ")"); Matrix neutral = IdentityMatrix; - if (sourceIsRaw) { neutral[0][0] = asShotNeutral[0]; @@ -2310,9 +2309,11 @@ void DCPProfile::applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const } } -void DCPProfile::applyLinear(Image& image, const Triple& neutral, const bool sourceIsRaw) const +void DCPProfile::applyLinear(Image& image, const Triple& neutral, const bool sourceIsRaw, const bool useColorMatrixOnly) const { - const Matrix cameraToACES2065Matrix = getCameraToACES2065Matrix(neutral, sourceIsRaw); + const Matrix cameraToACES2065Matrix = getCameraToACES2065Matrix(neutral, sourceIsRaw, useColorMatrixOnly); + + ALICEVISION_LOG_INFO("cameraToACES2065Matrix : " << cameraToACES2065Matrix); #pragma omp parallel for for (int i = 0; i < image.Height(); ++i) diff --git a/src/aliceVision/image/dcp.hpp b/src/aliceVision/image/dcp.hpp index 28780a56de..02b1718eb8 100644 --- a/src/aliceVision/image/dcp.hpp +++ b/src/aliceVision/image/dcp.hpp @@ -201,6 +201,7 @@ class DCPProfile final * param[in] image The OIIO image on which the profile must be applied * param[in] neutral The neutral value calculated from the camera multiplicators contained in the cam_mul OIIO metadata * param[in] sourceIsRaw indicates that the image buffer contains data in raw space (no neutralization <=> cam_mul not applied) + * param[in] useColorMatrixOnly indicates to apply a DCP profile computed only from the color matrices */ void applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const bool sourceIsRaw = false, const bool useColorMatrixOnly = false) const; @@ -209,8 +210,9 @@ class DCPProfile final * param[in] image The aliceVision image on which the profile must be applied * param[in] neutral The neutral value calculated from the camera multiplicators contained in the cam_mul OIIO metadata * param[in] sourceIsRaw indicates that the image buffer contains data in raw space (no neutralization <=> cam_mul not applied) + * param[in] useColorMatrixOnly indicates to apply a DCP profile computed only from the color matrices */ - void applyLinear(Image& image, const Triple& neutral, const bool sourceIsRaw = false) const; + void applyLinear(Image& image, const Triple& neutral, const bool sourceIsRaw = false, const bool useColorMatrixOnly = false) const; /** * @brief apply applies the non linear part of a DCP profile on an OIIO image buffer diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 3b9e8e630f..bb84dd7f98 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -603,11 +603,10 @@ void readImage(const std::string& path, image::DCPProfile::Triple neutral; for (int i = 0; i < 3; i++) { - //neutral[i] = v_mult[1] / v_mult[i]; neutral[i] = v_mult[i] / v_mult[1]; } - ALICEVISION_LOG_TRACE("Apply DCP Linear processing with neutral = " << neutral); + ALICEVISION_LOG_INFO("Apply DCP Linear processing with neutral = " << neutral); dcpProfile.applyLinear(inBuf, neutral, imageReadOptions.doWBAfterDemosaicing, imageReadOptions.useDCPColorMatrixOnly); } diff --git a/src/software/utils/main_imageProcessing.cpp b/src/software/utils/main_imageProcessing.cpp index c15d2ba37a..519022115e 100644 --- a/src/software/utils/main_imageProcessing.cpp +++ b/src/software/utils/main_imageProcessing.cpp @@ -265,6 +265,7 @@ struct ProcessingParams bool fillHoles = false; bool fixNonFinite = false; bool applyDcpMetadata = false; + bool useDCPColorMatrixOnly = false; SharpenParams sharpen = { @@ -490,10 +491,10 @@ void processImage(image::Image& image, const ProcessingParams ALICEVISION_LOG_INFO("Matrix Number : " << colorMatrixNb << " ; " << fwdMatrixNb); dcpMetadataOK = !((colorMatrixNb == 0) || - ((colorMatrixNb > 0) && map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ColorMat1")) || - ((colorMatrixNb > 1) && map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ColorMat2")) || - ((fwdMatrixNb > 0) && map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ForwardMat1")) || - ((fwdMatrixNb > 1) && map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ForwardMat2"))); + ((colorMatrixNb > 0) && !map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ColorMat1")) || + ((colorMatrixNb > 1) && !map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ColorMat2")) || + ((fwdMatrixNb > 0) && !map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ForwardMat1")) || + ((fwdMatrixNb > 1) && !map_has_non_empty_value(imageMetadata, "AliceVision:DCP:ForwardMat2"))); } if (!dcpMetadataOK) @@ -530,7 +531,7 @@ void processImage(image::Image& image, const ProcessingParams dcpProf.setMatricesFromStrings("forward", v_str); } - std::string cam_mul = imageMetadata.at("raw:cam_mul"); + std::string cam_mul = map_has_non_empty_value(imageMetadata, "raw:cam_mul") ? imageMetadata.at("raw:cam_mul") : imageMetadata.at("AliceVision:raw:cam_mul"); std::vector v_mult; size_t last = 0; size_t next = 1; @@ -544,10 +545,10 @@ void processImage(image::Image& image, const ProcessingParams image::DCPProfile::Triple neutral; for (int i = 0; i < 3; i++) { - neutral[i] = v_mult[1] / v_mult[i]; + neutral[i] = v_mult[i] / v_mult[1]; } - dcpProf.applyLinear(image, neutral, true); + dcpProf.applyLinear(image, neutral, true, pParams.useDCPColorMatrixOnly); } } @@ -765,16 +766,19 @@ int aliceVision_main(int argc, char * argv[]) "Rise an error if a DCP color profiles database is specified but no DCP file matches with the camera model (maker+name) extracted from metadata (Only for raw images)") ("useDCPColorMatrixOnly", po::value(&useDCPColorMatrixOnly)->default_value(useDCPColorMatrixOnly), - "Use only Color matrices of DCP profile, ignoring Forward matrices if any.") + "Use only Color matrices of DCP profile, ignoring Forward matrices if any. Default: False.\n" + "In case white balancing has been done before demosaicing, the reverse operation is done before applying the color matrix.") ("doWBAfterDemosaicing", po::value(&doWBAfterDemosaicing)->default_value(doWBAfterDemosaicing), - "Do not use libRaw white balancing. White balance applied just before DCP profile") + "Do not use libRaw white balancing. White balancing is applied just before DCP profile if useDCPColorMatrixOnly is set to False. Default: False.") ("demosaicingAlgo", po::value(&demosaicingAlgo)->default_value(demosaicingAlgo), - "Demosaicing algorithm (see libRaw documentation).") + "Demosaicing algorithm (see libRaw documentation).\n" + "Possible algos are: linear, VNG, PPG, AHD (default), DCB, AHD-Mod, AFD, VCD, Mixed, LMMSE, AMaZE, DHT, AAHD, none.") ("highlightMode", po::value(&highlightMode)->default_value(highlightMode), - "Highlight management (see libRaw documentation).") + "Highlight management (see libRaw documentation).\n" + "0 = clip (default), 1 = unclip, 2 = blend, 3+ = rebuild.") ("storageDataType", po::value(&storageDataType)->default_value(storageDataType), ("Storage data type: " + image::EStorageDataType_informations()).c_str()) @@ -885,19 +889,36 @@ int aliceVision_main(int argc, char * argv[]) ALICEVISION_LOG_INFO(++i << "/" << size << " - Process view '" << viewId << "'."); + auto metadata = view.getMetadata(); + + if (pParams.applyDcpMetadata && metadata["AliceVision:ColorSpace"] != "no_conversion") + { + ALICEVISION_LOG_WARNING("A dcp profile will be applied on an image containing non raw data!"); + } + image::ImageReadOptions options; - options.workingColorSpace = workingColorSpace; + options.workingColorSpace = pParams.applyDcpMetadata ? image::EImageColorSpace::NO_CONVERSION : workingColorSpace; if (rawColorInterpretation == image::ERawColorInterpretation::Auto) { options.rawColorInterpretation = image::ERawColorInterpretation_stringToEnum(view.getRawColorInterpretation()); + if (options.rawColorInterpretation == image::ERawColorInterpretation::DcpMetadata) + { + options.useDCPColorMatrixOnly = false; + options.doWBAfterDemosaicing = true; + } + else + { + options.useDCPColorMatrixOnly = useDCPColorMatrixOnly; + options.doWBAfterDemosaicing = doWBAfterDemosaicing; + } } else { options.rawColorInterpretation = rawColorInterpretation; + options.useDCPColorMatrixOnly = useDCPColorMatrixOnly; + options.doWBAfterDemosaicing = doWBAfterDemosaicing; } options.colorProfileFileName = view.getColorProfileFileName(); - options.useDCPColorMatrixOnly = useDCPColorMatrixOnly; - options.doWBAfterDemosaicing = doWBAfterDemosaicing; options.demosaicingAlgo = demosaicingAlgo; options.highlightMode = highlightMode; @@ -922,6 +943,11 @@ int aliceVision_main(int argc, char * argv[]) // Image processing processImage(image, pParams, view.getMetadata()); + if (pParams.applyDcpMetadata) + { + workingColorSpace = image::EImageColorSpace::ACES2065_1; + } + // Save the image saveImage(image, viewPath, outputfilePath, view.getMetadata(), metadataFolders, workingColorSpace, outputFormat, outputColorSpace, storageDataType); @@ -929,6 +955,7 @@ int aliceVision_main(int argc, char * argv[]) view.setImagePath(outputfilePath); view.setWidth(image.Width()); view.setHeight(image.Height()); + view.addMetadata("AliceVision:ColorSpace", image::EImageColorSpace_enumToString(outputColorSpace)); } if (pParams.scaleFactor != 1.0f) @@ -1032,6 +1059,10 @@ int aliceVision_main(int argc, char * argv[]) image::DCPProfile dcpProf; sfmData::View view; // used to extract and complete metadata + view.setImagePath(inputFilePath); + int width, height; + const auto metadata = image::readImageMetadata(inputFilePath, width, height); + view.setMetadata(image::getMapFromMetadata(metadata)); if (rawColorInterpretation == image::ERawColorInterpretation::DcpLinearProcessing || rawColorInterpretation == image::ERawColorInterpretation::DcpMetadata) @@ -1039,12 +1070,7 @@ int aliceVision_main(int argc, char * argv[]) // Load DCP color profiles database if not already loaded dcpDatabase.load(colorProfileDatabaseDirPath.empty() ? getColorProfileDatabaseFolder() : colorProfileDatabaseDirPath, false); - // Get DSLR maker and model by creating a view and picking values up in it. - view.setImagePath(inputFilePath); - int width, height; - const auto metadata = image::readImageMetadata(inputFilePath, width, height); - view.setMetadata(image::getMapFromMetadata(metadata)); - + // Get DSLR maker and model in view metadata. const std::string& make = view.getMetadataMake(); const std::string& model = view.getMetadataModel(); @@ -1080,7 +1106,15 @@ int aliceVision_main(int argc, char * argv[]) { readOptions.rawColorInterpretation = rawColorInterpretation; } - readOptions.workingColorSpace = workingColorSpace; + + std::map md = view.getMetadata(); + + if (pParams.applyDcpMetadata && md["AliceVision::ColorSpace"] != "no_conversion") + { + ALICEVISION_LOG_WARNING("A dcp profile will be applied on an image containing non raw data!"); + } + + readOptions.workingColorSpace = pParams.applyDcpMetadata ? image::EImageColorSpace::NO_CONVERSION : workingColorSpace; readOptions.useDCPColorMatrixOnly = useDCPColorMatrixOnly; readOptions.doWBAfterDemosaicing = doWBAfterDemosaicing; readOptions.demosaicingAlgo = demosaicingAlgo; @@ -1090,13 +1124,18 @@ int aliceVision_main(int argc, char * argv[]) image::Image image; image::readImage(inputFilePath, image, readOptions); - std::map metadata = view.getMetadata(); + pParams.useDCPColorMatrixOnly = useDCPColorMatrixOnly; // Image processing - processImage(image, pParams,metadata); + processImage(image, pParams, md); + + if (pParams.applyDcpMetadata) + { + workingColorSpace = image::EImageColorSpace::ACES2065_1; + } // Save the image - saveImage(image, inputFilePath, outputFilePath, metadata, metadataFolders, workingColorSpace, outputFormat, outputColorSpace, storageDataType); + saveImage(image, inputFilePath, outputFilePath, md, metadataFolders, workingColorSpace, outputFormat, outputColorSpace, storageDataType); } } From 537057c754d9e74e503f8b2ff5db3e5f7f4e29e7 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Thu, 2 Mar 2023 11:52:10 +0100 Subject: [PATCH 07/14] [DCP processing] change default mode to ColorMatrixOnly --- src/aliceVision/image/dcp.hpp | 2 +- src/aliceVision/image/io.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aliceVision/image/dcp.hpp b/src/aliceVision/image/dcp.hpp index 02b1718eb8..09d5817dcb 100644 --- a/src/aliceVision/image/dcp.hpp +++ b/src/aliceVision/image/dcp.hpp @@ -203,7 +203,7 @@ class DCPProfile final * param[in] sourceIsRaw indicates that the image buffer contains data in raw space (no neutralization <=> cam_mul not applied) * param[in] useColorMatrixOnly indicates to apply a DCP profile computed only from the color matrices */ - void applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const bool sourceIsRaw = false, const bool useColorMatrixOnly = false) const; + void applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const bool sourceIsRaw = false, const bool useColorMatrixOnly = true) const; /** * @brief applyLinear applies the linear part of a DCP profile on an aliceVision image diff --git a/src/aliceVision/image/io.hpp b/src/aliceVision/image/io.hpp index 00ff31962f..37ca0a57ae 100644 --- a/src/aliceVision/image/io.hpp +++ b/src/aliceVision/image/io.hpp @@ -183,7 +183,7 @@ struct ImageReadOptions { ImageReadOptions(EImageColorSpace colorSpace = EImageColorSpace::AUTO, ERawColorInterpretation rawColorInterpretation = ERawColorInterpretation::LibRawWhiteBalancing, - const std::string& colorProfile = "", const bool useDCPColorMatrixOnly = false, const oiio::ROI& roi = oiio::ROI()) : + const std::string& colorProfile = "", const bool useDCPColorMatrixOnly = true, const oiio::ROI& roi = oiio::ROI()) : workingColorSpace(colorSpace), rawColorInterpretation(rawColorInterpretation), colorProfileFileName(colorProfile), useDCPColorMatrixOnly(useDCPColorMatrixOnly), doWBAfterDemosaicing(false), demosaicingAlgo("AHD"), highlightMode(0), subROI(roi) { From e2b9e013c071e9e9ee14fcc7e7bee9cdbd395879 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Thu, 2 Mar 2023 20:30:00 +0100 Subject: [PATCH 08/14] [panorama Post Processing] Add output color space option. Code factorization for dcp loading from map of metadata --- src/aliceVision/image/dcp.cpp | 58 ++++++++++++ src/aliceVision/image/dcp.hpp | 6 ++ src/aliceVision/image/io.cpp | 10 --- src/software/pipeline/main_LdrToHdrMerge.cpp | 10 ++- .../pipeline/main_panoramaPostProcessing.cpp | 89 ++++++++++++++++++- 5 files changed, 157 insertions(+), 16 deletions(-) diff --git a/src/aliceVision/image/dcp.cpp b/src/aliceVision/image/dcp.cpp index 0b94d74ba5..beb308b865 100644 --- a/src/aliceVision/image/dcp.cpp +++ b/src/aliceVision/image/dcp.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -1294,6 +1295,63 @@ void DCPProfile::Load(const std::string& filename) igammatab_srgb.Set(igammatab_srgb_data); } +void DCPProfile::Load(const std::map& metadata) +{ + bool dcpMetadataOK = aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:Temp1") && + aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:Temp2") && + aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:ForwardMatrixNumber") && + aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:ColorMatrixNumber"); + + int colorMatrixNb; + int fwdMatrixNb; + + if (dcpMetadataOK) + { + colorMatrixNb = std::stoi(metadata.at("AliceVision:DCP:ColorMatrixNumber")); + fwdMatrixNb = std::stoi(metadata.at("AliceVision:DCP:ForwardMatrixNumber")); + + ALICEVISION_LOG_INFO("Matrix Number : " << colorMatrixNb << " ; " << fwdMatrixNb); + + dcpMetadataOK = !((colorMatrixNb == 0) || + ((colorMatrixNb > 0) && !aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:ColorMat1")) || + ((colorMatrixNb > 1) && !aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:ColorMat2")) || + ((fwdMatrixNb > 0) && !aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:ForwardMat1")) || + ((fwdMatrixNb > 1) && !aliceVision::map_has_non_empty_value(metadata, "AliceVision:DCP:ForwardMat2"))); + } + + if (!dcpMetadataOK) + { + ALICEVISION_THROW_ERROR("Image Processing: All required DCP metadata cannot be found.\n" << metadata); + } + + info.temperature_1 = std::stof(metadata.at("AliceVision:DCP:Temp1")); + info.temperature_2 = std::stof(metadata.at("AliceVision:DCP:Temp2")); + info.has_color_matrix_1 = colorMatrixNb > 0; + info.has_color_matrix_2 = colorMatrixNb > 1; + info.has_forward_matrix_1 = fwdMatrixNb > 0; + info.has_forward_matrix_2 = fwdMatrixNb > 1; + + std::vector v_str; + + v_str.push_back(metadata.at("AliceVision:DCP:ColorMat1")); + if (colorMatrixNb > 1) + { + v_str.push_back(metadata.at("AliceVision:DCP:ColorMat2")); + } + setMatricesFromStrings("color", v_str); + + v_str.clear(); + if (fwdMatrixNb > 0) + { + v_str.push_back(metadata.at("AliceVision:DCP:ForwardMat1")); + if (fwdMatrixNb > 1) + { + v_str.push_back(metadata.at("AliceVision:DCP:ForwardMat2")); + } + setMatricesFromStrings("forward", v_str); + } +} + void DCPProfile::apply(OIIO::ImageBuf& image, const DCPProfileApplyParams& params) { // Compute matrices to and from selected working space diff --git a/src/aliceVision/image/dcp.hpp b/src/aliceVision/image/dcp.hpp index 09d5817dcb..620a65e525 100644 --- a/src/aliceVision/image/dcp.hpp +++ b/src/aliceVision/image/dcp.hpp @@ -168,6 +168,12 @@ class DCPProfile final */ void Load(const std::string& filename); + /** + * @brief DCPProfile loader + * @param[in] map of metadata + */ + void Load(const std::map& metadata); + /** * @brief getMatrices gets some matrices contained in the profile * param[in] type The matrices to get, "color" or "forward" diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index bb84dd7f98..16f5a5f029 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -509,11 +509,6 @@ void readImage(const std::string& path, { ALICEVISION_THROW_ERROR("A DCP color profile is required but cannot be found"); } - ALICEVISION_LOG_INFO("Raw demosaicing algo: " << imageReadOptions.demosaicingAlgo); - ALICEVISION_LOG_INFO("WB after demosaicing: " << (imageReadOptions.doWBAfterDemosaicing ? "True" : "False")); - ALICEVISION_LOG_INFO("Highlight mode: " << (imageReadOptions.highlightMode == 0 ? "Clip" : (imageReadOptions.highlightMode == 1 ? "Unclip" : "Blend"))); - ALICEVISION_LOG_INFO("DCP mode: " << (imageReadOptions.useDCPColorMatrixOnly ? "Color Matrix Only" : "Full")); - float user_mul[4] = { neutral[0],neutral[1],neutral[2],neutral[1] }; if (imageReadOptions.doWBAfterDemosaicing) { @@ -536,11 +531,6 @@ void readImage(const std::string& path, { ALICEVISION_THROW_ERROR("A DCP color profile is required but cannot be found"); } - ALICEVISION_LOG_INFO("Raw demosaicing algo: " << imageReadOptions.demosaicingAlgo); - ALICEVISION_LOG_INFO("WB after demosaicing: " << (imageReadOptions.doWBAfterDemosaicing ? "True" : "False")); - ALICEVISION_LOG_INFO("Highlight mode: " << (imageReadOptions.highlightMode == 0 ? "Clip" : (imageReadOptions.highlightMode == 1 ? "Unclip" : "Blend"))); - ALICEVISION_LOG_INFO("DCP mode: " << (imageReadOptions.useDCPColorMatrixOnly ? "Color Matrix Only" : "Full")); - float user_mul[4] = { neutral[0],neutral[1],neutral[2],neutral[1] }; if (imageReadOptions.doWBAfterDemosaicing) { diff --git a/src/software/pipeline/main_LdrToHdrMerge.cpp b/src/software/pipeline/main_LdrToHdrMerge.cpp index 66dfff46fa..820f2491e6 100644 --- a/src/software/pipeline/main_LdrToHdrMerge.cpp +++ b/src/software/pipeline/main_LdrToHdrMerge.cpp @@ -341,8 +341,14 @@ int aliceVision_main(int argc, char** argv) { targetMetadata.add_or_replace(oiio::ParamValue(meta.first, meta.second)); } - targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", image::EImageColorSpace_enumToString(image::EImageColorSpace::LINEAR))); - image::writeImage(hdrImagePath, HDRimage, image::ImageWriteOptions().storageDataType(storageDataType), targetMetadata); + targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", image::EImageColorSpace_enumToString(workingColorSpace))); + + image::ImageWriteOptions writeOptions; + writeOptions.fromColorSpace(workingColorSpace); + writeOptions.toColorSpace(workingColorSpace); + writeOptions.storageDataType(storageDataType); + + image::writeImage(hdrImagePath, HDRimage, writeOptions, targetMetadata); } return EXIT_SUCCESS; diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index c0494491fa..5ad56e6cdc 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include #include @@ -142,12 +144,55 @@ bool readFullTile(image::Image & output, std::unique_ptr& inputImage, oiio::ImageBuf* outBuf, image::EImageColorSpace fromColorSpace, image::EImageColorSpace toColorSpace, image::DCPProfile dcpProf, image::DCPProfile::Triple neutral) +{ + const int width = inputImage.Width(); + const int tileSize = inputImage.Height(); + oiio::ImageBuf inBuf = oiio::ImageBuf(oiio::ImageSpec(width, tileSize, 4, oiio::TypeDesc::FLOAT), const_cast(inputImage.data())); + outBuf = &inBuf; + + if (fromColorSpace == image::EImageColorSpace::NO_CONVERSION) + { + dcpProf.applyLinear(inBuf, neutral, true, true); + fromColorSpace = image::EImageColorSpace::ACES2065_1; + } + + oiio::ImageBuf colorspaceBuf = oiio::ImageBuf(oiio::ImageSpec(width, tileSize, 4, oiio::TypeDesc::FLOAT), const_cast(inputImage.data())); // buffer for image colorspace modification + if ((fromColorSpace == toColorSpace) || (toColorSpace == image::EImageColorSpace::NO_CONVERSION)) + { + // Do nothing. Note that calling imageAlgo::colorconvert() will copy the source buffer + // even if no conversion is needed. + } + else if ((toColorSpace == image::EImageColorSpace::ACES2065_1) || (toColorSpace == image::EImageColorSpace::ACEScg) || + (fromColorSpace == image::EImageColorSpace::ACES2065_1) || (fromColorSpace == image::EImageColorSpace::ACEScg)) + { + const auto colorConfigPath = image::getAliceVisionOCIOConfig(); + if (colorConfigPath.empty()) + { + throw std::runtime_error("ALICEVISION_ROOT is not defined, OCIO config file cannot be accessed."); + } + oiio::ColorConfig colorConfig(colorConfigPath); + oiio::ImageBufAlgo::colorconvert(colorspaceBuf, *outBuf, + EImageColorSpace_enumToOIIOString(fromColorSpace), + EImageColorSpace_enumToOIIOString(toColorSpace), true, "", "", + &colorConfig); + outBuf = &colorspaceBuf; + } + else + { + oiio::ImageBufAlgo::colorconvert(colorspaceBuf, *outBuf, EImageColorSpace_enumToOIIOString(fromColorSpace), EImageColorSpace_enumToOIIOString(toColorSpace)); + outBuf = &colorspaceBuf; + } + +} + int aliceVision_main(int argc, char** argv) { std::string inputPanoramaPath; std::string outputPanoramaPath; image::EStorageDataType storageDataType = image::EStorageDataType::Float; - const size_t maxProcessingSize = 2000; + image::EImageColorSpace outputColorSpace = image::EImageColorSpace::LINEAR; + const size_t maxProcessingSize = 2000; bool fillHoles = false; // Description of mandatory parameters @@ -160,7 +205,8 @@ int aliceVision_main(int argc, char** argv) po::options_description optionalParams("Optional parameters"); optionalParams.add_options() ("storageDataType", po::value(&storageDataType)->default_value(storageDataType), ("Storage data type: " + image::EStorageDataType_informations()).c_str()) - ("fillHoles", po::value(&fillHoles)->default_value(fillHoles), "Execute fill holes algorithm"); + ("fillHoles", po::value(&fillHoles)->default_value(fillHoles), "Execute fill holes algorithm") + ("outputColorSpace", po::value(&outputColorSpace)->default_value(outputColorSpace), "Color space for the output panorama."); CmdLine cmdline("This program performs estimation of cameras orientation around a nodal point for 360° panorama.\n" "AliceVision PanoramaPostProcessing"); @@ -182,12 +228,41 @@ int aliceVision_main(int argc, char** argv) const oiio::ImageSpec &inputSpec = panoramaInput->spec(); const int tileWidth = inputSpec.tile_width; const int tileHeight = inputSpec.tile_height; + image::EImageColorSpace fromColorSpace = image::EImageColorSpace_stringToEnum(inputSpec.get_string_attribute("AliceVision:ColorSpace", "linear")); + + int tmpWidth, tmpHeight; // same as tileWidth and tileHeight ???? + std::map imageMetadata = image::getMapFromMetadata(image::readImageMetadata(inputPanoramaPath, tmpWidth, tmpHeight)); + if (tileWidth != tileHeight) { ALICEVISION_LOG_ERROR("non square tiles !"); return EXIT_FAILURE; } + image::DCPProfile dcpProf; + image::DCPProfile::Triple neutral; + if (fromColorSpace == image::EImageColorSpace::NO_CONVERSION) + { + // load DCP metadata + dcpProf.Load(imageMetadata); + + std::string cam_mul = map_has_non_empty_value(imageMetadata, "raw:cam_mul") ? imageMetadata.at("raw:cam_mul") : imageMetadata.at("AliceVision:raw:cam_mul"); + std::vector v_mult; + size_t last = 0; + size_t next = 1; + while ((next = cam_mul.find(",", last)) != std::string::npos) + { + v_mult.push_back(std::stof(cam_mul.substr(last, next - last))); + last = next + 1; + } + v_mult.push_back(std::stof(cam_mul.substr(last, cam_mul.find("}", last) - last))); + + for (int i = 0; i < 3; i++) + { + neutral[i] = v_mult[i] / v_mult[1]; + } + } + //Create output panorama std::unique_ptr panoramaOutput = oiio::ImageOutput::create(outputPanoramaPath); oiio::ImageSpec outputSpec(inputSpec); @@ -415,7 +490,10 @@ int aliceVision_main(int argc, char** argv) final.block(0, 0, tileSize, width) = finalTile.block(tileSize, tileSize, tileSize, width); - panoramaOutput->write_scanlines(ty * tileSize, (ty + 1) * tileSize, 0, oiio::TypeDesc::FLOAT, final.data()); + oiio::ImageBuf* outBuf = nullptr; + colorSpaceTransform(final, outBuf, fromColorSpace, outputColorSpace, dcpProf, neutral); + + panoramaOutput->write_scanlines(ty * tileSize, (ty + 1) * tileSize, 0, oiio::TypeDesc::FLOAT, outBuf->localpixels()); } } else @@ -449,7 +527,10 @@ int aliceVision_main(int argc, char** argv) } } - panoramaOutput->write_scanlines(ybegin, yend, 0, oiio::TypeDesc::FLOAT, final.data()); + oiio::ImageBuf* outBuf = nullptr; + colorSpaceTransform(final, outBuf, fromColorSpace, outputColorSpace, dcpProf, neutral); + + panoramaOutput->write_scanlines(ybegin, yend, 0, oiio::TypeDesc::FLOAT, outBuf->localpixels()); } } From 4d681ebfa4ca76d9a8cae6c9b5c24e897f422e85 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Fri, 3 Mar 2023 15:01:10 +0100 Subject: [PATCH 09/14] [IOs] Update readImage to support reading images containing raw data in a non raw image format. --- src/aliceVision/image/io.cpp | 45 ++++++++++++++++++-- src/software/pipeline/main_LdrToHdrMerge.cpp | 9 +++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index 16f5a5f029..b6678ae491 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -606,12 +607,48 @@ void readImage(const std::string& path, ALICEVISION_THROW_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 = (isRawImage && imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing) ? "aces2065-1" : - (isRawImage ? "linear" : - inBuf.spec().get_string_attribute("aliceVision:ColorSpace", inBuf.spec().get_string_attribute("oiio:ColorSpace", "sRGB"))); + std::string fromColorSpaceName = (isRawImage && imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing) ? "aces2065-1" : + (isRawImage ? "linear" : + inBuf.spec().get_string_attribute("aliceVision:ColorSpace", inBuf.spec().get_string_attribute("oiio:ColorSpace", "sRGB"))); ALICEVISION_LOG_TRACE("Read image " << path << " (encoded in " << fromColorSpaceName << " colorspace)."); - + + DCPProfile dcpProf; + if ((fromColorSpaceName == "no_conversion") && (imageReadOptions.workingColorSpace != EImageColorSpace::NO_CONVERSION)) + { + ALICEVISION_LOG_INFO("Source image is in a raw color space and must be converted into " << imageReadOptions.workingColorSpace << "."); + ALICEVISION_LOG_INFO("Check if a DCP profile is available in the metadata to be applied."); + if (inBuf.spec().nchannels < 3) + { + ALICEVISION_THROW_ERROR("A DCP profile cannot be applied on an image containing less than 3 channels."); + } + + int width, height; + std::map imageMetadata = getMapFromMetadata(readImageMetadata(path, width, height)); + + // load DCP metadata from metadata. An error will be thrown if all required metadata are not there. + dcpProf.Load(imageMetadata); + + std::string cam_mul = map_has_non_empty_value(imageMetadata, "raw:cam_mul") ? imageMetadata.at("raw:cam_mul") : imageMetadata.at("AliceVision:raw:cam_mul"); + std::vector v_mult; + size_t last = 0; + size_t next = 1; + while ((next = cam_mul.find(",", last)) != std::string::npos) + { + v_mult.push_back(std::stof(cam_mul.substr(last, next - last))); + last = next + 1; + } + v_mult.push_back(std::stof(cam_mul.substr(last, cam_mul.find("}", last) - last))); + + for (int i = 0; i < 3; i++) + { + neutral[i] = v_mult[i] / v_mult[1]; + } + + dcpProf.applyLinear(inBuf, neutral, imageReadOptions.doWBAfterDemosaicing, imageReadOptions.useDCPColorMatrixOnly); + fromColorSpaceName = "aces2065-1"; + } + if ((imageReadOptions.workingColorSpace == EImageColorSpace::NO_CONVERSION) || (imageReadOptions.workingColorSpace == EImageColorSpace_stringToEnum(fromColorSpaceName))) { diff --git a/src/software/pipeline/main_LdrToHdrMerge.cpp b/src/software/pipeline/main_LdrToHdrMerge.cpp index 820f2491e6..cf5812f67a 100644 --- a/src/software/pipeline/main_LdrToHdrMerge.cpp +++ b/src/software/pipeline/main_LdrToHdrMerge.cpp @@ -339,7 +339,14 @@ int aliceVision_main(int argc, char** argv) oiio::ParamValueList targetMetadata; for (const auto& meta : viewMetadata) { - targetMetadata.add_or_replace(oiio::ParamValue(meta.first, meta.second)); + if (meta.first.compare(0, 3, "raw") == 0) + { + targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:" + meta.first, meta.second)); + } + else + { + targetMetadata.add_or_replace(oiio::ParamValue(meta.first, meta.second)); + } } targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", image::EImageColorSpace_enumToString(workingColorSpace))); From c41a19d7507aeaf86516947a7be25da75d15ec90 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Sat, 4 Mar 2023 18:32:26 +0100 Subject: [PATCH 10/14] [panoramaPostProcessing] BugFix outputColorSpace --- .../pipeline/main_panoramaPostProcessing.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index 5ad56e6cdc..1bc6de326f 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -144,12 +144,12 @@ bool readFullTile(image::Image & output, std::unique_ptr& inputImage, oiio::ImageBuf* outBuf, image::EImageColorSpace fromColorSpace, image::EImageColorSpace toColorSpace, image::DCPProfile dcpProf, image::DCPProfile::Triple neutral) +void colorSpaceTransform(image::Image& inputImage, image::EImageColorSpace fromColorSpace, image::EImageColorSpace toColorSpace, image::DCPProfile dcpProf, image::DCPProfile::Triple neutral) { const int width = inputImage.Width(); const int tileSize = inputImage.Height(); oiio::ImageBuf inBuf = oiio::ImageBuf(oiio::ImageSpec(width, tileSize, 4, oiio::TypeDesc::FLOAT), const_cast(inputImage.data())); - outBuf = &inBuf; + oiio::ImageBuf* outBuf = &inBuf; if (fromColorSpace == image::EImageColorSpace::NO_CONVERSION) { @@ -174,8 +174,7 @@ void colorSpaceTransform(image::Image& inputImage, oiio::Imag oiio::ColorConfig colorConfig(colorConfigPath); oiio::ImageBufAlgo::colorconvert(colorspaceBuf, *outBuf, EImageColorSpace_enumToOIIOString(fromColorSpace), - EImageColorSpace_enumToOIIOString(toColorSpace), true, "", "", - &colorConfig); + EImageColorSpace_enumToOIIOString(toColorSpace), true, "", "", &colorConfig); outBuf = &colorspaceBuf; } else @@ -184,6 +183,10 @@ void colorSpaceTransform(image::Image& inputImage, oiio::Imag outBuf = &colorspaceBuf; } + oiio::ROI exportROI = outBuf->roi(); + exportROI.chbegin = 0; + exportROI.chend = inputImage.Channels(); + outBuf->get_pixels(exportROI, outBuf->pixeltype(), inputImage.data()); } int aliceVision_main(int argc, char** argv) @@ -230,17 +233,17 @@ int aliceVision_main(int argc, char** argv) const int tileHeight = inputSpec.tile_height; image::EImageColorSpace fromColorSpace = image::EImageColorSpace_stringToEnum(inputSpec.get_string_attribute("AliceVision:ColorSpace", "linear")); - int tmpWidth, tmpHeight; // same as tileWidth and tileHeight ???? - std::map imageMetadata = image::getMapFromMetadata(image::readImageMetadata(inputPanoramaPath, tmpWidth, tmpHeight)); - if (tileWidth != tileHeight) { ALICEVISION_LOG_ERROR("non square tiles !"); return EXIT_FAILURE; } + int tmpWidth, tmpHeight; + std::map imageMetadata = image::getMapFromMetadata(image::readImageMetadata(inputPanoramaPath, tmpWidth, tmpHeight)); + image::DCPProfile dcpProf; - image::DCPProfile::Triple neutral; + image::DCPProfile::Triple neutral = { 1.0,1.0,1.0 }; if (fromColorSpace == image::EImageColorSpace::NO_CONVERSION) { // load DCP metadata @@ -270,6 +273,8 @@ int aliceVision_main(int argc, char** argv) outputSpec.tile_height = 0; outputSpec.attribute("compression", "zip"); outputSpec.extra_attribs.remove("openexr:lineOrder"); + outputSpec.attribute("AliceVision:ColorSpace",image::EImageColorSpace_enumToString(outputColorSpace)); + if (!panoramaOutput->open(outputPanoramaPath, outputSpec)) { ALICEVISION_LOG_ERROR("Impossible to write to destination path"); @@ -284,7 +289,6 @@ int aliceVision_main(int argc, char** argv) const int countHeight = std::ceil(double(height) / double(tileSize)); const int rowSize = countWidth + 2; - if (fillHoles) { ALICEVISION_LOG_INFO("Reduce image (" << width << "x" << height << ")"); @@ -424,7 +428,6 @@ int aliceVision_main(int argc, char** argv) cs = ns; } - pyramid[pyramid.size() - 1] = subFiled; for (int level = pyramid.size() - 2; level >= 0; level--) @@ -490,10 +493,9 @@ int aliceVision_main(int argc, char** argv) final.block(0, 0, tileSize, width) = finalTile.block(tileSize, tileSize, tileSize, width); - oiio::ImageBuf* outBuf = nullptr; - colorSpaceTransform(final, outBuf, fromColorSpace, outputColorSpace, dcpProf, neutral); + colorSpaceTransform(final, fromColorSpace, outputColorSpace, dcpProf, neutral); - panoramaOutput->write_scanlines(ty * tileSize, (ty + 1) * tileSize, 0, oiio::TypeDesc::FLOAT, outBuf->localpixels()); + panoramaOutput->write_scanlines(ty * tileSize, (ty + 1) * tileSize, 0, oiio::TypeDesc::FLOAT, final.data()); } } else @@ -515,7 +517,6 @@ int aliceVision_main(int argc, char** argv) ALICEVISION_LOG_ERROR("Error reading from image"); } - int available = width - tx*tileSize; if (available < tileSize) { @@ -527,10 +528,9 @@ int aliceVision_main(int argc, char** argv) } } - oiio::ImageBuf* outBuf = nullptr; - colorSpaceTransform(final, outBuf, fromColorSpace, outputColorSpace, dcpProf, neutral); + colorSpaceTransform(final, fromColorSpace, outputColorSpace, dcpProf, neutral); - panoramaOutput->write_scanlines(ybegin, yend, 0, oiio::TypeDesc::FLOAT, outBuf->localpixels()); + panoramaOutput->write_scanlines(ybegin, yend, 0, oiio::TypeDesc::FLOAT, final.data()); } } From 84c14b70af9aacf234c2951a0fd2e6d50738bdd9 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Mon, 6 Mar 2023 14:42:41 +0100 Subject: [PATCH 11/14] [imageProcessing] dcpColorMatrixOnly by default --- src/software/utils/main_imageProcessing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/software/utils/main_imageProcessing.cpp b/src/software/utils/main_imageProcessing.cpp index 519022115e..8619ffb1ca 100644 --- a/src/software/utils/main_imageProcessing.cpp +++ b/src/software/utils/main_imageProcessing.cpp @@ -661,7 +661,7 @@ int aliceVision_main(int argc, char * argv[]) image::ERawColorInterpretation rawColorInterpretation = image::ERawColorInterpretation::LibRawNoWhiteBalancing; std::string colorProfileDatabaseDirPath = ""; bool errorOnMissingColorProfile = true; - bool useDCPColorMatrixOnly = false; + bool useDCPColorMatrixOnly = true; bool doWBAfterDemosaicing = false; std::string demosaicingAlgo = "AHD"; int highlightMode = 0; From 4f40c6d4876f6f1d610a77c9f73a9089df9e056d Mon Sep 17 00:00:00 2001 From: demoulinv Date: Tue, 7 Mar 2023 14:56:44 +0100 Subject: [PATCH 12/14] [default raw settings] Change from AHD to DHT as demosaicing algo Change from LibRawNoWhiteBalancing to DcpLinearProcessing as default raw color interpretation in imageProcessing. --- src/aliceVision/image/io.hpp | 2 +- src/software/utils/main_imageProcessing.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/aliceVision/image/io.hpp b/src/aliceVision/image/io.hpp index 37ca0a57ae..7f382c7541 100644 --- a/src/aliceVision/image/io.hpp +++ b/src/aliceVision/image/io.hpp @@ -185,7 +185,7 @@ struct ImageReadOptions ERawColorInterpretation rawColorInterpretation = ERawColorInterpretation::LibRawWhiteBalancing, const std::string& colorProfile = "", const bool useDCPColorMatrixOnly = true, const oiio::ROI& roi = oiio::ROI()) : workingColorSpace(colorSpace), rawColorInterpretation(rawColorInterpretation), colorProfileFileName(colorProfile), useDCPColorMatrixOnly(useDCPColorMatrixOnly), - doWBAfterDemosaicing(false), demosaicingAlgo("AHD"), highlightMode(0), subROI(roi) + doWBAfterDemosaicing(false), demosaicingAlgo("DHT"), highlightMode(0), subROI(roi) { } diff --git a/src/software/utils/main_imageProcessing.cpp b/src/software/utils/main_imageProcessing.cpp index 8619ffb1ca..2e0fb99701 100644 --- a/src/software/utils/main_imageProcessing.cpp +++ b/src/software/utils/main_imageProcessing.cpp @@ -658,12 +658,12 @@ int aliceVision_main(int argc, char * argv[]) image::EImageColorSpace outputColorSpace = image::EImageColorSpace::LINEAR; image::EStorageDataType storageDataType = image::EStorageDataType::Float; std::string extension; - image::ERawColorInterpretation rawColorInterpretation = image::ERawColorInterpretation::LibRawNoWhiteBalancing; + image::ERawColorInterpretation rawColorInterpretation = image::ERawColorInterpretation::DcpLinearProcessing; std::string colorProfileDatabaseDirPath = ""; bool errorOnMissingColorProfile = true; bool useDCPColorMatrixOnly = true; bool doWBAfterDemosaicing = false; - std::string demosaicingAlgo = "AHD"; + std::string demosaicingAlgo = "DHT"; int highlightMode = 0; ProcessingParams pParams; @@ -754,7 +754,7 @@ int aliceVision_main(int argc, char * argv[]) ("Output color space: " + image::EImageColorSpace_informations()).c_str()) ("rawColorInterpretation", po::value(&rawColorInterpretation)->default_value(rawColorInterpretation), - ("RAW color interpretation: " + image::ERawColorInterpretation_informations() + "\ndefault : librawnowhitebalancing").c_str()) + ("RAW color interpretation: " + image::ERawColorInterpretation_informations() + "\ndefault : DcpLinearProcessing").c_str()) ("applyDcpMetadata", po::value(&pParams.applyDcpMetadata)->default_value(pParams.applyDcpMetadata), "Apply after all processings a linear dcp profile generated from the image DCP metadata if any") @@ -774,7 +774,7 @@ int aliceVision_main(int argc, char * argv[]) ("demosaicingAlgo", po::value(&demosaicingAlgo)->default_value(demosaicingAlgo), "Demosaicing algorithm (see libRaw documentation).\n" - "Possible algos are: linear, VNG, PPG, AHD (default), DCB, AHD-Mod, AFD, VCD, Mixed, LMMSE, AMaZE, DHT, AAHD, none.") + "Possible algos are: linear, VNG, PPG, AHD, DCB, AHD-Mod, AFD, VCD, Mixed, LMMSE, AMaZE, DHT (default), AAHD, none.") ("highlightMode", po::value(&highlightMode)->default_value(highlightMode), "Highlight management (see libRaw documentation).\n" From bea1a2b2da0fd018d2a7931341ef97ef681cb072 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Wed, 8 Mar 2023 07:45:32 +0100 Subject: [PATCH 13/14] [IO] Read code cleaning --- src/aliceVision/image/io.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/aliceVision/image/io.cpp b/src/aliceVision/image/io.cpp index b6678ae491..6da0ca4e8e 100644 --- a/src/aliceVision/image/io.cpp +++ b/src/aliceVision/image/io.cpp @@ -457,10 +457,10 @@ void readImage(const std::string& path, size_t next = 1; while ((next = cam_mul.find(",", last)) != std::string::npos) { - v_mult.push_back(std::stof(cam_mul.substr(last, next - last).c_str())); + v_mult.push_back(std::stof(cam_mul.substr(last, next - last))); last = next + 1; } - v_mult.push_back(std::stof(cam_mul.substr(last, cam_mul.find("}", last) - last).c_str())); + v_mult.push_back(std::stof(cam_mul.substr(last, cam_mul.find("}", last) - last))); for (int i = 0; i < 3; i++) { @@ -493,15 +493,15 @@ void readImage(const std::string& path, else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::LibRawNoWhiteBalancing) { configSpec.attribute("raw:auto_bright", 0); // disable exposure correction - configSpec.attribute("raw:use_camera_wb", 0); // white balance correction - configSpec.attribute("raw:use_camera_matrix", 1); // do not use embeded color profile if any except for dng files + configSpec.attribute("raw:use_camera_wb", 0); // no white balance correction + configSpec.attribute("raw:use_camera_matrix", 1); // do not use embeded color profile if any, except for dng files configSpec.attribute("raw:ColorSpace", "Linear"); // use linear colorspace with sRGB primaries } else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::LibRawWhiteBalancing) { configSpec.attribute("raw:auto_bright", 0); // disable exposure correction configSpec.attribute("raw:use_camera_wb", 1); // white balance correction - configSpec.attribute("raw:use_camera_matrix", 1); // do not use embeded color profile if any except for dng files + configSpec.attribute("raw:use_camera_matrix", 1); // do not use embeded color profile if any, except for dng files configSpec.attribute("raw:ColorSpace", "Linear"); // use linear colorspace with sRGB primaries } else if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing) @@ -624,7 +624,7 @@ void readImage(const std::string& path, } int width, height; - std::map imageMetadata = getMapFromMetadata(readImageMetadata(path, width, height)); + const std::map imageMetadata = getMapFromMetadata(readImageMetadata(path, width, height)); // load DCP metadata from metadata. An error will be thrown if all required metadata are not there. dcpProf.Load(imageMetadata); From 3bb3504a34483be9bb0ba6be4e48bb7f3b455482 Mon Sep 17 00:00:00 2001 From: demoulinv Date: Wed, 8 Mar 2023 15:35:56 +0100 Subject: [PATCH 14/14] [HDRmerge & default demosaicing] Adjust output color to 'Linear' space when working color space is 'sRGB'. Set back AHD as default demosaicing algo. --- src/aliceVision/image/io.hpp | 2 +- src/software/pipeline/main_LdrToHdrMerge.cpp | 10 +++++++--- src/software/utils/main_imageProcessing.cpp | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/aliceVision/image/io.hpp b/src/aliceVision/image/io.hpp index 7f382c7541..37ca0a57ae 100644 --- a/src/aliceVision/image/io.hpp +++ b/src/aliceVision/image/io.hpp @@ -185,7 +185,7 @@ struct ImageReadOptions ERawColorInterpretation rawColorInterpretation = ERawColorInterpretation::LibRawWhiteBalancing, const std::string& colorProfile = "", const bool useDCPColorMatrixOnly = true, const oiio::ROI& roi = oiio::ROI()) : workingColorSpace(colorSpace), rawColorInterpretation(rawColorInterpretation), colorProfileFileName(colorProfile), useDCPColorMatrixOnly(useDCPColorMatrixOnly), - doWBAfterDemosaicing(false), demosaicingAlgo("DHT"), highlightMode(0), subROI(roi) + doWBAfterDemosaicing(false), demosaicingAlgo("AHD"), highlightMode(0), subROI(roi) { } diff --git a/src/software/pipeline/main_LdrToHdrMerge.cpp b/src/software/pipeline/main_LdrToHdrMerge.cpp index cf5812f67a..04a53a52b0 100644 --- a/src/software/pipeline/main_LdrToHdrMerge.cpp +++ b/src/software/pipeline/main_LdrToHdrMerge.cpp @@ -348,11 +348,15 @@ int aliceVision_main(int argc, char** argv) targetMetadata.add_or_replace(oiio::ParamValue(meta.first, meta.second)); } } - targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", image::EImageColorSpace_enumToString(workingColorSpace))); + + // Fusion always produces linear image. sRGB is the only non linear color space that must be changed to linear (sRGB linear). + image::EImageColorSpace mergedColorSpace = (workingColorSpace == image::EImageColorSpace::SRGB) ? image::EImageColorSpace::LINEAR : workingColorSpace; + + targetMetadata.add_or_replace(oiio::ParamValue("AliceVision:ColorSpace", image::EImageColorSpace_enumToString(mergedColorSpace))); image::ImageWriteOptions writeOptions; - writeOptions.fromColorSpace(workingColorSpace); - writeOptions.toColorSpace(workingColorSpace); + writeOptions.fromColorSpace(mergedColorSpace); + writeOptions.toColorSpace(mergedColorSpace); writeOptions.storageDataType(storageDataType); image::writeImage(hdrImagePath, HDRimage, writeOptions, targetMetadata); diff --git a/src/software/utils/main_imageProcessing.cpp b/src/software/utils/main_imageProcessing.cpp index 2e0fb99701..99f2c06c11 100644 --- a/src/software/utils/main_imageProcessing.cpp +++ b/src/software/utils/main_imageProcessing.cpp @@ -663,7 +663,7 @@ int aliceVision_main(int argc, char * argv[]) bool errorOnMissingColorProfile = true; bool useDCPColorMatrixOnly = true; bool doWBAfterDemosaicing = false; - std::string demosaicingAlgo = "DHT"; + std::string demosaicingAlgo = "AHD"; int highlightMode = 0; ProcessingParams pParams; @@ -774,7 +774,7 @@ int aliceVision_main(int argc, char * argv[]) ("demosaicingAlgo", po::value(&demosaicingAlgo)->default_value(demosaicingAlgo), "Demosaicing algorithm (see libRaw documentation).\n" - "Possible algos are: linear, VNG, PPG, AHD, DCB, AHD-Mod, AFD, VCD, Mixed, LMMSE, AMaZE, DHT (default), AAHD, none.") + "Possible algos are: linear, VNG, PPG, AHD (default), DCB, AHD-Mod, AFD, VCD, Mixed, LMMSE, AMaZE, DHT, AAHD, none.") ("highlightMode", po::value(&highlightMode)->default_value(highlightMode), "Highlight management (see libRaw documentation).\n"