Skip to content

Commit 60dc65d

Browse files
author
Fabien Servant
committed
Pose injection from json
1 parent f59dd85 commit 60dc65d

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed

src/software/utils/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,19 @@ if(ALICEVISION_BUILD_SFM)
218218
Boost::program_options
219219
)
220220

221+
# SfM Merge
222+
alicevision_add_software(aliceVision_sfmPoseInjecting
223+
SOURCE main_sfmPoseInjecting.cpp
224+
FOLDER ${FOLDER_SOFTWARE_UTILS}
225+
LINKS aliceVision_system
226+
aliceVision_cmdline
227+
aliceVision_sfmData
228+
aliceVision_sfmDataIO
229+
aliceVision_sfm
230+
Boost::program_options
231+
Boost::json
232+
)
233+
221234
# SfM Regression
222235
alicevision_add_software(aliceVision_sfmRegression
223236
SOURCE main_sfmRegression.cpp
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2024 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
#include <aliceVision/types.hpp>
8+
#include <aliceVision/config.hpp>
9+
10+
#include <aliceVision/system/Timer.hpp>
11+
#include <aliceVision/system/Logger.hpp>
12+
#include <aliceVision/system/main.hpp>
13+
#include <aliceVision/cmdline/cmdline.hpp>
14+
15+
#include <aliceVision/sfmDataIO/sfmDataIO.hpp>
16+
17+
#include <boost/program_options.hpp>
18+
#include <boost/json.hpp>
19+
20+
// These constants define the current software version.
21+
// They must be updated when the command line is changed.
22+
#define ALICEVISION_SOFTWARE_VERSION_MAJOR 1
23+
#define ALICEVISION_SOFTWARE_VERSION_MINOR 0
24+
25+
using namespace aliceVision;
26+
namespace po = boost::program_options;
27+
28+
struct poseInput
29+
{
30+
IndexT frameId;
31+
Eigen::Matrix4d T;
32+
};
33+
34+
/**
35+
* I/O for Rotation format choice
36+
*/
37+
38+
enum class ERotationFormat
39+
{
40+
EulerZXY
41+
};
42+
43+
inline std::string ERotationFormat_enumToString(ERotationFormat format)
44+
{
45+
switch (format)
46+
{
47+
case ERotationFormat::EulerZXY:
48+
{
49+
return "EulerZXY";
50+
}
51+
}
52+
throw std::out_of_range("Invalid RotationFormat type Enum: " + std::to_string(int(format)));
53+
}
54+
55+
inline ERotationFormat ERotationFormat_stringToEnum(const std::string& format)
56+
{
57+
if (format == "EulerZXY")
58+
{
59+
return ERotationFormat::EulerZXY;
60+
}
61+
62+
throw std::out_of_range("Invalid RotationFormat type Enum: " + format);
63+
}
64+
65+
inline std::ostream& operator<<(std::ostream& os, ERotationFormat s)
66+
{
67+
return os << ERotationFormat_enumToString(s);
68+
}
69+
70+
inline std::istream& operator>>(std::istream& in, ERotationFormat& s)
71+
{
72+
std::string token(std::istreambuf_iterator<char>(in), {});
73+
s = ERotationFormat_stringToEnum(token);
74+
return in;
75+
}
76+
77+
78+
/**
79+
* @brief get a pose from a boost json object (assume the file format is ok)
80+
* @param obj the input json object
81+
* @param format the required rotation format to transform to rotation matrix
82+
* @param readPose the output pose information
83+
* @return false if the process failed
84+
*/
85+
bool getPoseFromJson(const boost::json::object& obj, ERotationFormat format, poseInput & readPose)
86+
{
87+
Eigen::Matrix3d R = Eigen::Matrix3d::Identity();
88+
89+
if (format == ERotationFormat::EulerZXY)
90+
{
91+
//Reading information from lineup
92+
const double rx = degreeToRadian(boost::json::value_to<double>(obj.at("rx")));
93+
const double ry = degreeToRadian(boost::json::value_to<double>(obj.at("ry")));
94+
const double rz = degreeToRadian(boost::json::value_to<double>(obj.at("rz")));
95+
96+
Eigen::AngleAxisd Rx(rx, Eigen::Vector3d::UnitX());
97+
Eigen::AngleAxisd Ry(ry, Eigen::Vector3d::UnitY());
98+
Eigen::AngleAxisd Rz(rz, Eigen::Vector3d::UnitZ());
99+
100+
R = Ry.toRotationMatrix() * Rx.toRotationMatrix() * Rz.toRotationMatrix();
101+
}
102+
else
103+
{
104+
return false;
105+
}
106+
107+
readPose.frameId = boost::json::value_to<IndexT>(obj.at("frame_no"));
108+
109+
Eigen::Vector3d t;
110+
t.x() = boost::json::value_to<double>(obj.at("tx"));
111+
t.y() = boost::json::value_to<double>(obj.at("ty"));
112+
t.z() = boost::json::value_to<double>(obj.at("tz"));
113+
114+
readPose.T = Eigen::Matrix4d::Identity();
115+
readPose.T.block<3, 3>(0, 0) = R;
116+
readPose.T.block<3, 1>(0, 3) = t;
117+
118+
return true;
119+
}
120+
121+
/**
122+
* @brief get a set of poses from a json file (assume the file format is ok)
123+
* Json file contains an array of objects. Each object describes a frameId, a rotation and a translation.
124+
* @param obj the input json filename
125+
* @param format the required rotation format to transform to rotation matrix
126+
* @param readPose the output poses vector
127+
* @return false if the process failed
128+
*/
129+
bool getPosesFromJson(const std::string & posesFilename, ERotationFormat format, std::vector<poseInput> & readPoses)
130+
{
131+
std::ifstream inputfile(posesFilename);
132+
if (!inputfile.is_open())
133+
{
134+
return false;
135+
}
136+
137+
std::stringstream buffer;
138+
buffer << inputfile.rdbuf();
139+
boost::json::value jv = boost::json::parse(buffer.str());
140+
141+
if (!jv.is_array())
142+
{
143+
return false;
144+
}
145+
146+
boost::json::array vobj = jv.as_array();
147+
148+
for (auto item : vobj)
149+
{
150+
const boost::json::object& obj = item.as_object();
151+
152+
poseInput input;
153+
if (getPoseFromJson(obj, format, input))
154+
{
155+
readPoses.push_back(input);
156+
}
157+
}
158+
159+
return true;
160+
}
161+
162+
int aliceVision_main(int argc, char** argv)
163+
{
164+
// command-line parameters
165+
std::string sfmDataFilename;
166+
std::string sfmDataOutputFilename;
167+
std::string posesFilename;
168+
ERotationFormat format;
169+
170+
171+
po::options_description requiredParams("Required parameters");
172+
requiredParams.add_options()
173+
("input,i", po::value<std::string>(&sfmDataFilename)->required(), "SfMData file.")
174+
("output,o", po::value<std::string>(&sfmDataOutputFilename)->required(), "SfMData output file.")
175+
("posesFilename,p", po::value<std::string>(&posesFilename)->required(), "Poses file.")
176+
("rotationFormat,r", po::value<ERotationFormat>(&format)->required(), "Poses file.");
177+
178+
179+
CmdLine cmdline("AliceVision SfM Pose injecting");
180+
181+
cmdline.add(requiredParams);
182+
if(!cmdline.execute(argc, argv))
183+
{
184+
return EXIT_FAILURE;
185+
}
186+
187+
// set maxThreads
188+
HardwareContext hwc = cmdline.getHardwareContext();
189+
omp_set_num_threads(hwc.getMaxThreads());
190+
191+
// load input SfMData scene
192+
sfmData::SfMData sfmData;
193+
if(!sfmDataIO::load(sfmData, sfmDataFilename, sfmDataIO::ESfMData::ALL))
194+
{
195+
ALICEVISION_LOG_ERROR("The input SfMData file '" + sfmDataFilename + "' cannot be read.");
196+
return EXIT_FAILURE;
197+
}
198+
199+
std::vector<poseInput> readPoses;
200+
if (!getPosesFromJson(posesFilename, format, readPoses))
201+
{
202+
ALICEVISION_LOG_ERROR("Cannot read the poses");
203+
return EXIT_FAILURE;
204+
}
205+
206+
207+
//Set the pose for all views with frame Ids found in the json file
208+
for (const auto & [id, pview] : sfmData.getViews())
209+
{
210+
for (const auto & rpose : readPoses)
211+
{
212+
if (pview->getFrameId() == rpose.frameId)
213+
{
214+
geometry::Pose3 pose(rpose.T);
215+
sfmData::CameraPose cpose(pose, false);
216+
sfmData.setAbsolutePose(id, cpose);
217+
}
218+
}
219+
}
220+
221+
sfmDataIO::save(sfmData, sfmDataOutputFilename, sfmDataIO::ESfMData::ALL);
222+
223+
return EXIT_SUCCESS;
224+
}

0 commit comments

Comments
 (0)