From 3cb2acf3741778f78f2df121afeb579fac0aa729 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Thu, 8 Aug 2024 06:58:28 +1200 Subject: [PATCH] raw: expose additional white balancing hints (#4360) The main purpose of this change is to make it possible to use OIIO for reading raw files in rawtoaces instead of calling LibRaw directly. There are the changes: - add the missing hints needed to implement all combinations of white-balancing methods and matrix methods provided by rawtoaces. - add the DNG-specific attributes The change adds this functionality: - new "raw:user_black" hint to override the default black point - new "raw:use_auto_wb" hint to force LibRaw to white balance by averaging over the whole image. - new "raw:grey_box" hint to make LibRaw to white balance by averaging over the given rectange. - new "raw:dng:XXX" attributes added to the output ImageBuf if the input image is a DNG file. The attributes consist of 2 sets of [calibration illuminant; calibration matrix, XYZ to camera RGB matrix]. Note, the current DNG standard supports up to 3 calibration illuminants, but both LibRaw and rawtoaces only use 2 currently. I have manually tested all permutations of white-balancing modes and matrix methods which are currently supported by raw to aces. The images match up to a rounding error. The current unit tests pass, but they only seem to use the default conversion settings. We may want to extend those. I'm not clear on how to do that, there are multiple reference images for different versions of LibRaw, not sure if I will have to re-generate all of them. I intend to make more changes to the raw plugin soon, may come back to updating tests during/after that. There are currently no tests using DNG files, so the new DNG-specific attributes are not covered. The code relying on those in rawtoaces works fine. I have also updated the documentation to add the new hints, however, I haven't been able to build the documentation. Signed-off-by: Anton Dukhovnikov --- src/doc/builtinplugins.rst | 25 +++++++++++- src/raw.imageio/rawinput.cpp | 74 ++++++++++++++++++++++++++++-------- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/doc/builtinplugins.rst b/src/doc/builtinplugins.rst index 7fa37e62a7..5743de5890 100644 --- a/src/doc/builtinplugins.rst +++ b/src/doc/builtinplugins.rst @@ -2066,7 +2066,23 @@ options are supported: - If nonzero, will use libraw's exposure correction. (Default: 0) * - ``raw:use_camera_wb`` - int - - If 1, use libraw's camera white balance adjustment. (Default: 1) + - If 1, use libraw's camera white balance adjustment. Takes precedence + over ``raw:use_auto_wb``, ``raw:greybox``, ``raw:user_mul``. + (Default: 1) + * - ``raw:use_auto_wb`` + - int + - If 1, white balance automatically by averaging over the entire image. + Only applies if ``raw:use_camera_wb`` is not equal to 0. Takes + precedence over ``raw:greybox``, ``raw:user_mul``. + (Default: 0) + * - ``raw:greybox`` + - int[4] + - White balance by averaging over the given box. The four values are the + X and Y coordinate of the top-left corner, the width and the height. + Only applies if the size is non-zero, and ``raw:use_camera_wb`` is not + equal to 0, ``raw:use_auto_wb`` is not equal to 0. Takes + precedence over ``raw:user_mul``. + (Default: 0, 0, 0, 0; meaning no correction.) * - ``raw:use_camera_matrix`` - int - Whether to use the embedded color profile, if it's present: 0 = @@ -2074,6 +2090,10 @@ options are supported: * - ``raw:adjust_maximum_thr`` - float - If nonzero, auto-adjusting maximum value. (Default:0.0) + * - ``raw:user_black`` + - int + - If not negative, sets the camera minimum value that will be normalized to + appear 0. (Default: -1) * - ``raw:user_sat`` - int - If nonzero, sets the camera maximum value that will be normalized to @@ -2090,7 +2110,8 @@ options are supported: * - ``raw:user_mul`` - float[4] - Sets user white balance coefficients. Only applies if ``raw:use_camera_wb`` - is not equal to 0. + is not equal to 0, ``raw:use_auto_wb`` is not equal to 0, and the + ``raw:greybox`` box is zero size. * - ``raw:ColorSpace`` - string - Which color primaries to use for the returned pixel values: ``raw``, diff --git a/src/raw.imageio/rawinput.cpp b/src/raw.imageio/rawinput.cpp index 2b4f715d7a..dd75df798f 100644 --- a/src/raw.imageio/rawinput.cpp +++ b/src/raw.imageio/rawinput.cpp @@ -459,6 +459,9 @@ RawInput::open_raw(bool unpack, const std::string& name, // Turn off maximum threshold value (unless set to non-zero) m_processor->imgdata.params.adjust_maximum_thr = config.get_float_attribute("raw:adjust_maximum_thr", 0.0f); + // Set camera minimum value if "raw:user_black" is not negative + m_processor->imgdata.params.user_black + = config.get_int_attribute("raw:user_black", -1); // Set camera maximum value if "raw:user_sat" is not 0 m_processor->imgdata.params.user_sat = config.get_int_attribute("raw:user_sat", 0); @@ -502,21 +505,34 @@ RawInput::open_raw(bool unpack, const std::string& name, params.user_mul[2] = norm[2]; params.user_mul[3] = norm[3]; } else { - // Set user white balance coefficients. - // Only has effect if "raw:use_camera_wb" is equal to 0, - // i.e. we are not using the camera white balance - auto p = config.find_attribute("raw:user_mul"); - if (p && p->type() == TypeDesc(TypeDesc::FLOAT, 4)) { - m_processor->imgdata.params.user_mul[0] = p->get(0); - m_processor->imgdata.params.user_mul[1] = p->get(1); - m_processor->imgdata.params.user_mul[2] = p->get(2); - m_processor->imgdata.params.user_mul[3] = p->get(3); - } - if (p && p->type() == TypeDesc(TypeDesc::DOUBLE, 4)) { - m_processor->imgdata.params.user_mul[0] = p->get(0); - m_processor->imgdata.params.user_mul[1] = p->get(1); - m_processor->imgdata.params.user_mul[2] = p->get(2); - m_processor->imgdata.params.user_mul[3] = p->get(3); + if (config.get_int_attribute("raw:use_auto_wb", 0) == 1) { + m_processor->imgdata.params.use_auto_wb = 1; + } else { + auto p = config.find_attribute("raw:greybox"); + if (p && p->type() == TypeDesc(TypeDesc::INT, 4)) { + // p->get() didn't work for me here + m_processor->imgdata.params.greybox[0] = p->get_int_indexed(0); + m_processor->imgdata.params.greybox[1] = p->get_int_indexed(1); + m_processor->imgdata.params.greybox[2] = p->get_int_indexed(2); + m_processor->imgdata.params.greybox[3] = p->get_int_indexed(3); + } else { + // Set user white balance coefficients. + // Only has effect if "raw:use_camera_wb" is equal to 0, + // i.e. we are not using the camera white balance + auto p = config.find_attribute("raw:user_mul"); + if (p && p->type() == TypeDesc(TypeDesc::FLOAT, 4)) { + m_processor->imgdata.params.user_mul[0] = p->get(0); + m_processor->imgdata.params.user_mul[1] = p->get(1); + m_processor->imgdata.params.user_mul[2] = p->get(2); + m_processor->imgdata.params.user_mul[3] = p->get(3); + } + if (p && p->type() == TypeDesc(TypeDesc::DOUBLE, 4)) { + m_processor->imgdata.params.user_mul[0] = p->get(0); + m_processor->imgdata.params.user_mul[1] = p->get(1); + m_processor->imgdata.params.user_mul[2] = p->get(2); + m_processor->imgdata.params.user_mul[3] = p->get(3); + } + } } } @@ -1319,6 +1335,34 @@ RawInput::get_colorinfo() cspan(&(m_processor->imgdata.color.cam_xyz[0][0]), &(m_processor->imgdata.color.cam_xyz[3][3])), false, 0.f); + + if (m_processor->imgdata.idata.dng_version) { + add("raw", "dng:version", m_processor->imgdata.idata.dng_version); + + auto const& c = m_processor->imgdata.rawdata.color; + +#if LIBRAW_VERSION >= LIBRAW_MAKE_VERSION(0, 20, 0) + add("raw", "dng:baseline_exposure", c.dng_levels.baseline_exposure); +#else + add("raw", "dng:baseline_exposure", c.baseline_exposure); +#endif + + for (int i = 0; i < 2; i++) { + std::string index = std::to_string(i + 1); + add("raw", "dng:calibration_illuminant" + index, + c.dng_color[i].illuminant); + + add("raw", "dng:color_matrix" + index, + cspan(&(c.dng_color[i].colormatrix[0][0]), + &(c.dng_color[i].colormatrix[3][3])), + false, 0.f); + + add("raw", "dng:camera_calibration" + index, + cspan(&(c.dng_color[i].calibration[0][0]), + &(c.dng_color[i].calibration[3][4])), + false, 0.f); + } + } }