Skip to content

Commit

Permalink
Merge pull request #1301 from alicevision/dev/rawDisableFlip
Browse files Browse the repository at this point in the history
Disable libraw flip
  • Loading branch information
mugulmd authored Jun 12, 2023
2 parents 07354f0 + 5fe182b commit 634ac12
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 23 deletions.
34 changes: 32 additions & 2 deletions src/aliceVision/image/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,14 @@ oiio::ParamValueList readImageMetadata(const std::string& path, int& width, int&

oiio::ImageSpec readImageSpec(const std::string& path)
{
std::unique_ptr<oiio::ImageInput> in(oiio::ImageInput::open(path));
oiio::ImageSpec configSpec;
#if OIIO_VERSION >= (10000 * 2 + 100 * 4 + 12) // OIIO_VERSION >= 2.4.12
// To disable the application of the orientation, we need the PR https://github.com/OpenImageIO/oiio/pull/3669,
// so we can disable the auto orientation and keep the metadata.
configSpec.attribute("raw:user_flip", 0); // disable auto rotation of the image buffer but keep exif metadata orientation valid
#endif

std::unique_ptr<oiio::ImageInput> in(oiio::ImageInput::open(path, &configSpec));
oiio::ImageSpec spec = in->spec();

if(!in)
Expand Down Expand Up @@ -551,6 +558,12 @@ void readImage(const std::string& path,
// libRAW configuration
// See https://openimageio.readthedocs.io/en/master/builtinplugins.html#raw-digital-camera-files

#if OIIO_VERSION >= (10000 * 2 + 100 * 4 + 12) // OIIO_VERSION >= 2.4.12
// To disable the application of the orientation, we need the PR https://github.com/OpenImageIO/oiio/pull/3669,
// so we can disable the auto orientation and keep the metadata.
configSpec.attribute("raw:user_flip", 0); // disable auto rotation of the image buffer but keep exif metadata orientation valid
#endif

if (imageReadOptions.rawColorInterpretation == ERawColorInterpretation::None)
{
if (imageReadOptions.workingColorSpace != EImageColorSpace::NO_CONVERSION)
Expand Down Expand Up @@ -648,13 +661,30 @@ void readImage(const std::string& path,
if (inBuf.spec().nchannels == 2)
ALICEVISION_THROW_ERROR("Load of 2 channels is not supported. Image file: '" + path + "'.");

oiio::ParamValueList imgMetadata = readImageMetadata(path);

if (isRawImage)
{
// Check orientation metadata. If image is mirrored, mirror it back and update orientation metadata
int orientation = imgMetadata.get_int("orientation", -1);

if (orientation == 2 || orientation == 4 || orientation == 5 || orientation == 7)
{
// horizontal mirroring
oiio::ImageBuf inBufMirrored = oiio::ImageBufAlgo::flop(inBuf);
inBuf = inBufMirrored;

orientation += (orientation == 2 || orientation == 4) ? -1 : 1;
}
}

// Apply DCP profile
if (!imageReadOptions.colorProfileFileName.empty() &&
imageReadOptions.rawColorInterpretation == ERawColorInterpretation::DcpLinearProcessing)
{
image::DCPProfile dcpProfile(imageReadOptions.colorProfileFileName);

oiio::ParamValueList imgMetadata = readImageMetadata(path);
//oiio::ParamValueList imgMetadata = readImageMetadata(path);
std::string cam_mul = "";
if (!imgMetadata.getattribute("raw:cam_mul", cam_mul))
{
Expand Down
138 changes: 117 additions & 21 deletions src/software/pipeline/main_panoramaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,6 @@ namespace po = boost::program_options;
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

struct Contact
{
int rank;
std::string path;
int width;
int height;
sfmData::EEXIFOrientation orientation;
};

/**
* A simple class for gaussian pyramid
*/
Expand Down Expand Up @@ -665,16 +656,93 @@ class CircleDetector
size_t _minimal_size;
};

void resample(image::Image<image::RGBfColor>& output, const image::Image<image::RGBfColor>& input)
/**
* @brief Utility function for resizing an image.
*/
void resample(image::Image<image::RGBfColor>& output,
const image::Image<image::RGBfColor>& input)
{
const oiio::ImageBuf inBuf(oiio::ImageSpec(input.Width(), input.Height(), 3, oiio::TypeDesc::FLOAT),
const_cast<image::RGBfColor*>(input.data()));

oiio::ImageBuf outBuf(oiio::ImageSpec(output.Width(), output.Height(), 3, oiio::TypeDesc::FLOAT),
(image::RGBfColor*)output.data());

oiio::ImageBufAlgo::resample(outBuf, inBuf, false);
}

/**
* @brief Utility function for rotating an image given its orientation metadata.
*/
void applyOrientation(image::Image<image::RGBfColor>& output,
const image::Image<image::RGBfColor>& input,
sfmData::EEXIFOrientation orientation)
{
const oiio::ImageBuf inBuf(oiio::ImageSpec(input.Width(), input.Height(), 3, oiio::TypeDesc::FLOAT),
const_cast<image::RGBfColor*>(input.data()));

oiio::ImageBuf outBuf(oiio::ImageSpec(output.Width(), output.Height(), 3, oiio::TypeDesc::FLOAT),
(image::RGBfColor*)output.data());

switch (orientation)
{
case sfmData::EEXIFOrientation::UPSIDEDOWN:
oiio::ImageBufAlgo::rotate180(outBuf, inBuf);
break;
case sfmData::EEXIFOrientation::LEFT:
oiio::ImageBufAlgo::rotate90(outBuf, inBuf);
break;
case sfmData::EEXIFOrientation::RIGHT:
oiio::ImageBufAlgo::rotate270(outBuf, inBuf);
break;
default:
outBuf.copy(inBuf);
break;
}
}

/**
* @brief Utility struct for contact sheet elements.
*/
struct Contact
{
int rank;
std::string path;
int width;
int height;
sfmData::EEXIFOrientation orientation;
};

/**
* @brief Width of contact sheet element, taking into account orientation metadata.
*/
int orientedWidth(const Contact& contact)
{
switch (contact.orientation)
{
case sfmData::EEXIFOrientation::LEFT:
case sfmData::EEXIFOrientation::RIGHT:
return contact.height;
default:
return contact.width;
}
}

/**
* @brief Height of contact sheet element, taking into account orientation metadata.
*/
int orientedHeight(const Contact& contact)
{
switch (contact.orientation)
{
case sfmData::EEXIFOrientation::LEFT:
case sfmData::EEXIFOrientation::RIGHT:
return contact.width;
default:
return contact.height;
}
}

bool buildContactSheetImage(image::Image<image::RGBfColor>& output,
const std::map<int, std::map<int, Contact>>& contactSheetInfo, int contactSheetItemMaxSize)
{
Expand All @@ -686,8 +754,8 @@ bool buildContactSheetImage(image::Image<image::RGBfColor>& output,
{
for(const auto& item : rowpair.second)
{
maxdim = std::max(maxdim, item.second.width);
maxdim = std::max(maxdim, item.second.height);
maxdim = std::max(maxdim, orientedWidth(item.second));
maxdim = std::max(maxdim, orientedHeight(item.second));
}
}
double ratioResize = double(contactSheetItemMaxSize) / double(maxdim);
Expand All @@ -702,8 +770,8 @@ bool buildContactSheetImage(image::Image<image::RGBfColor>& output,

for(const auto& item : rowpair.second)
{
int resizedHeight = int(ratioResize * double(item.second.height));
int resizedWidth = int(ratioResize * double(item.second.width));
int resizedHeight = int(ratioResize * double(orientedHeight(item.second)));
int resizedWidth = int(ratioResize * double(orientedWidth(item.second)));

rowHeight = std::max(rowHeight, resizedHeight);
rowWidth += resizedWidth + space;
Expand All @@ -729,8 +797,8 @@ bool buildContactSheetImage(image::Image<image::RGBfColor>& output,

for(const auto& item : rowpair.second)
{
int resizedHeight = int(ratioResize * double(item.second.height));
int resizedWidth = int(ratioResize * double(item.second.width));
int resizedHeight = int(ratioResize * double(orientedHeight(item.second)));
int resizedWidth = int(ratioResize * double(orientedWidth(item.second)));

rowHeight = std::max(rowHeight, resizedHeight);
rowWidth += resizedWidth + space;
Expand All @@ -742,15 +810,20 @@ bool buildContactSheetImage(image::Image<image::RGBfColor>& output,
int posX = space;
for(const auto& item : rowpair.second)
{
int resizedHeight = int(ratioResize * double(item.second.height));
int resizedWidth = int(ratioResize * double(item.second.width));
int rawResizedHeight = int(ratioResize * double(item.second.height));
int rawResizedWidth = int(ratioResize * double(item.second.width));

int resizedHeight = int(ratioResize * double(orientedHeight(item.second)));
int resizedWidth = int(ratioResize * double(orientedWidth(item.second)));

image::Image<image::RGBfColor> input;
image::Image<image::RGBfColor> rawThumbnail(rawResizedWidth, rawResizedHeight);
image::Image<image::RGBfColor> thumbnail(resizedWidth, resizedHeight);

image::readImage(item.second.path, input, image::EImageColorSpace::SRGB);

resample(thumbnail, input);
resample(rawThumbnail, input);
applyOrientation(thumbnail, rawThumbnail, item.second.orientation);

rowOutput.block(0, posX, resizedHeight, resizedWidth) = thumbnail;
posX += resizedWidth + space;
Expand Down Expand Up @@ -1154,9 +1227,32 @@ int main(int argc, char* argv[])
for(const auto& item_rotation : rotations)
{
IndexT viewIdx = namesWithRank[index].second;
if(item_rotation.second.trace() != 0)
const sfmData::View& v = sfmData.getView(viewIdx);

sfmData::EEXIFOrientation orientation = v.getMetadataOrientation();
double orientationAngle = 0.;
switch (orientation)
{
case sfmData::EEXIFOrientation::UPSIDEDOWN:
orientationAngle = boost::math::constants::pi<double>();
break;
case sfmData::EEXIFOrientation::LEFT:
orientationAngle = boost::math::constants::pi<double>() * .5;
break;
case sfmData::EEXIFOrientation::RIGHT:
orientationAngle = boost::math::constants::pi<double>() * -.5;
break;
default:
break;
}

const Eigen::AngleAxis<double> Morientation(orientationAngle, Eigen::Vector3d::UnitZ());

const Eigen::Matrix3d viewRotation = Morientation.toRotationMatrix().transpose() * item_rotation.second;

if(viewRotation.trace() != 0)
{
sfmData::CameraPose pose(geometry::Pose3(item_rotation.second, Eigen::Vector3d::Zero()));
sfmData::CameraPose pose(geometry::Pose3(viewRotation, Eigen::Vector3d::Zero()));
sfmData.setAbsolutePose(viewIdx, pose);
}
++index;
Expand Down

0 comments on commit 634ac12

Please sign in to comment.