Skip to content

Commit

Permalink
Merge pull request #1368 from alicevision/dev/rawAdvancedProcessing
Browse files Browse the repository at this point in the history
RAW advanced processing
  • Loading branch information
fabiencastan authored Mar 9, 2023
2 parents 18a6568 + 3bb3504 commit f99c95d
Show file tree
Hide file tree
Showing 7 changed files with 400 additions and 67 deletions.
101 changes: 89 additions & 12 deletions src/aliceVision/image/dcp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <aliceVision/numeric/numeric.hpp>
#include <aliceVision/system/Logger.hpp>
#include <aliceVision/stl/mapUtils.hpp>

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
Expand Down Expand Up @@ -1294,6 +1295,63 @@ void DCPProfile::Load(const std::string& filename)
igammatab_srgb.Set(igammatab_srgb_data);
}

void DCPProfile::Load(const std::map<std::string, std::string>& 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<std::string> 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
Expand Down Expand Up @@ -2106,27 +2164,28 @@ 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);

ALICEVISION_LOG_INFO("Estimated illuminant (cct; tint) : (" << cct << "; " << tint << ")");

Matrix neutral = IdentityMatrix;

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)
Expand All @@ -2137,11 +2196,22 @@ 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
const Matrix cat = getChromaticAdaptationMatrix(getXyzFromChromaticityCoordinates(x, y), getXyzFromTemperature(D50_cct, D50_tint));

cameraToXyzD50 = matMult(cat, cameraToXyz);
}
else if ((info.has_forward_matrix_1) && (info.has_forward_matrix_2))
Expand All @@ -2152,6 +2222,9 @@ DCPProfile::Matrix DCPProfile::getCameraToACES2065Matrix(const Triple& asShotNeu
{
cameraToXyzD50 = matMult(forward_matrix_1, neutral);
}

ALICEVISION_LOG_INFO("cameraToXyzD50Matrix : " << cameraToXyzD50);

Matrix cameraToACES2065 = matMult(xyzD50ToACES2065Matrix, cameraToXyzD50);

return cameraToACES2065;
Expand Down Expand Up @@ -2268,9 +2341,11 @@ void DCPProfile::setMatricesFromStrings(const std::string& type, std::vector<std
setMatrices(type, v_Mat);
}

void DCPProfile::applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const bool sourceIsRaw) const
void DCPProfile::applyLinear(OIIO::ImageBuf& 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.spec().height; ++i)
Expand All @@ -2292,9 +2367,11 @@ void DCPProfile::applyLinear(OIIO::ImageBuf& image, const Triple& neutral, const
}
}

void DCPProfile::applyLinear(Image<image::RGBAfColor>& image, const Triple& neutral, const bool sourceIsRaw) const
void DCPProfile::applyLinear(Image<image::RGBAfColor>& 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)
Expand Down
14 changes: 11 additions & 3 deletions src/aliceVision/image/dcp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string, std::string>& metadata);

/**
* @brief getMatrices gets some matrices contained in the profile
* param[in] type The matrices to get, "color" or "forward"
Expand Down Expand Up @@ -201,16 +207,18 @@ 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;
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
* 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::RGBAfColor>& image, const Triple& neutral, const bool sourceIsRaw = false) const;
void applyLinear(Image<image::RGBAfColor>& 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
Expand Down Expand Up @@ -270,7 +278,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
Expand Down
Loading

0 comments on commit f99c95d

Please sign in to comment.