Skip to content

Commit

Permalink
Add export of animated distortion in nuke
Browse files Browse the repository at this point in the history
  • Loading branch information
servantftechnicolor authored and cbentejac committed Dec 2, 2024
1 parent 3eb9554 commit 000236e
Showing 1 changed file with 306 additions and 4 deletions.
310 changes: 306 additions & 4 deletions src/software/export/main_exportDistortion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,234 @@ namespace po = boost::program_options;
using namespace aliceVision;
using namespace aliceVision::camera;

/**
* Build nuke animated distortion
* @param content the output string
* @param sfmData the input sfmData
* @param sequence list of views with SAME sensor/image size/pixelaspectratio/undistortiontype
* @return true if succeeded
*/
bool sequenceToNuke(std::string & content, const sfmData::SfMData & sfmData, const std::vector<sfmData::View::sptr> & sequence)
{
if (sequence.size() == 0)
{
return false;
}

//Sort views by increasing frame ID
std::vector<sfmData::View::sptr> sorted = sequence;
std::sort(sorted.begin(), sorted.end(), [](const sfmData::View::sptr & v1, const sfmData::View::sptr & v2)
{
return v1->getFrameId() < v2->getFrameId();
});

std::string vecFocal, vecOffsetx, vecOffsety;
std::vector<std::string> vecParams;
bool first = true;
camera::EUNDISTORTION commonType;
double commonSensorWidth;
double commonSensorHeight;
double commonPixelAspect;
Vec2 commonSize;

//Build strings
for (const auto & viewPtr: sorted)
{
IndexT idIntrinsic = viewPtr->getIntrinsicId();
if (idIntrinsic == UndefinedIndexT)
{
continue;
}

const auto intrinsic = sfmData.getIntrinsicSharedPtr(idIntrinsic);
const auto intrinsicDisto = std::dynamic_pointer_cast<IntrinsicScaleOffsetDisto>(intrinsic);
if (!intrinsicDisto)
{
continue;
}

aliceVision::IndexT frameId = viewPtr->getFrameId();
std::string sfid = "x" + std::to_string(frameId);

const auto undistortion = intrinsicDisto->getUndistortion();


const double focal = intrinsicDisto->getFocalLength();
const double sensorWidth = intrinsicDisto->sensorWidth();
const double sensorHeight = intrinsicDisto->sensorHeight();
const auto& size = undistortion->getSize();
const double pa = undistortion->getPixelAspectRatio();
const double updatedSensorHeight = (undistortion->isDesqueezed())?sensorHeight:sensorHeight/pa;
const Vec2 offset = undistortion->getScaledOffset();

const std::vector<double>& params = undistortion->getParameters();

if (first)
{
commonType = undistortion->getType();
commonSensorWidth = sensorWidth;
commonSensorHeight = updatedSensorHeight;
commonSize = size;
commonPixelAspect = pa;

vecParams.resize(params.size());
}
else
{
bool same = (commonType == undistortion->getType());
same &= (commonSensorWidth == sensorWidth);
same &= (commonSensorHeight == updatedSensorHeight);
same &= (commonSize == size);
same &= (commonPixelAspect == pa);

if (!same)
{
ALICEVISION_LOG_ERROR("Unsupported change of image/sensor size in the sequence");
return false;
}
}


vecFocal += sfid + " " + std::to_string(focal) + " ";
vecOffsetx += sfid + " " + std::to_string(offset.x()) + " ";
vecOffsety += sfid + " " + std::to_string(-offset.y()) + " ";

for (int idParam = 0; idParam < params.size(); idParam++)
{
double param = params[idParam];

if (idParam == 10)
{
if (undistortion->getType() == EUNDISTORTION::UNDISTORTION_3DEANAMORPHIC4)
{
param = radianToDegree(params[10]);
}
}

vecParams[idParam] += sfid + " " + std::to_string(param) + " ";
}

first = false;
}

for (int idParam = 0; idParam < vecParams.size(); idParam++)
{
vecParams[idParam] = "{{curve " + vecParams[idParam] + "}}";
}

vecFocal = "{{curve " + vecFocal + "}}";
std::string vecOffset = "{{curve "+ vecOffsetx+ "} {curve " + vecOffsety + "}}";

std::stringstream ss;

switch (commonType)
{
case EUNDISTORTION::UNDISTORTION_RADIALK3:
ss << "LensDistortion2 {" << "\n"
<< "\n"
<< " distortionModelPreset Custom" << "\n"
<< " distortionModelPreset \"3DEqualizer/3DE4 Anamorphic - Standard, Degree 4\"\n"
<< " distortionNumerator0 " << vecParams[0] << "\n"
<< "\n"
<< " distortionNumerator1 " << vecParams[1] << "\n"
<< " lens Anamorphic\n"
<< " distortionNumerator2 " << vecParams[2] << "\n"
<< " centre " << vecOffset << "\n"
<< " output Undistort" << "\n"
<< " distortionScalingType Format" << "\n"
<< " distortionScalingFormat \"" << commonSize(0) << " " << commonSize(1) << " 0 0 " << commonSize(0) << " " << commonSize(1) << " 1 AV_undist_fmt \""
<< "\n"
<< "\n"
<< " distortionOrder {3 0}" << "\n"
<< " normalisationType Diagonal" << "\n"
<< " distortInFisheyeSpace false" << "\n"
<< "}"
<< "\n";
break;
case EUNDISTORTION::UNDISTORTION_3DEANAMORPHIC4:
ss << "LD_3DE4_Anamorphic_Standard_Degree_4 {\n"
<< "direction undistort \n"
<< "tde4_focal_length_cm " << vecFocal << " \n"
<< "tde4_custom_focus_distance_cm 1.0 \n"
<< "tde4_filmback_width_cm " << commonSensorWidth << " \n"
<< "tde4_filmback_height_cm " << commonSensorWidth << " \n"
<< "tde4_lens_center_offset_x_cm 0.0000000 \n"
<< "tde4_lens_center_offset_y_cm 0.0000000 \n"
<< "tde4_pixel_aspect " << commonPixelAspect << " \n"
<< "field_of_view_xa_unit 0.0000000 \n"
<< "field_of_view_xb_unit 1.0000000 \n"
<< "field_of_view_ya_unit 0.0000000 \n"
<< "field_of_view_yb_unit 1.0000000 \n"
<< "Cx02_Degree_2 " << vecParams[0] << " \n"
<< "Cy02_Degree_2 " << vecParams[1] << " \n"
<< "Cx22_Degree_2 " << vecParams[2] << " \n"
<< "Cy22_Degree_2 " << vecParams[3] << " \n"
<< "Cx04_Degree_4 " << vecParams[4] << " \n"
<< "Cy04_Degree_4 " << vecParams[5] << " \n"
<< "Cx24_Degree_4 " << vecParams[6] << " \n"
<< "Cy24_Degree_4 " << vecParams[7] << " \n"
<< "Cx44_Degree_4 " << vecParams[8] << " \n"
<< "Cy44_Degree_4 " << vecParams[9] << " \n"
<< "Lens_Rotation " << vecParams[10] << " \n"
<< "Squeeze_X " << vecParams[11] << "\n"
<< "Squeeze_Y " << vecParams[12] << "\n"
<< "}\n";
break;
case EUNDISTORTION::UNDISTORTION_3DERADIAL4:
ss << "LD_3DE4_Radial_Standard_Degree_4 {\n"
<< "direction undistort \n"
<< "tde4_focal_length_cm " << vecFocal << " \n"
<< "tde4_custom_focus_distance_cm 1.0 \n"
<< "tde4_filmback_width_cm " << commonSensorWidth << " \n"
<< "tde4_filmback_height_cm " << commonSensorWidth << " \n"
<< "tde4_lens_center_offset_x_cm 0.0000000 \n"
<< "tde4_lens_center_offset_y_cm 0.0000000 \n"
<< "tde4_pixel_aspect " << commonPixelAspect << " \n"
<< "field_of_view_xa_unit 0.0000000 \n"
<< "field_of_view_xb_unit 1.0000000 \n"
<< "field_of_view_ya_unit 0.0000000 \n"
<< "field_of_view_yb_unit 1.0000000 \n"
<< "Distortion_Degree_2 " << vecParams[0] << " \n"
<< "U_Degree_2 " << vecParams[1] << " \n"
<< "V_Degree_2 " << vecParams[2] << " \n"
<< "Quartic_Distortion_Degree_4 " << vecParams[3] << " \n"
<< "U_Degree_4 " << vecParams[4] << " \n"
<< "V_Degree_4 " << vecParams[5] << " \n"
<< "Phi_Cylindric_Direction " << vecParams[6] << " \n"
<< "B_Cylindric_Bending " << vecParams[7] << " \n"
<< "}\n";
break;
case EUNDISTORTION::UNDISTORTION_3DECLASSICLD:
ss << "LD_3DE4_Radial_Standard_Degree_4 {\n"
<< "direction undistort \n"
<< "tde4_focal_length_cm " << vecFocal << " \n"
<< "tde4_custom_focus_distance_cm 1.0 \n"
<< "tde4_filmback_width_cm " << commonSensorWidth << " \n"
<< "tde4_filmback_height_cm " << commonSensorHeight << " \n"
<< "tde4_lens_center_offset_x_cm 0.0000000 \n"
<< "tde4_lens_center_offset_y_cm 0.0000000 \n"
<< "tde4_pixel_aspect " << commonPixelAspect << " \n"
<< "field_of_view_xa_unit 0.0000000 \n"
<< "field_of_view_xb_unit 1.0000000 \n"
<< "field_of_view_ya_unit 0.0000000 \n"
<< "field_of_view_yb_unit 1.0000000 \n"
<< "Distortion " << vecParams[0] << " \n"
<< "Anamorphic_Squeeze " << vecParams[1] << " \n"
<< "Curvature_X " << vecParams[2] << " \n"
<< "Curvature_Y " << vecParams[3] << " \n"
<< "Quartic_Distortion " << vecParams[4] << " \n"
<< "}\n";
break;
default:
ALICEVISION_LOG_ERROR("Unsupported intrinsic type for conversion to Nuke LensDistortion node: " << EUNDISTORTION_enumToString(commonType));
return false;
}

content = ss.str();

return true;
}

Check notice on line 259 in src/software/export/main_exportDistortion.cpp

View check run for this annotation

codefactor.io / CodeFactor

src/software/export/main_exportDistortion.cpp#L39-L259

Complex Method
std::string toNuke(std::shared_ptr<camera::IntrinsicScaleOffsetDisto> intrinsic)
{
std::stringstream ss;
Expand All @@ -50,11 +278,11 @@ std::string toNuke(std::shared_ptr<camera::IntrinsicScaleOffsetDisto> intrinsic)
ss << "LensDistortion2 {" << "\n"
<< "\n"
<< " distortionModelPreset Custom" << "\n"
<< " distortionModelPreset \"3DEqualizer/3DE4 Anamorphic - Standard, Degree 4\""
<< " distortionModelPreset \"3DEqualizer/3DE4 Anamorphic - Standard, Degree 4\"\n"
<< " distortionNumerator0 " << params[0] << "\n"
<< "\n"
<< " distortionNumerator1 " << params[1] << "\n"
<< " lens Anamorphic"
<< " lens Anamorphic\n"
<< " distortionNumerator2 " << params[2] << "\n"
<< " centre {" << offset[0] << " " << -offset[1] << "}" << "\n"
<< " output Undistort" << "\n"
Expand Down Expand Up @@ -193,6 +421,7 @@ int aliceVision_main(int argc, char* argv[])
bool exportLensGridsUndistorted = true;
bool exportNukeNode = true;
bool exportSTMaps = true;
bool exportAnimatedNukeNode = true;

// Command line parameters
// clang-format off
Expand All @@ -205,9 +434,11 @@ int aliceVision_main(int argc, char* argv[])

po::options_description optionalParams("Optional parameters");
optionalParams.add_options()
("exportNukeNode", po::value<bool>(&exportNukeNode)->default_value(exportLensGridsUndistorted),
("exportNukeNode", po::value<bool>(&exportNukeNode)->default_value(exportNukeNode),
"Export Nuke node as FILE.nk.")
("exportAnimatedNukeNode", po::value<bool>(&exportAnimatedNukeNode)->default_value(exportAnimatedNukeNode),
"Export Nuke node as FILE.nk.")
("exportSTMaps", po::value<bool>(&exportSTMaps)->default_value(exportLensGridsUndistorted),
("exportSTMaps", po::value<bool>(&exportSTMaps)->default_value(exportSTMaps),
"Export STMaps.")
("exportLensGridsUndistorted,e", po::value<bool>(&exportLensGridsUndistorted)->default_value(exportLensGridsUndistorted),
"Export lens grids undistorted for validation.");
Expand All @@ -229,6 +460,77 @@ int aliceVision_main(int argc, char* argv[])
return EXIT_FAILURE;
}

if (exportAnimatedNukeNode)
{
//Map is indexed by a tuple of :
//Undistortion type
//sensor width
//sensor height
//image width
//image height
//Pixel aspect ratio
typedef std::tuple<camera::EUNDISTORTION, int, int, int, int, double> Descriptor;

//Group views by unique descriptor
std::map<Descriptor, std::vector<sfmData::View::sptr>> viewsPerUndistortionType;
for (const auto& [viewId, viewPtr] : sfmData.getViews())
{
IndexT idIntrinsic = viewPtr->getIntrinsicId();
if (idIntrinsic == UndefinedIndexT)
{
continue;
}

const auto intrinsic = sfmData.getIntrinsicSharedPtr(idIntrinsic);
const auto intrinsicDisto = std::dynamic_pointer_cast<IntrinsicScaleOffsetDisto>(intrinsic);
if (!intrinsicDisto)
{
ALICEVISION_LOG_INFO("Intrinsic " << idIntrinsic << " has incorrect format");
continue;
}

const auto undistortion = intrinsicDisto->getUndistortion();

const double sensorWidth = intrinsicDisto->sensorWidth();
const double sensorHeight = intrinsicDisto->sensorHeight();
const auto& size = undistortion->getSize();
const double pa = undistortion->getPixelAspectRatio();

Descriptor d = {undistortion->getType(), sensorWidth, sensorHeight, size.x(), size.y(), pa};
viewsPerUndistortionType[d].push_back(viewPtr);
}

for (const auto & [desc, vec]: viewsPerUndistortionType)
{
std::string nukeNodeStr;

if (!sequenceToNuke(nukeNodeStr, sfmData, vec))
{
continue;
}

const std::string typeName = camera::EUNDISTORTION_enumToString(std::get<0>(desc));

ALICEVISION_LOG_INFO("Writing Nuke animated LensDistortion node for " << typeName);


//Create a unique filename
std::stringstream ss;
ss << outputFilePath << "/animated_";
ss << typeName << "_";
ss << std::to_string(std::get<1>(desc)) << "_";
ss << std::to_string(std::get<2>(desc)) << "_";
ss << std::to_string(std::get<3>(desc)) << "_";
ss << std::to_string(std::get<4>(desc)) << "_";
ss << std::to_string(int(std::get<5>(desc) * 100.0)) << ".nk";

//Store file
std::ofstream of(ss.str());
of << nukeNodeStr;
of.close();
}
}

for (const auto& [intrinsicId, intrinsicPtr] : sfmData.getIntrinsics())
{
ALICEVISION_LOG_INFO("Exporting distortion for intrinsic " << intrinsicId);
Expand Down

0 comments on commit 000236e

Please sign in to comment.