Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage LCP in imageProcessing #1459

Merged
merged 7 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 131 additions & 29 deletions src/aliceVision/lensCorrectionProfile/lcp.cpp

Large diffs are not rendered by default.

93 changes: 72 additions & 21 deletions src/aliceVision/lensCorrectionProfile/lcp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,33 +92,70 @@ struct RectilinearModel
{
*this = RectilinearModel();
}
};

/**
* @brief PerspectiveModel contains parameters of a perspective model of distortion
* Detailed information on this model can be found in the Adobe technical report
* "Adobe Camera Model" part of the documentation of the Adobe free tool Lens Profile Creator.
*/
struct PerspectiveModel
{
int Version = -1;
float FocalLengthX = 0.f;
float FocalLengthY = 0.f;
float ImageXCenter = 0.5f;
float ImageYCenter = 0.5f;
float ResidualMeanError = 0.f;
float ResidualStandardDeviation = 0.f;
float RadialDistortParam1 = 0.f;
float RadialDistortParam2 = 0.f;
float RadialDistortParam3 = 0.f;
bool isEmpty = true;
void distort(const float x, const float y, float& x_d, float& y_d)
{
const float rr = x * x + y * y;
const float p1 = 1.f + rr * (RadialDistortParam1 + rr * (RadialDistortParam2 + rr * RadialDistortParam3));
const float p2 = TangentialDistortParam1 * y + TangentialDistortParam2 * x;
x_d = ScaleFactor * (p1 * x + 2 * p2 * x + TangentialDistortParam2 * rr);
y_d = ScaleFactor * (p1 * y + 2 * p2 * y + TangentialDistortParam1 * rr);
}

void reset()
bool init3(const std::vector<float>& params)
{
*this = PerspectiveModel();
if(params.size() < 7)
{
reset();
return false;
}
FocalLengthX = params[0];
FocalLengthY = params[1];
ImageXCenter = params[2];
ImageYCenter = params[3];
RadialDistortParam1 = params[4];
RadialDistortParam2 = params[5];
RadialDistortParam3 = params[6];
ScaleFactor = (params.size() >= 8) ? params[7] : 1.0;
isEmpty = false;
return true;
}

bool init5(const std::vector<float>& params)
{
if(params.size() < 9)
{
reset();
return false;
}
init3(params);
TangentialDistortParam1 = params[7];
TangentialDistortParam2 = params[8];
ScaleFactor = (params.size() >= 10) ? params[9] : 1.0;
isEmpty = false;
return true;
}
};

inline std::ostream& operator<<(std::ostream& os, const RectilinearModel& model)
{
if (model.isEmpty)
{
os << "Empty";
}
else
{
os << "Focal: (" << model.FocalLengthX << ", " << model.FocalLengthY << ")" << std::endl;
os << "Center: (" << model.ImageXCenter << ", " << model.ImageYCenter << ")" << std::endl;
os << "Radial: (" << model.RadialDistortParam1 << ", " << model.RadialDistortParam2 << ", "
<< model.RadialDistortParam3 << ")" << std::endl;
os << "Tangential: (" << model.TangentialDistortParam1 << ", " << model.TangentialDistortParam2 << ")"
<< std::endl;
os << "scale: " << model.ScaleFactor;
}
return os;
}

/**
* @brief VignetteModel contains parameters of a vignetting model of distortion
* Detailed information on this model can be found in the Adobe technical report
Expand Down Expand Up @@ -181,6 +218,12 @@ class LensParam
*/
void clear();

/**
* @brief Indicate that no geometric model is available
* @return true if no geometric model is available
*/
bool isEmpty() const { return perspParams.isEmpty && fisheyeParams.isEmpty; }

/**
* @brief Indicate that paramaters apply for a fisheye lens
* @return true if the fisheye model is the valid one
Expand Down Expand Up @@ -299,6 +342,14 @@ class LCPinfo
*/
void getVignettingParams(const float& focalLength, const float& aperture, LensParam& lparam);

/**
* @brief Get defringing parameters for a given couple focal length, focus distance. Focus distance can set to zero.
* @param[in] focalLength Focal length in mm
* @param[in] focusDistance Focus distance in meters
* @param[out] lparam Lens parameters to be populated with the R, G and B defringing models
*/
void getChromaticParams(const float& focalLength, const float& focusDistance, LensParam& lparam);

/**
* @brief Indicate that no lens paramater set is available
* @return true if no lens paramater set is available
Expand Down
1 change: 1 addition & 0 deletions src/aliceVision/sfmData/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ alicevision_add_library(aliceVision_sfmData
aliceVision_feature
aliceVision_geometry
aliceVision_camera
aliceVision_sensorDB
aliceVision_stl
Boost::filesystem
PRIVATE_LINKS
Expand Down
184 changes: 183 additions & 1 deletion src/aliceVision/sfmData/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
#include <utility>
#include <regex>


#include <iostream>
#include <aliceVision/numeric/gps.hpp>
#include <aliceVision/sensorDB/parseDatabase.hpp>
#include <aliceVision/sfmDataIO/viewIO.hpp>

namespace aliceVision {
namespace sfmData {
Expand Down Expand Up @@ -194,6 +195,187 @@ Vec3 View::getGpsPositionWGS84FromMetadata() const
return {lat, lon, alt};
}

int View::getSensorSize(const std::vector<sensorDB::Datasheet>& sensorDatabase, double& sensorWidth, double& sensorHeight,
double& focalLengthmm, camera::EInitMode& intrinsicInitMode, bool verbose)
{
int errCode = 0;

enum class ESensorWidthSource
{
FROM_DB,
FROM_METADATA_ESTIMATION,
UNKNOWN
} sensorWidthSource = ESensorWidthSource::UNKNOWN;

const std::string& make = getMetadataMake();
const std::string& model = getMetadataModel();
focalLengthmm = getMetadataFocalLength();
const bool hasCameraMetadata = (!make.empty() || !model.empty());

if (hasCameraMetadata)
{
intrinsicInitMode = camera::EInitMode::UNKNOWN;
sensorDB::Datasheet datasheet;
if (sensorDB::getInfo(make, model, sensorDatabase, datasheet))
{
if (verbose)
{
// sensor is in the database
ALICEVISION_LOG_TRACE("Sensor width found in sensor database: " << std::endl
<< "\t- brand: " << make << std::endl
<< "\t- model: " << model << std::endl
<< "\t- sensor width: " << datasheet._sensorWidth << " mm");
}

if ((datasheet._model != model) && (datasheet._model != make + " " + model))
{
// the camera model in sensor database is slightly different
errCode = 3;

if (verbose)
{
ALICEVISION_LOG_WARNING("The camera found in the sensor database is slightly different for image " << getImagePath());
ALICEVISION_LOG_WARNING("\t- image camera brand: " << make << std::endl
<< "\t- image camera model: " << model << std::endl
<< "\t- sensor database camera brand: " << datasheet._brand << std::endl
<< "\t- sensor database camera model: " << datasheet._model << std::endl
<< "\t- sensor database camera sensor width: " << datasheet._sensorWidth << " mm");
ALICEVISION_LOG_WARNING("Please check and correct camera model(s) name in the sensor database." << std::endl);
}
}

sensorWidth = datasheet._sensorWidth;
sensorWidthSource = ESensorWidthSource::FROM_DB;

if (focalLengthmm > 0.0)
{
intrinsicInitMode = camera::EInitMode::ESTIMATED;
}
}
}

// try to find / compute with 'FocalLengthIn35mmFilm' metadata
const bool hasFocalIn35mmMetadata = hasDigitMetadata({"Exif:FocalLengthIn35mmFilm", "FocalLengthIn35mmFilm"});
if (hasFocalIn35mmMetadata)
{
const double imageRatio = static_cast<double>(getWidth()) / static_cast<double>(getHeight());
const double diag24x36 = std::sqrt(36.0 * 36.0 + 24.0 * 24.0);
const double focalIn35mm = hasFocalIn35mmMetadata ? getDoubleMetadata({"Exif:FocalLengthIn35mmFilm", "FocalLengthIn35mmFilm"}) : -1.0;

if (sensorWidth == -1.0)
{
const double invRatio = 1.0 / imageRatio;

if (focalLengthmm > 0.0)
{
// no sensorWidth but valid focalLength and valid focalLengthIn35mm, so deduce
// sensorWith approximation
const double sensorDiag = (focalLengthmm * diag24x36) / focalIn35mm; // 43.3 is the diagonal of 35mm film
sensorWidth = sensorDiag * std::sqrt(1.0 / (1.0 + invRatio * invRatio));
sensorWidthSource = ESensorWidthSource::FROM_METADATA_ESTIMATION;
}
else
{
// no sensorWidth and no focalLength but valid focalLengthIn35mm, so consider sensorWith
// as 35mm
sensorWidth = diag24x36 * std::sqrt(1.0 / (1.0 + invRatio * invRatio));
focalLengthmm = sensorWidth * (focalIn35mm) / 36.0;
sensorWidthSource = ESensorWidthSource::UNKNOWN;
}
errCode = 4;

if (verbose)
{
std::stringstream ss;
ss << "Intrinsic(s) initialized from 'FocalLengthIn35mmFilm' exif metadata in image " << getImagePath() << "\n";
ss << "\t- sensor width: " << sensorWidth << "\n";
ss << "\t- focal length: " << focalLengthmm << "\n";
ALICEVISION_LOG_DEBUG(ss.str());
}

sensorHeight = (imageRatio > 1.0) ? sensorWidth / imageRatio : sensorWidth * imageRatio;

intrinsicInitMode = camera::EInitMode::ESTIMATED;
}
else if (sensorWidth > 0 && focalLengthmm <= 0)
{
// valid sensorWidth and valid focalLengthIn35mm but no focalLength, so convert
// focalLengthIn35mm to the actual width of the sensor
const double sensorDiag = std::sqrt(std::pow(sensorWidth, 2) + std::pow(sensorWidth / imageRatio, 2));
focalLengthmm = (sensorDiag * focalIn35mm) / diag24x36;

errCode = 4;

if (verbose)
{
std::stringstream ss;
ss << "Intrinsic(s) initialized from 'FocalLengthIn35mmFilm' exif metadata in image " << getImagePath() << "\n";
ss << "\t- sensor width: " << sensorWidth << "\n";
ss << "\t- focal length: " << focalLengthmm << "\n";
ALICEVISION_LOG_DEBUG(ss.str());
}

intrinsicInitMode = camera::EInitMode::ESTIMATED;
}
}

// error handling
if (sensorWidth == -1.0)
{
if (hasCameraMetadata)
{
// sensor is not in the database
errCode = 1;
if (verbose)
{
std::stringstream ss;
ss << "Sensor width doesn't exist in the sensor database for image " << getImagePath() << "\n";
ss << "\t- camera brand: " << make << "\n";
ss << "\t- camera model: " << model << "\n";
ss << "Please add camera model and sensor width in the database.";
ALICEVISION_LOG_WARNING(ss.str());
}
}
else
{
// no metadata 'Make' and 'Model' can't find sensor width
errCode = 2;
if (verbose)
{
std::stringstream ss;
ss << "No metadata in image " << getImagePath() << "\n";
ALICEVISION_LOG_DEBUG(ss.str());
}
}
}
else
{
// we have a valid sensorWidth information, so we store it into the metadata (where it would
// have been nice to have it in the first place)
if (sensorWidthSource == ESensorWidthSource::FROM_DB)
{
addMetadata("AliceVision:SensorWidth", std::to_string(sensorWidth));
}
else if (sensorWidthSource == ESensorWidthSource::FROM_METADATA_ESTIMATION)
{
addMetadata("AliceVision:SensorWidthEstimation", std::to_string(sensorWidth));
}
}

if (sensorWidth < 0)
{
if (verbose)
{
ALICEVISION_LOG_WARNING("Sensor size is unknown");
ALICEVISION_LOG_WARNING("Use default sensor size (24x36 mm)");
}
sensorWidth = 36.0;
sensorHeight = 24.0;
}

return errCode;
}

std::string GPSExifTags::latitude()
{
return "GPS:Latitude";
Expand Down
Loading