Skip to content

Commit

Permalink
Panorama: Expose image storageDataType on multiple nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
fabiencastan committed Sep 11, 2020
1 parent 74b43ef commit cb2d65e
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 37 deletions.
92 changes: 86 additions & 6 deletions src/aliceVision/image/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ EImageFileType EImageFileType_stringToEnum(const std::string& imageFileType)
if(type == "tif" || type == "tiff") return EImageFileType::TIFF;
if(type == "exr") return EImageFileType::EXR;

throw std::out_of_range("Invalid image file type : " + imageFileType);
throw std::out_of_range("Invalid image file type: " + imageFileType);
}

std::string EImageFileType_enumToString(const EImageFileType imageFileType)
Expand Down Expand Up @@ -101,6 +101,53 @@ bool isSupported(const std::string& ext)
return (std::find(start, end, boost::to_lower_copy(ext)) != end);
}


std::string EStorageDataType_informations()
{
return EStorageDataType_enumToString(EStorageDataType::Float) + ", " +
EStorageDataType_enumToString(EStorageDataType::Half) + ", " +
EStorageDataType_enumToString(EStorageDataType::HalfFinite) + ", " +
EStorageDataType_enumToString(EStorageDataType::Auto);
}

EStorageDataType EStorageDataType_stringToEnum(const std::string& dataType)
{
std::string type = dataType;
std::transform(type.begin(), type.end(), type.begin(), ::tolower); //tolower

if (type == "Float") return EStorageDataType::Float;
if (type == "Half") return EStorageDataType::Half;
if (type == "HalfFinite") return EStorageDataType::HalfFinite;
if (type == "Auto") return EStorageDataType::Auto;

throw std::out_of_range("Invalid EStorageDataType: " + dataType);
}

std::string EStorageDataType_enumToString(const EStorageDataType dataType)
{
switch (dataType)
{
case EStorageDataType::Float: return "Float";
case EStorageDataType::Half: return "Half";
case EStorageDataType::HalfFinite: return "HalfFinite";
case EStorageDataType::Auto: return "Auto";
}
throw std::out_of_range("Invalid EStorageDataType enum");
}

std::ostream& operator<<(std::ostream& os, EStorageDataType dataType)
{
return os << EStorageDataType_enumToString(dataType);
}

std::istream& operator>>(std::istream& in, EStorageDataType& dataType)
{
std::string token;
in >> token;
dataType = EStorageDataType_stringToEnum(token);
return in;
}

// Warning: type conversion problems from string to param value, we may lose some metadata with string maps
oiio::ParamValueList getMetadataFromMap(const std::map<std::string, std::string>& metadataMap)
{
Expand Down Expand Up @@ -280,7 +327,7 @@ void readImage(const std::string& path,

// compute luminance via a weighted sum of R,G,B
// (assuming Rec709 primaries and a linear scale)
const float weights[3] = {.2126, .7152, .0722};
const float weights[3] = {.2126f, .7152f, .0722f};
oiio::ImageBuf grayscaleBuf;
oiio::ImageBufAlgo::channel_sum(grayscaleBuf, inBuf, weights, convertionROI);
inBuf.copy(grayscaleBuf);
Expand Down Expand Up @@ -324,6 +371,19 @@ void readImage(const std::string& path,
}
}

bool containsHalfFloatOverflow(const oiio::ImageBuf& image)
{
oiio::ImageBufAlgo::PixelStats stats;
oiio::ImageBufAlgo::computePixelStats(stats, image);

for(auto maxValue: stats.max)
{
if(maxValue > HALF_MAX)
return true;
}
return false;
}

template<typename T>
void writeImage(const std::string& path,
oiio::TypeDesc typeDesc,
Expand Down Expand Up @@ -368,11 +428,31 @@ void writeImage(const std::string& path,
oiio::ImageBuf formatBuf; // buffer for image format modification
if(isEXR)
{
int useFullFloat = imageSpec.get_int_attribute("AliceVision:useFullFloat", 0);
EStorageDataType storageDataType = EStorageDataType_stringToEnum(imageSpec.get_string_attribute("AliceVision:storageDataType", EStorageDataType_enumToString(EStorageDataType::HalfFinite)));

if (storageDataType == EStorageDataType::Auto)
{
if (containsHalfFloatOverflow(*outBuf))
{
storageDataType = EStorageDataType::Float;
}
else
{
storageDataType = EStorageDataType::Half;
}
}

if (!useFullFloat) {
formatBuf.copy(*outBuf, oiio::TypeDesc::HALF); // override format, use half instead of float
outBuf = &formatBuf;
if (storageDataType == EStorageDataType::HalfFinite)
{
oiio::ImageBufAlgo::clamp(colorspaceBuf, *outBuf, -HALF_MAX, HALF_MAX);
outBuf = &colorspaceBuf;
}

if (storageDataType == EStorageDataType::Half ||
storageDataType == EStorageDataType::HalfFinite)
{
formatBuf.copy(*outBuf, oiio::TypeDesc::HALF); // override format, use half instead of float
outBuf = &formatBuf;
}
}

Expand Down
20 changes: 20 additions & 0 deletions src/aliceVision/image/io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum class EImageFileType
EXR
};


/**
* @brief get informations about each image file type
* @return String
Expand Down Expand Up @@ -91,6 +92,25 @@ std::vector<std::string> getSupportedExtensions();
*/
bool isSupported(const std::string& ext);


/**
* @brief Data type use to write the image
*/
enum class EStorageDataType
{
Float, //< Use full floating point precision to store
Half, //< Use half (values our of range could become inf or nan)
HalfFinite, //< Use half, but ensures out-of-range pixels are clamps to keep finite pixel values
Auto //< Use half if all pixels can be stored in half without clamp, else use full float
};

std::string EStorageDataType_informations();
EStorageDataType EStorageDataType_stringToEnum(const std::string& dataType);
std::string EStorageDataType_enumToString(const EStorageDataType dataType);
std::ostream& operator<<(std::ostream& os, EStorageDataType dataType);
std::istream& operator>>(std::istream& in, EStorageDataType& dataType);


/**
* @brief convert a metadata string map into an oiio::ParamValueList
* @param[in] metadataMap string map
Expand Down
14 changes: 5 additions & 9 deletions src/software/pipeline/main_LdrToHdrMerge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ std::string getHdrImagePath(const std::string& outputPath, std::size_t g)
return hdrImagePath;
}

bool isOverflow(const image::Image<image::RGBfColor> & input) {
const float maxHalfFloat = 65504.0f;
return (input.maxCoeff() > maxHalfFloat);
}

int aliceVision_main(int argc, char** argv)
{
Expand All @@ -64,6 +60,8 @@ int aliceVision_main(int argc, char** argv)
float highlightCorrectionFactor = 1.0f;
float highlightTargetLux = 120000.0f;

image::EStorageDataType storageDataType = image::EStorageDataType::Float;

int rangeStart = -1;
int rangeSize = 1;

Expand Down Expand Up @@ -97,6 +95,8 @@ int aliceVision_main(int argc, char** argv)
("highlightCorrectionFactor", po::value<float>(&highlightCorrectionFactor)->default_value(highlightCorrectionFactor),
"float value between 0 and 1 to correct clamped highlights in dynamic range: use 0 for no correction, 1 for "
"full correction to maxLuminance.")
("storageDataType", po::value<image::EStorageDataType>(&storageDataType)->default_value(storageDataType),
("Storage data type: " + image::EStorageDataType_informations()).c_str())
("rangeStart", po::value<int>(&rangeStart)->default_value(rangeStart),
"Range image index start.")
("rangeSize", po::value<int>(&rangeSize)->default_value(rangeSize),
Expand Down Expand Up @@ -292,11 +292,7 @@ int aliceVision_main(int argc, char** argv)

// Write an image with parameters from the target view
oiio::ParamValueList targetMetadata = image::readImageMetadata(targetView->getImagePath());

if (isOverflow(HDRimage))
{
targetMetadata.push_back(oiio::ParamValue("AliceVision:useFullFloat", int(1)));
}
targetMetadata.push_back(oiio::ParamValue("AliceVision:storageDataType", image::EStorageDataType_enumToString(storageDataType)));

image::writeImage(hdrImagePath, HDRimage, image::EImageColorSpace::AUTO, targetMetadata);
}
Expand Down
17 changes: 7 additions & 10 deletions src/software/pipeline/main_panoramaCompositing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ typedef struct {
std::string weights_path;
} ConfigView;

bool isOverflow(const image::Image<image::RGBAfColor> & input) {
const float maxHalfFloat = 65504.0f;
return (input.maxCoeff() > maxHalfFloat);
}

/**
* @brief Maxflow computation based on a standard Adjacency List graph reprensentation.
Expand Down Expand Up @@ -2155,6 +2151,8 @@ int aliceVision_main(int argc, char **argv)
bool showBorders = false;
bool showSeams = false;

image::EStorageDataType storageDataType = image::EStorageDataType::Float;

system::EVerboseLevel verboseLevel = system::Logger::getDefaultVerboseLevel();

// Program description
Expand All @@ -2176,7 +2174,9 @@ int aliceVision_main(int argc, char **argv)
optionalParams.add_options()
("compositerType,c", po::value<std::string>(&compositerType)->required(), "Compositer Type [replace, alpha, multiband].")
("overlayType,c", po::value<std::string>(&overlayType)->required(), "Overlay Type [none, borders, seams, all].")
("useGraphCut,c", po::value<bool>(&useGraphCut)->default_value(useGraphCut), "Do we use graphcut for ghost removal ?");
("useGraphCut,c", po::value<bool>(&useGraphCut)->default_value(useGraphCut), "Do we use graphcut for ghost removal ?")
("storageDataType", po::value<image::EStorageDataType>(&storageDataType)->default_value(storageDataType),
("Storage data type: " + image::EStorageDataType_informations()).c_str());
allParams.add(optionalParams);

// Setup log level given command line
Expand Down Expand Up @@ -2490,11 +2490,8 @@ int aliceVision_main(int argc, char **argv)
ALICEVISION_LOG_INFO("Write output panorama to file " << outputPanorama);
const aliceVision::image::Image<image::RGBAfColor> & panorama = compositer->getPanorama();

oiio::ParamValueList view_metadata = outputMetadata;
if (isOverflow(panorama))
{
outputMetadata.push_back(oiio::ParamValue("AliceVision:useFullFloat", int(1)));
}
// Select storage data type
outputMetadata.push_back(oiio::ParamValue("AliceVision:storageDataType", image::EStorageDataType_enumToString(storageDataType)));

image::writeImage(outputPanorama, panorama, image::EImageColorSpace::AUTO, outputMetadata);

Expand Down
21 changes: 9 additions & 12 deletions src/software/pipeline/main_panoramaWarping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ namespace po = boost::program_options;
namespace bpt = boost::property_tree;
namespace fs = boost::filesystem;

bool isOverflow(const image::Image<image::RGBfColor> & input) {
const float maxHalfFloat = 65504.0f;
return (input.maxCoeff() > maxHalfFloat);
}

namespace SphericalMapping
{
/**
Expand Down Expand Up @@ -1008,9 +1003,12 @@ int aliceVision_main(int argc, char **argv)
std::string outputDirectory;

std::pair<int, int> panoramaSize = {0, 0};
int percentUpscale = 50;

image::EStorageDataType storageDataType = image::EStorageDataType::Float;

int rangeStart = -1;
int rangeSize = 1;
int percentUpscale = 50;

// Program description
po::options_description allParams (
Expand All @@ -1032,6 +1030,8 @@ int aliceVision_main(int argc, char **argv)
"Panorama Width in pixels.")
("percentUpscale", po::value<int>(&percentUpscale)->default_value(percentUpscale),
"Percentage of upscaled pixels.")
("storageDataType", po::value<image::EStorageDataType>(&storageDataType)->default_value(storageDataType),
("Storage data type: " + image::EStorageDataType_informations()).c_str())
("rangeStart", po::value<int>(&rangeStart)->default_value(rangeStart),
"Range image index start.")
("rangeSize", po::value<int>(&rangeSize)->default_value(rangeSize),
Expand Down Expand Up @@ -1202,15 +1202,12 @@ int aliceVision_main(int argc, char **argv)
{
const aliceVision::image::Image<image::RGBfColor> & cam = warper.getColor();

oiio::ParamValueList view_metadata = metadata;
if (isOverflow(cam))
{
view_metadata.push_back(oiio::ParamValue("AliceVision:useFullFloat", int(1)));
}
oiio::ParamValueList viewMetadata = metadata;
viewMetadata.push_back(oiio::ParamValue("AliceVision:storageDataType", image::EStorageDataType_enumToString(storageDataType)));

const std::string viewFilepath = (fs::path(outputDirectory) / (viewIdStr + ".exr")).string();
ALICEVISION_LOG_INFO("Store view " << i << " with path " << viewFilepath);
image::writeImage(viewFilepath, cam, image::EImageColorSpace::AUTO, view_metadata);
image::writeImage(viewFilepath, cam, image::EImageColorSpace::AUTO, viewMetadata);
}
{
const aliceVision::image::Image<unsigned char> & mask = warper.getMask();
Expand Down

0 comments on commit cb2d65e

Please sign in to comment.