Skip to content

Commit

Permalink
transform: transform scene by the given matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
cdcseacave committed May 4, 2023
1 parent b41a8ce commit af8578a
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 8 deletions.
42 changes: 38 additions & 4 deletions apps/TransformScene/TransformScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace OPT {
String strInputFileName;
String strOutputFileName;
String strAlignFileName;
String strTransformFileName;
String strTransferTextureFileName;
String strIndicesFileName;
bool bComputeVolume;
Expand Down Expand Up @@ -98,7 +99,8 @@ bool Initialize(size_t argc, LPCTSTR* argv)
("input-file,i", boost::program_options::value<std::string>(&OPT::strInputFileName), "input scene filename")
("output-file,o", boost::program_options::value<std::string>(&OPT::strOutputFileName), "output filename for storing the scene")
("align-file,a", boost::program_options::value<std::string>(&OPT::strAlignFileName), "input scene filename to which the scene will be cameras aligned")
("transfer-texture-file,t", boost::program_options::value<std::string>(&OPT::strTransferTextureFileName), "input mesh filename to which the texture of the scene's mesh will be transfered to (the two meshes should be aligned and the new mesh to have UV-map)")
("transform-file,t", boost::program_options::value<std::string>(&OPT::strTransformFileName), "input transform filename by which the scene will transformed")
("transfer-texture-file", boost::program_options::value<std::string>(&OPT::strTransferTextureFileName), "input mesh filename to which the texture of the scene's mesh will be transfered to (the two meshes should be aligned and the new mesh to have UV-map)")
("indices-file", boost::program_options::value<std::string>(&OPT::strIndicesFileName), "input indices filename to be used with ex. texture transfer to select a subset of the scene's mesh")
("compute-volume", boost::program_options::value(&OPT::bComputeVolume)->default_value(false), "compute the volume of the given watertight mesh, or else try to estimate the ground plane and assume the mesh is bounded by it")
("plane-threshold", boost::program_options::value(&OPT::fPlaneThreshold)->default_value(0.f), "threshold used to estimate the ground plane (<0 - disabled, 0 - auto, >0 - desired threshold)")
Expand Down Expand Up @@ -142,10 +144,12 @@ bool Initialize(size_t argc, LPCTSTR* argv)
// validate input
Util::ensureValidPath(OPT::strInputFileName);
Util::ensureValidPath(OPT::strAlignFileName);
Util::ensureValidPath(OPT::strTransformFileName);
Util::ensureValidPath(OPT::strTransferTextureFileName);
Util::ensureValidPath(OPT::strIndicesFileName);
const String strInputFileNameExt(Util::getFileExt(OPT::strInputFileName).ToLower());
const bool bInvalidCommand(OPT::strInputFileName.empty() || (OPT::strAlignFileName.empty() && OPT::strTransferTextureFileName.empty() && !OPT::bComputeVolume));
const bool bInvalidCommand(OPT::strInputFileName.empty() ||
(OPT::strAlignFileName.empty() && OPT::strTransformFileName.empty() && OPT::strTransferTextureFileName.empty() && !OPT::bComputeVolume));
if (OPT::vm.count("help") || bInvalidCommand) {
boost::program_options::options_description visible("Available options");
visible.add(generic).add(config);
Expand Down Expand Up @@ -215,7 +219,7 @@ int main(int argc, LPCTSTR* argv)
Scene scene(OPT::nMaxThreads);

// load given scene
if (!scene.Load(MAKE_PATH_SAFE(OPT::strInputFileName), !OPT::strTransferTextureFileName.empty() || OPT::bComputeVolume))
if (!scene.Load(MAKE_PATH_SAFE(OPT::strInputFileName), !OPT::strTransformFileName.empty() || !OPT::strTransferTextureFileName.empty() || OPT::bComputeVolume))
return EXIT_FAILURE;

if (!OPT::strAlignFileName.empty()) {
Expand All @@ -228,6 +232,31 @@ int main(int argc, LPCTSTR* argv)
VERBOSE("Scene aligned to the given reference scene (%s)", TD_TIMER_GET_FMT().c_str());
}

if (!OPT::strTransformFileName.empty()) {
// transform this scene by the given transform matrix
std::ifstream file(MAKE_PATH_SAFE(OPT::strTransformFileName));
std::string strLine;
std::vector<double> transformValues;
while (std::getline(file, strLine)) {
errno = 0;
char* strEnd{};
const double v = std::strtod(strLine.c_str(), &strEnd);
if (errno == ERANGE || strEnd == strLine.c_str())
continue;
transformValues.push_back(v);
}
if (transformValues.size() != 12 &&
(transformValues.size() != 16 || transformValues[12] != 0 || transformValues[13] != 0 || transformValues[14] != 0 || transformValues[15] != 1)) {
VERBOSE("error: invalid transform");
return EXIT_FAILURE;
}
Matrix3x4 transform;
for (unsigned i=0; i<12; ++i)
transform[i] = transformValues[i];
scene.Transform(transform);
VERBOSE("Scene transformed by the given transformation matrix (%s)", TD_TIMER_GET_FMT().c_str());
}

if (!OPT::strTransferTextureFileName.empty()) {
// transfer the texture of the scene's mesh to the new mesh;
// the two meshes should be aligned and the new mesh to have UV-coordinates
Expand Down Expand Up @@ -263,7 +292,12 @@ int main(int argc, LPCTSTR* argv)
}

// write transformed scene
scene.Save(MAKE_PATH_SAFE(OPT::strOutputFileName), (ARCHIVE_TYPE)OPT::nArchiveType);
if (scene.IsValid())
scene.Save(MAKE_PATH_SAFE(OPT::strOutputFileName), (ARCHIVE_TYPE)OPT::nArchiveType);
else if (!scene.pointcloud.IsEmpty())
scene.pointcloud.Save(Util::getFileFullName(MAKE_PATH_SAFE(OPT::strOutputFileName)) + ".ply");
else if (!scene.mesh.IsEmpty())
scene.mesh.Save(Util::getFileFullName(MAKE_PATH_SAFE(OPT::strOutputFileName)) + ".ply");

Finalize();
return EXIT_SUCCESS;
Expand Down
3 changes: 2 additions & 1 deletion libs/MVS/PythonWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ BOOST_PYTHON_MODULE(pyOpenMVS) {
.def("load_mesh", &Scene::pyLoadMesh, (arg("file_path")))
.def("save_mesh", &Scene::pySaveMesh, (arg("file_path")))
.def("scale_images", &Scene::ScaleImages)
.def("transform", &Scene::Transform)
.def("transform", static_cast<void (Scene:: *)(const Matrix3x3&, const Point3&, REAL)>(&Scene::Transform))
.def("transform34", static_cast<void (Scene:: *)(const Matrix3x4&)>(&Scene::Transform))
.def("align_to", &Scene::AlignTo)
.def("dense_reconstruction", &Scene::pyDenseReconstruction, (arg("resolution_level")=0, arg("fusion_mode")=0, arg("crop_to_roi")=true, arg("roi_border")=0.f))
.def("reconstruct_mesh", &Scene::pyReconstructMesh, (arg("dist_insert")=2, arg("use_free_space_support")=false, arg("use_only_roi")=false))
Expand Down
32 changes: 29 additions & 3 deletions libs/MVS/Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ void Scene::Release()
mesh.Release();
}

bool Scene::IsValid() const
{
return !platforms.IsEmpty() && !images.IsEmpty();
}

bool Scene::IsEmpty() const
{
return pointcloud.IsEmpty() && mesh.IsEmpty();
Expand Down Expand Up @@ -122,6 +127,7 @@ bool Scene::LoadInterface(const String & fileName)
for (const Interface::Image& image: obj.images) {
const uint32_t ID(images.size());
Image& imageData = images.AddEmpty();
imageData.ID = (image.ID == NO_ID ? ID : image.ID);
imageData.name = image.name;
Util::ensureUnifySlash(imageData.name);
imageData.name = MAKE_PATH_FULL(WORKING_FOLDER_FULL, imageData.name);
Expand All @@ -137,7 +143,6 @@ bool Scene::LoadInterface(const String & fileName)
}
imageData.platformID = image.platformID;
imageData.cameraID = image.cameraID;
imageData.ID = (image.ID == NO_ID ? ID : image.ID);
// init camera
const Interface::Platform::Camera& camera = obj.platforms[image.platformID].cameras[image.cameraID];
if (camera.HasResolution()) {
Expand Down Expand Up @@ -1440,7 +1445,8 @@ bool Scene::ScaleImages(unsigned nMaxResolution, REAL scale, const String& folde
} // ScaleImages

// apply similarity transform
void Scene::Transform(const Matrix3x3& rotation, const Point3& translation, REAL scale) {
void Scene::Transform(const Matrix3x3& rotation, const Point3& translation, REAL scale)
{
const Matrix3x3 rotationScale(rotation * scale);
for (Platform& platform : platforms) {
for (Platform::Pose& pose : platform.poses) {
Expand All @@ -1449,7 +1455,8 @@ void Scene::Transform(const Matrix3x3& rotation, const Point3& translation, REAL
}
}
for (Image& image : images) {
image.UpdateCamera(platforms);
if (image.IsValid())
image.UpdateCamera(platforms);
}
FOREACH(i, pointcloud.points) {
pointcloud.points[i] = rotationScale * Cast<REAL>(pointcloud.points[i]) + translation;
Expand All @@ -1469,6 +1476,25 @@ void Scene::Transform(const Matrix3x3& rotation, const Point3& translation, REAL
obb.Translate(Cast<float>(translation));
}
}
void Scene::Transform(const Matrix3x4& transform)
{
#if 1
Matrix3x3 mscale, rotation;
RQDecomp3x3<REAL>(cv::Mat(3,4,cv::DataType<REAL>::type,const_cast<REAL*>(transform.val))(cv::Rect(0,0, 3,3)), mscale, rotation);
const Point3 translation = transform.col(3);
#else
Eigen::Matrix<REAL,4,4> transform4x4 = Eigen::Matrix<REAL,4,4>::Identity();
transform4x4.topLeftCorner<3,4>() = static_cast<const Matrix3x4::CEMatMap>(transform);
Eigen::Transform<REAL, 3, Eigen::Isometry> transformIsometry(transform4x4);
Eigen::Matrix<REAL,3,3> mrotation;
Eigen::Matrix<REAL,3,3> mscale;
transformIsometry.computeRotationScaling(&mrotation, &mscale);
const Point3 translation = transformIsometry.translation();
const Matrix3x3 rotation = mrotation;
#endif
ASSERT(mscale(0,0) > 0 && ISEQUAL(mscale(0,0), mscale(1,1)) && ISEQUAL(mscale(0,0), mscale(2,2)));
Transform(rotation, translation, mscale(0,0));
} // Transform

// transform this scene such that it best aligns with the given scene based on the camera positions
bool Scene::AlignTo(const Scene& scene)
Expand Down
2 changes: 2 additions & 0 deletions libs/MVS/Scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class MVS_API Scene
: obb(true), nMaxThreads(Thread::getMaxThreads(_nMaxThreads)) {}

void Release();
bool IsValid() const;
bool IsEmpty() const;
bool ImagesHaveNeighbors() const;
bool IsBounded() const { return obb.IsValid(); }
Expand Down Expand Up @@ -105,6 +106,7 @@ class MVS_API Scene
bool Scale(const REAL* pScale = NULL);
bool ScaleImages(unsigned nMaxResolution = 0, REAL scale = 0, const String& folderName = String());
void Transform(const Matrix3x3& rotation, const Point3& translation, REAL scale);
void Transform(const Matrix3x4& transform);
bool AlignTo(const Scene&);
REAL ComputeLeveledVolume(float planeThreshold=0, float sampleMesh=-100000, unsigned upAxis=2, bool verbose=true);

Expand Down

0 comments on commit af8578a

Please sign in to comment.