Skip to content

Commit

Permalink
Merge pull request #932 from alicevision/dev/whiteBalance
Browse files Browse the repository at this point in the history
Dev/white balance
  • Loading branch information
fabiencastan authored Dec 1, 2020
2 parents 2eccd22 + 150dfb5 commit 3ed4dbe
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 37 deletions.
8 changes: 6 additions & 2 deletions src/aliceVision/hdr/sampling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ void square(image::Image<image::RGBfColor> & dest, const Eigen::Matrix<image::RG
}
}

bool Sampling::extractSamplesFromImages(std::vector<ImageSample>& out_samples, const std::vector<std::string> & imagePaths, const std::vector<float>& times, const size_t imageWidth, const size_t imageHeight, const size_t channelQuantization, const EImageColorSpace & colorspace, const Sampling::Params params)
bool Sampling::extractSamplesFromImages(std::vector<ImageSample>& out_samples, const std::vector<std::string> & imagePaths, const std::vector<float>& times, const size_t imageWidth, const size_t imageHeight, const size_t channelQuantization, const EImageColorSpace & colorspace, bool applyWhiteBalance, const Sampling::Params params)
{
const int radiusp1 = params.radius + 1;
const int diameter = (params.radius * 2) + 1;
Expand All @@ -169,8 +169,12 @@ bool Sampling::extractSamplesFromImages(std::vector<ImageSample>& out_samples, c
{
const float exposure = times[idBracket];

image::ImageReadOptions options;
options.outputColorSpace = colorspace;
options.applyWhiteBalance = applyWhiteBalance;

// Load image
readImage(imagePaths[idBracket], img, colorspace);
readImage(imagePaths[idBracket], img, options);

if(img.Width() != imageWidth || img.Height() != imageHeight)
{
Expand Down
2 changes: 1 addition & 1 deletion src/aliceVision/hdr/sampling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class Sampling
void filter(size_t maxTotalPoints);
void extractUsefulSamples(std::vector<ImageSample> & out_samples, const std::vector<ImageSample> & samples, int imageIndex) const;

static bool extractSamplesFromImages(std::vector<ImageSample>& out_samples, const std::vector<std::string> & imagePaths, const std::vector<float>& times, const size_t imageWidth, const size_t imageHeight, const size_t channelQuantization, const image::EImageColorSpace & colorspace, const Params params);
static bool extractSamplesFromImages(std::vector<ImageSample>& out_samples, const std::vector<std::string> & imagePaths, const std::vector<float>& times, const size_t imageWidth, const size_t imageHeight, const size_t channelQuantization, const image::EImageColorSpace & colorspace, bool applyWhiteBalance, const Params params);

private:
MapSampleRefList _positions;
Expand Down
46 changes: 24 additions & 22 deletions src/aliceVision/image/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,22 +246,24 @@ void readImage(const std::string& path,
oiio::TypeDesc format,
int nchannels,
Image<T>& image,
EImageColorSpace imageColorSpace)
const ImageReadOptions & imageReadOptions)
{
// check requested channels number
assert(nchannels == 1 || nchannels >= 3);

oiio::ImageSpec configSpec;

// libRAW configuration
configSpec.attribute("raw:auto_bright", 0); // don't want exposure correction
configSpec.attribute("raw:use_camera_wb", 1); // want white balance correction
configSpec.attribute("raw:use_camera_matrix", 3); // want to use embeded color profile
// See https://openimageio.readthedocs.io/en/master/builtinplugins.html#raw-digital-camera-files
configSpec.attribute("raw:auto_bright", 0); // disable exposure correction
configSpec.attribute("raw:use_camera_wb", (imageReadOptions.applyWhiteBalance?1:0)); // white balance correction
// use_camera_matrix: Whether to use the embedded color profile, if it is present: 0=never, 1 (default)=only for DNG files, 3=always
configSpec.attribute("raw:use_camera_matrix", 3); // use embeded color profile
#if OIIO_VERSION <= (10000 * 2 + 100 * 0 + 8) // OIIO_VERSION <= 2.0.8
// In these previous versions of oiio, there was no Linear option
configSpec.attribute("raw:ColorSpace", "sRGB"); // want colorspace sRGB
// In old versions of oiio, there was no Linear option
configSpec.attribute("raw:ColorSpace", "sRGB"); // use colorspace sRGB
#else
configSpec.attribute("raw:ColorSpace", "Linear"); // want linear colorspace with sRGB primaries
configSpec.attribute("raw:ColorSpace", "Linear"); // use linear colorspace with sRGB primaries
#endif

oiio::ImageBuf inBuf(path, 0, 0, NULL, &configSpec);
Expand All @@ -276,21 +278,21 @@ void readImage(const std::string& path,
throw std::runtime_error("Can't load channels of image file '" + path + "'.");

// color conversion
if(imageColorSpace == EImageColorSpace::AUTO)
if(imageReadOptions.outputColorSpace == EImageColorSpace::AUTO)
throw std::runtime_error("You must specify a requested color space for image file '" + path + "'.");

const std::string& colorSpace = inBuf.spec().get_string_attribute("oiio:ColorSpace", "sRGB"); // default image color space is sRGB
ALICEVISION_LOG_TRACE("Read image " << path << " (encoded in " << colorSpace << " colorspace).");

if(imageColorSpace == EImageColorSpace::SRGB) // color conversion to sRGB
if(imageReadOptions.outputColorSpace == EImageColorSpace::SRGB) // color conversion to sRGB
{
if (colorSpace != "sRGB")
{
oiio::ImageBufAlgo::colorconvert(inBuf, inBuf, colorSpace, "sRGB");
ALICEVISION_LOG_TRACE("Convert image " << path << " from " << colorSpace << " to sRGB colorspace");
}
}
else if(imageColorSpace == EImageColorSpace::LINEAR) // color conversion to linear
else if(imageReadOptions.outputColorSpace == EImageColorSpace::LINEAR) // color conversion to linear
{
if (colorSpace != "Linear")
{
Expand Down Expand Up @@ -453,34 +455,34 @@ void writeImage(const std::string& path,
fs::rename(tmpPath, path);
}

void readImage(const std::string& path, Image<float>& image, EImageColorSpace imageColorSpace)
void readImage(const std::string& path, Image<float>& image, const ImageReadOptions & imageReadOptions)
{
readImage(path, oiio::TypeDesc::FLOAT, 1, image, imageColorSpace);
readImage(path, oiio::TypeDesc::FLOAT, 1, image, imageReadOptions);
}

void readImage(const std::string& path, Image<unsigned char>& image, EImageColorSpace imageColorSpace)
void readImage(const std::string& path, Image<unsigned char>& image, const ImageReadOptions & imageReadOptions)
{
readImage(path, oiio::TypeDesc::UINT8, 1, image, imageColorSpace);
readImage(path, oiio::TypeDesc::UINT8, 1, image, imageReadOptions);
}

void readImage(const std::string& path, Image<RGBAfColor>& image, EImageColorSpace imageColorSpace)
void readImage(const std::string& path, Image<RGBAfColor>& image, const ImageReadOptions & imageReadOptions)
{
readImage(path, oiio::TypeDesc::FLOAT, 4, image, imageColorSpace);
readImage(path, oiio::TypeDesc::FLOAT, 4, image, imageReadOptions);
}

void readImage(const std::string& path, Image<RGBAColor>& image, EImageColorSpace imageColorSpace)
void readImage(const std::string& path, Image<RGBAColor>& image, const ImageReadOptions & imageReadOptions)
{
readImage(path, oiio::TypeDesc::UINT8, 4, image, imageColorSpace);
readImage(path, oiio::TypeDesc::UINT8, 4, image, imageReadOptions);
}

void readImage(const std::string& path, Image<RGBfColor>& image, EImageColorSpace imageColorSpace)
void readImage(const std::string& path, Image<RGBfColor>& image, const ImageReadOptions & imageReadOptions)
{
readImage(path, oiio::TypeDesc::FLOAT, 3, image, imageColorSpace);
readImage(path, oiio::TypeDesc::FLOAT, 3, image, imageReadOptions);
}

void readImage(const std::string& path, Image<RGBColor>& image, EImageColorSpace imageColorSpace)
void readImage(const std::string& path, Image<RGBColor>& image, const ImageReadOptions & imageReadOptions)
{
readImage(path, oiio::TypeDesc::UINT8, 3, image, imageColorSpace);
readImage(path, oiio::TypeDesc::UINT8, 3, image, imageReadOptions);
}

void writeImage(const std::string& path, const Image<unsigned char>& image, EImageColorSpace imageColorSpace, const oiio::ParamValueList& metadata)
Expand Down
26 changes: 20 additions & 6 deletions src/aliceVision/image/io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ enum class EImageFileType
EXR
};

/**
* @brief aggregate for multiple image reading options
*/
struct ImageReadOptions
{
ImageReadOptions(EImageColorSpace colorSpace = EImageColorSpace::AUTO, bool useWhiteBalance = true) :
outputColorSpace(colorSpace), applyWhiteBalance(useWhiteBalance)
{
}

EImageColorSpace outputColorSpace;
bool applyWhiteBalance;
};


/**
* @brief get informations about each image file type
Expand Down Expand Up @@ -161,12 +175,12 @@ void getBufferFromImage(Image<RGBColor>& image, oiio::ImageBuf& buffer);
* @param[out] image The output image buffer
* @param[in] image color space
*/
void readImage(const std::string& path, Image<float>& image, EImageColorSpace imageColorSpace);
void readImage(const std::string& path, Image<unsigned char>& image, EImageColorSpace imageColorSpace);
void readImage(const std::string& path, Image<RGBAfColor>& image, EImageColorSpace imageColorSpace);
void readImage(const std::string& path, Image<RGBAColor>& image, EImageColorSpace imageColorSpace);
void readImage(const std::string& path, Image<RGBfColor>& image, EImageColorSpace imageColorSpace);
void readImage(const std::string& path, Image<RGBColor>& image, EImageColorSpace imageColorSpace);
void readImage(const std::string& path, Image<float>& image, const ImageReadOptions & imageReadOptions);
void readImage(const std::string& path, Image<unsigned char>& image, const ImageReadOptions & imageReadOptions);
void readImage(const std::string& path, Image<RGBAfColor>& image, const ImageReadOptions & imageReadOptions);
void readImage(const std::string& path, Image<RGBAColor>& image, const ImageReadOptions & imageReadOptions);
void readImage(const std::string& path, Image<RGBfColor>& image, const ImageReadOptions & imageReadOptions);
void readImage(const std::string& path, Image<RGBColor>& image, const ImageReadOptions & imageReadOptions);

/**
* @brief write an image with a given path and buffer
Expand Down
12 changes: 11 additions & 1 deletion src/aliceVision/sfmData/View.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,16 @@ class View
return static_cast<EEXIFOrientation>(orientation);
}

const bool getApplyWhiteBalance() const
{
if (getIntMetadata({"AliceVision:useWhiteBalance"}) == 0)
{
return false;
}

return true;
}

const bool hasMetadataDateTimeOriginal() const
{
return hasMetadata(
Expand Down Expand Up @@ -509,7 +519,7 @@ class View
*/
void addMetadata(const std::string& key, const std::string& value)
{
_metadata.emplace(key, value);
_metadata[key] = value;
}

private:
Expand Down
6 changes: 5 additions & 1 deletion src/software/pipeline/main_LdrToHdrMerge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,11 @@ int aliceVision_main(int argc, char** argv)
{
const std::string filepath = group[i]->getImagePath();
ALICEVISION_LOG_INFO("Load " << filepath);
image::readImage(filepath, images[i], image::EImageColorSpace::SRGB);

image::ImageReadOptions options;
options.outputColorSpace = image::EImageColorSpace::SRGB;
options.applyWhiteBalance = group[i]->getApplyWhiteBalance();
image::readImage(filepath, images[i], options);

exposures[i] = group[i]->getCameraExposureSetting(/*targetView->getMetadataISO(), targetView->getMetadataFNumber()*/);
}
Expand Down
6 changes: 5 additions & 1 deletion src/software/pipeline/main_LdrToHdrSampling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,19 @@ int aliceVision_main(int argc, char** argv)
std::vector<std::string> paths;
std::vector<float> exposures;

bool applyWhiteBalance = true;

for (auto & v : group)
{
paths.push_back(v->getImagePath());
exposures.push_back(v->getCameraExposureSetting());

applyWhiteBalance = applyWhiteBalance && v->getApplyWhiteBalance();
}

ALICEVISION_LOG_INFO("Extracting samples from group " << groupIdx);
std::vector<hdr::ImageSample> out_samples;
const bool res = hdr::Sampling::extractSamplesFromImages(out_samples, paths, exposures, width, height, channelQuantization, image::EImageColorSpace::SRGB, params);
const bool res = hdr::Sampling::extractSamplesFromImages(out_samples, paths, exposures, width, height, channelQuantization, image::EImageColorSpace::SRGB, applyWhiteBalance, params);
if (!res)
{
ALICEVISION_LOG_ERROR("Error while extracting samples from group " << groupIdx);
Expand Down
13 changes: 12 additions & 1 deletion src/software/pipeline/main_cameraInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ int aliceVision_main(int argc, char **argv)
std::string outputFilePath;

// user optional parameters

std::string defaultIntrinsicKMatrix;
std::string defaultCameraModelName;
std::string allowedCameraModelsStr = "pinhole,radial1,radial3,brown,fisheye4,fisheye1";
Expand All @@ -193,6 +192,7 @@ int aliceVision_main(int argc, char **argv)
std::string viewIdRegex = ".*?(\\d+)";

bool allowSingleView = false;
bool useInternalWhiteBalance = true;

po::options_description allParams("AliceVision cameraInit");

Expand Down Expand Up @@ -231,6 +231,8 @@ int aliceVision_main(int argc, char **argv)
" * " + EViewIdMethod_enumToString(EViewIdMethod::FILENAME) + ": Generate viewId from file names using regex.") .c_str())
("viewIdRegex", po::value<std::string>(&viewIdRegex)->default_value(viewIdRegex),
"Regex used to catch number used as viewId in filename.")
("useInternalWhiteBalance", po::value<bool>(&useInternalWhiteBalance)->default_value(useInternalWhiteBalance),
"Apply the white balance included in the image metadata (Only for raw images)")
("allowSingleView", po::value<bool>(&allowSingleView)->default_value(allowSingleView),
"Allow the program to process a single view.\n"
"Warning: if a single view is process, the output file can't be use in many other programs.");
Expand Down Expand Up @@ -773,6 +775,15 @@ int aliceVision_main(int argc, char **argv)
<< "Check your input images metadata (brand, model, focal length, ...), more should be set and correct." << std::endl);
return EXIT_FAILURE;
}

// Add the white balance option to the image metadata
for (auto vitem : sfmData.getViews())
{
if (vitem.second)
{
vitem.second->addMetadata("AliceVision:useWhiteBalance", (useInternalWhiteBalance)?"1":"0");
}
}

// store SfMData views & intrinsic data
if(!Save(sfmData, outputFilePath, ESfMData(VIEWS|INTRINSICS|EXTRINSICS)))
Expand Down
8 changes: 7 additions & 1 deletion src/software/pipeline/main_panoramaPrepareImages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,13 @@ int aliceVision_main(int argc, char* argv[])

// Read input file
image::Image<image::RGBfColor> originalImage;
image::readImage(v.second->getImagePath(), originalImage, image::EImageColorSpace::LINEAR);

image::ImageReadOptions options;
options.outputColorSpace = image::EImageColorSpace::LINEAR;
options.applyWhiteBalance = v.second->getApplyWhiteBalance();


image::readImage(v.second->getImagePath(), originalImage, options);
oiio::ImageBuf bufInput(
oiio::ImageSpec(originalImage.Width(), originalImage.Height(), 3, oiio::TypeDesc::FLOAT),
originalImage.data());
Expand Down
7 changes: 6 additions & 1 deletion src/software/utils/main_imageProcessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,9 +750,14 @@ int aliceVision_main(int argc, char * argv[])

ALICEVISION_LOG_INFO(++i << "/" << size << " - Process view '" << viewId << "'.");


image::ImageReadOptions options;
options.outputColorSpace = image::EImageColorSpace::LINEAR;
options.applyWhiteBalance = view.getApplyWhiteBalance();

// Read original image
image::Image<image::RGBAfColor> image;
image::readImage(viewPath, image, image::EImageColorSpace::LINEAR);
image::readImage(viewPath, image, options);

// If exposureCompensation is needed for sfmData files
if (pParams.exposureCompensation)
Expand Down

0 comments on commit 3ed4dbe

Please sign in to comment.