2727using namespace aliceVision ;
2828namespace po = boost::program_options;
2929
30- struct SurveyObservation
30+ // Internal structures for json reading
31+
32+ struct Position3D
3133{
32- Vec3 point3d;
33- Vec2 point2d;
34+ double x;
35+ double y;
36+ double z;
3437};
3538
36- struct SurveyInput
39+ struct ImagePoint
3740{
38- int frameId;
39- std::vector<SurveyObservation> observations;
41+ int frame;
42+ double x;
43+ double y;
4044};
4145
42- /* *
43- * @brief get a survey from a boost json object (assume the file format is ok)
44- * @param obj the input json object
45- * @param readSurvey the output survey information
46- * @return false if the process failed
47- */
48- bool getSurveyFromJson (const boost::json::object& obj, SurveyInput& readSurvey)
46+ struct Point
4947{
50- readSurvey. observations . clear () ;
51- readSurvey. frameId = boost::json::value_to<IndexT>(obj. at ( " frame_no " )) ;
52-
53- boost::json::value jv = obj. at ( " points " ) ;
54- if (!jv. is_array ())
55- {
56- return false ;
57- }
48+ std::string point_id ;
49+ std::string point_name ;
50+ std::string calc_mode;
51+ std::string survey_mode ;
52+ Position3D calc_3d;
53+ Position3D survey_3d;
54+ std::vector<ImagePoint> image_points ;
55+ };
5856
59- boost::json::array vobj = jv.as_array ();
60- for (auto item : vobj)
61- {
62- const boost::json::object& obj = item.as_object ();
57+ struct Survey
58+ {
59+ std::string pgroup_name;
60+ std::string camera_name;
61+ std::vector<Point> points;
62+ };
6363
64- SurveyObservation obs;
65- obs.point3d .x () = boost::json::value_to<double >(obj.at (" X" ));
66- obs.point3d .y () = boost::json::value_to<double >(obj.at (" Y" ));
67- obs.point3d .z () = boost::json::value_to<double >(obj.at (" Z" ));
64+ Position3D tag_invoke (boost::json::value_to_tag<Position3D>, boost::json::value const & jv)
65+ {
66+ boost::json::object const & obj = jv.as_object ();
67+ return Position3D{
68+ boost::json::value_to<double >(obj.at (" x" )),
69+ boost::json::value_to<double >(obj.at (" y" )),
70+ boost::json::value_to<double >(obj.at (" z" ))
71+ };
72+ }
6873
69- obs.point2d .x () = boost::json::value_to<double >(obj.at (" u" ));
70- obs.point2d .y () = boost::json::value_to<double >(obj.at (" v" ));
74+ ImagePoint tag_invoke (boost::json::value_to_tag<ImagePoint>, boost::json::value const & jv)
75+ {
76+ boost::json::object const & obj = jv.as_object ();
77+ return ImagePoint{
78+ boost::json::value_to<int >(obj.at (" frame" )),
79+ boost::json::value_to<double >(obj.at (" x" )),
80+ boost::json::value_to<double >(obj.at (" y" ))
81+ };
82+ }
7183
72- readSurvey.observations .push_back (obs);
84+ Point tag_invoke (boost::json::value_to_tag<Point>, boost::json::value const & jv)
85+ {
86+ boost::json::object const & obj = jv.as_object ();
87+ Point pt;
88+ pt.point_id = boost::json::value_to<std::string>(obj.at (" point_id" ));
89+ pt.point_name = boost::json::value_to<std::string>(obj.at (" point_name" ));
90+ pt.calc_mode = boost::json::value_to<std::string>(obj.at (" calc_mode" ));
91+ pt.survey_mode = boost::json::value_to<std::string>(obj.at (" survey_mode" ));
92+ pt.calc_3d = boost::json::value_to<Position3D>(obj.at (" calc_3d" ));
93+ pt.survey_3d = boost::json::value_to<Position3D>(obj.at (" survey_3d" ));
94+
95+ boost::json::array const & img_points = obj.at (" image_points" ).as_array ();
96+ for (auto const & ip : img_points)
97+ {
98+ pt.image_points .push_back (boost::json::value_to<ImagePoint>(ip));
7399 }
100+
101+ return pt;
102+ }
74103
75- return true ;
104+ Survey tag_invoke (boost::json::value_to_tag<Survey>, boost::json::value const & jv)
105+ {
106+ boost::json::object const & obj = jv.as_object ();
107+ Survey survey;
108+ survey.pgroup_name = boost::json::value_to<std::string>(obj.at (" pgroup_name" ));
109+ survey.camera_name = boost::json::value_to<std::string>(obj.at (" camera_name" ));
110+
111+ boost::json::array const & points = obj.at (" points" ).as_array ();
112+ for (auto const & pt : points)
113+ {
114+ survey.points .push_back (boost::json::value_to<Point>(pt));
115+ }
116+
117+ return survey;
76118}
77119
78120/* *
79121 * @brief Get a set of surveys from a JSON file (assumes the file format is ok).
80122 * The JSON file contains an array of objects. Each object describes a frameId, and a list of points.
81123 * @param surveyFilename the input JSON filename
82- * @param output the read vector of surveyinput
124+ * @param output a Survey object filled
83125 * @return false if the process failed, true otherwise
84126 */
85- bool getSurveysFromJson (const std::string& surveyFilename, std::vector<SurveyInput> & output)
127+ bool getSurveysFromJson (const std::string& surveyFilename, Survey & output)
86128{
87129 std::ifstream inputfile (surveyFilename);
88130 if (!inputfile.is_open ())
@@ -94,23 +136,7 @@ bool getSurveysFromJson(const std::string& surveyFilename, std::vector<SurveyInp
94136 buffer << inputfile.rdbuf ();
95137 boost::json::value jv = boost::json::parse (buffer.str ());
96138
97- if (!jv.is_array ())
98- {
99- return false ;
100- }
101-
102- boost::json::array vobj = jv.as_array ();
103-
104- for (auto item : vobj)
105- {
106- const boost::json::object& obj = item.as_object ();
107-
108- SurveyInput input;
109- if (getSurveyFromJson (obj, input))
110- {
111- output.push_back (input);
112- }
113- }
139+ output = boost::json::value_to<Survey>(jv);
114140
115141 return true ;
116142}
@@ -164,56 +190,79 @@ int aliceVision_main(int argc, char** argv)
164190 return EXIT_FAILURE;
165191 }
166192
167- auto & landmarks = sfmData.getLandmarks ();
193+ // Get First Frame ID as 3DE gives a [0, nbFrames - 1] frame ID
194+ IndexT minFrameId = std::numeric_limits<IndexT>::max ();
195+ for (const auto & [viewId, pView] : sfmData.getViews ())
196+ {
197+ minFrameId = std::min (minFrameId, pView->getFrameId ());
198+ }
199+ ALICEVISION_LOG_INFO (" Minimal frame id in sfmData is " << minFrameId << " ." );
168200
169- std::vector<SurveyInput> surveys;
170- if (!getSurveysFromJson (surveyFilename, surveys))
201+ // Read survey points in an intermediate structure
202+ Survey survey;
203+ if (!getSurveysFromJson (surveyFilename, survey))
171204 {
172205 ALICEVISION_LOG_ERROR (" The survey file '" + surveyFilename + " ' cannot be read." );
173206 return EXIT_FAILURE;
174207 }
175208
176209 sfmData::SurveyPoints & spoints = sfmData.getSurveyPoints ();
177210
178- // Set the pose for all the views with frame IDs found in the JSON file
179- size_t idFeature = 0 ;
180- for (const auto & [viewId, pView] : sfmData.getViews ())
211+ // Fill up sfmData with the intermediate structure
212+ for (const auto & [viewId, view] : sfmData.getViews ().valueRange ())
181213 {
182- IndexT frameId = pView->getFrameId ();
183-
184- if (!sfmData.isIntrinsicDefined (viewId))
214+ if (!sfmData.isPoseAndIntrinsicDefined (viewId))
185215 {
186216 continue ;
187217 }
188218
189- const auto & intrinsic = sfmData.getIntrinsic (pView-> getIntrinsicId ());
219+ const auto & intrinsic = sfmData.getIntrinsic (view. getIntrinsicId ());
190220
191- for (const auto & survey: surveys)
192- {
193- if (frameId != survey.frameId )
194- {
195- continue ;
196- }
221+ std::vector<sfmData::SurveyPoint> spts;
197222
198- for (const auto & obs : survey.observations )
199- {
200- sfmData::SurveyPoint p;
223+ IndexT frameId = view.getFrameId ();
201224
202- p. survey . x () = obs. point2d . x () * intrinsic. w ();
203- p. survey . y () = intrinsic. h () - 1.0 - (obs. point2d . y () * intrinsic. h () );
225+ // We assume this pose is also coming from 3DE and has not been modified !
226+ geometry::Pose3 pose = sfmData. getPose (view). getTransform ( );
204227
205- p. point3d . x () = obs. point3d . x ();
206- p. point3d . y () = - obs. point3d . y ();
207- p. point3d . z () = - obs. point3d . z () ;
228+ for ( const auto & point: survey. points )
229+ {
230+ sfmData::SurveyPoint p ;
208231
209- spoints[viewId].push_back (p);
232+ p.point3d .x () = point.survey_3d .x ;
233+ p.point3d .y () = -point.survey_3d .y ;
234+ p.point3d .z () = -point.survey_3d .z ;
210235
211- idFeature++;
236+ for (const auto & image_point: point.image_points )
237+ {
238+ // Json frame is the sequence offset starting by 1.
239+ if (frameId != (image_point.frame - 1 + minFrameId))
240+ {
241+ continue ;
242+ }
243+
244+ // From 3DE representation to Alicevision
245+ p.survey .x () = image_point.x * intrinsic.w ();
246+ p.survey .y () = (1.0 - image_point.y ) * intrinsic.h ();
247+
248+ // Compute residual
249+ Vec2 obsEstimated = intrinsic.transformProject (pose, p.point3d .homogeneous (), true );
250+ p.residual .x () = p.survey .x () - obsEstimated.x ();
251+ p.residual .y () = p.survey .y () - obsEstimated.y ();
252+
253+ spts.push_back (p);
254+
255+ ALICEVISION_LOG_INFO (" Found observation for frame " << frameId << " ." );
256+ ALICEVISION_LOG_INFO (" X residual : " << std::abs (p.survey .x () - obsEstimated.x ()));
257+ ALICEVISION_LOG_INFO (" Y residual : " << std::abs (p.survey .y () - obsEstimated.y ()));
212258 }
213259 }
214- }
215260
216- std::cout << sfmData.getSurveyPoints ().size () << std::endl;
261+ if (spts.size () > 0 )
262+ {
263+ spoints[viewId] = spts;
264+ }
265+ }
217266
218267 sfmDataIO::save (sfmData, sfmDataOutputFilename, sfmDataIO::ESfMData::ALL);
219268
0 commit comments