Skip to content

Commit e7fcb0e

Browse files
committed
[sphereDetection] Rewrite writeManualSphereJSON method
There are now two variants of this method: - one that takes the coordinates and radius of the hand-detected spheres - one that takes a JSON file containing shape information for the spheres In both cases, `fillMissingSpheres` can be enabled to fill the location of some spheres for which the data is unavailable with the location of the last detected sphere.
1 parent e19c982 commit e7fcb0e

File tree

3 files changed

+147
-28
lines changed

3 files changed

+147
-28
lines changed

src/aliceVision/sphereDetection/sphereDetection.cpp

Lines changed: 111 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
// Standard libs
1010
#include <iostream>
1111
#include <numeric>
12+
#include <string>
13+
14+
#include <aliceVision/utils/convert.hpp>
1215

1316
// AliceVision image library
1417
#include <aliceVision/image/Image.hpp>
@@ -236,10 +239,6 @@ void sphereDetection(const sfmData::SfMData& sfmData, Ort::Session& session, fs:
236239
}
237240
}
238241

239-
240-
241-
242-
243242
// Main tree
244243
bpt::ptree fileTree;
245244
fillShapeTree(fileTree, spheresTree);
@@ -248,26 +247,55 @@ void sphereDetection(const sfmData::SfMData& sfmData, Ort::Session& session, fs:
248247
bpt::write_json(outputPath.string(), fileTree);
249248
}
250249

251-
void writeManualSphereJSON(const sfmData::SfMData& sfmData, const std::array<float, 3>& sphereParam, fs::path outputPath)
250+
bool writeManualSphereJSON(const sfmData::SfMData& sfmData,
251+
const std::vector<std::string>& x,
252+
const std::vector<std::string>& y,
253+
const std::vector<std::string>& radius,
254+
fs::path outputPath,
255+
bool fillMissingSpheres)
252256
{
257+
auto xValues = aliceVision::utils::dictStringToStringMap(x);
258+
auto yValues = aliceVision::utils::dictStringToStringMap(y);
259+
auto radiusValues = aliceVision::utils::dictStringToStringMap(radius);
260+
253261
// Spheres tree
254262
bpt::ptree spheresTree;
255263

256264
for (auto& viewID : sfmData.getViews())
257265
{
258-
ALICEVISION_LOG_DEBUG("View Id: " << viewID);
259-
266+
ALICEVISION_LOG_DEBUG("View ID: " << viewID);
260267
const std::string sphereName = std::to_string(viewID.second->getViewId());
261268

269+
std::vector<float> sphereParams;
270+
auto pos = xValues.find(sphereName);
271+
if (pos == xValues.end())
272+
{
273+
ALICEVISION_LOG_INFO("Sphere shape for view ID " << sphereName << " not found.");
274+
275+
if (fillMissingSpheres)
276+
{
277+
ALICEVISION_LOG_INFO("Using sphere position from view ID " << xValues.rbegin()->first << ".");
278+
sphereParams = {std::stof(xValues.rbegin()->second), std::stof(yValues.rbegin()->second), std::stof(radiusValues.rbegin()->second)};
279+
}
280+
}
281+
else
282+
{
283+
ALICEVISION_LOG_DEBUG("Sphere shape for view ID " << sphereName << " found.");
284+
sphereParams = {std::stof(xValues.at(sphereName)), std::stof(yValues.at(sphereName)), std::stof(radiusValues.at(sphereName))};
285+
}
286+
262287
// Create an unnamed node containing the sphere
263-
bpt::ptree sphereNode;
264-
sphereNode.put("center.x", sphereParam[0]);
265-
sphereNode.put("center.y", sphereParam[1]);
266-
sphereNode.put("radius", sphereParam[2]);
267-
sphereNode.put("type", "matte");
268-
269-
// Add sphere node to spheres tree
270-
spheresTree.add_child(sphereName, sphereNode);
288+
if (!sphereParams.empty())
289+
{
290+
bpt::ptree sphereNode;
291+
sphereNode.put("center.x", sphereParams[0]);
292+
sphereNode.put("center.y", sphereParams[1]);
293+
sphereNode.put("radius", sphereParams[2]);
294+
sphereNode.put("type", "matte");
295+
296+
// Add sphere node to spheres tree
297+
spheresTree.add_child(sphereName, sphereNode);
298+
}
271299
}
272300

273301
// Shapes tree
@@ -296,6 +324,74 @@ void writeManualSphereJSON(const sfmData::SfMData& sfmData, const std::array<flo
296324

297325
// Write JSON
298326
bpt::write_json(outputPath.string(), fileTree);
327+
328+
return true;
329+
}
330+
331+
bool writeManualSphereJSON(const sfmData::SfMData& sfmData, const std::string& sphereFile, const std::string& outputPath, bool fillMissingSpheres)
332+
{
333+
if (!fillMissingSpheres)
334+
{
335+
// Copy the file as is if since there is no need to check on missing spheres
336+
fs::copy_file(sphereFile, outputPath);
337+
return true;
338+
}
339+
340+
// Main tree
341+
bpt::ptree fileTree;
342+
343+
// Read the json file and initialize the tree
344+
bpt::read_json(sphereFile, fileTree);
345+
346+
// Spheres tree
347+
bpt::ptree spheresTree;
348+
349+
// Initialize spheres tree
350+
const auto shapesTreeOpt = fileTree.get_child_optional("shapes");
351+
if (shapesTreeOpt && !shapesTreeOpt->empty())
352+
{
353+
const auto& firstShapeTree = shapesTreeOpt->begin()->second;
354+
spheresTree = firstShapeTree.get_child("observations");
355+
}
356+
else
357+
{
358+
ALICEVISION_THROW_ERROR("Cannot find sphere detection data in '" << sphereFile << "'.");
359+
}
360+
361+
std::string lastSphereViewID = spheresTree.rbegin()->first;
362+
std::vector<float> sphereParams = {spheresTree.rbegin()->second.get("center.x", 0.0f),
363+
spheresTree.rbegin()->second.get("center.y", 0.0f),
364+
spheresTree.rbegin()->second.get("radius", 0.0f)};
365+
366+
ALICEVISION_LOG_INFO("Got last known sphere position: " << lastSphereViewID);
367+
368+
for (auto& viewID : sfmData.getViews())
369+
{
370+
ALICEVISION_LOG_DEBUG("View ID: " << viewID);
371+
const std::string sphereName = std::to_string(viewID.second->getViewId());
372+
373+
auto sphereExists = (spheresTree.get_child_optional(sphereName)).is_initialized();
374+
if (!sphereExists)
375+
{
376+
ALICEVISION_LOG_INFO("Sphere exists");
377+
bpt::ptree sphereNode;
378+
sphereNode.put("center.x", sphereParams[0]);
379+
sphereNode.put("center.y", sphereParams[1]);
380+
sphereNode.put("radius", sphereParams[2]);
381+
sphereNode.put("type", "matte");
382+
383+
// Add sphere node to spheres tree
384+
spheresTree.add_child(sphereName, sphereNode);
385+
}
386+
}
387+
388+
fileTree.clear();
389+
fillShapeTree(fileTree, spheresTree);
390+
391+
// Write JSON
392+
bpt::write_json(outputPath, fileTree);
393+
394+
return true;
299395
}
300396

301397
} // namespace sphereDetection

src/aliceVision/sphereDetection/sphereDetection.hpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,33 @@ void modelExplore(Ort::Session& session);
5454
void sphereDetection(const sfmData::SfMData& sfmData, Ort::Session& session, fs::path outputPath, const float minScore);
5555

5656
/**
57-
* @brief Write JSON for a hand-detected sphere
57+
* @brief Write a JSON file containing the shapes for the hand-detected spheres.
5858
*
59-
* @param sfmData Input .sfm file
60-
* @param sphereParam Parameters of the hand-detected sphere
61-
* @return outputPath Path to the JSON file
59+
* @param sfmData Input SfMData.
60+
* @param x Flat vector of strings containing "view ID":"x-coordinate" pairs for the hand-detected spheres.
61+
* @param y Flat vector of strings containing "view ID":"y-coordinate" pairs for the hand-detected spheres.
62+
* @param radius Flat vector of strings containing "view ID":"radius" pairs for the hand-detected spheres.
63+
* @param outputPath Path to the output JSON file.
64+
* @param fillMissingSpheres If enabled, view IDs for which no sphere has been hand-detected will use the location of the last detected sphere.
65+
* @return True if the JSON file was correctly written, False otherwise.
6266
*/
63-
void writeManualSphereJSON(const sfmData::SfMData& sfmData, const std::array<float, 3>& sphereParam, fs::path outputPath);
67+
bool writeManualSphereJSON(const sfmData::SfMData& sfmData,
68+
const std::vector<std::string>& x,
69+
const std::vector<std::string>& y,
70+
const std::vector<std::string>& radius,
71+
fs::path outputPath,
72+
bool fillMissingSpheres);
73+
74+
/**
75+
* @brief Write a JSON file containing the shapes for the spheres, based on a provided JSON file that contains sphere locations.
76+
*
77+
* @param sfmData Input SfMData.
78+
* @param sphereFile A JSON file containing the locations of the detected spheres.
79+
* @param outputPath Path to the output JSON file.
80+
* @param fillMissingSpheres If enabled, view IDs for which no sphere has been hand-detected will use the location of the last detected sphere.
81+
* @return True if the JSON file was correctly written, False otherwise.
82+
*/
83+
bool writeManualSphereJSON(const sfmData::SfMData& sfmData, const std::string& sphereFile, const std::string& outputPath, bool fillMissingSpheres);
6484

6585
} // namespace sphereDetection
6686
} // namespace aliceVision

src/software/pipeline/main_sphereDetection.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ int aliceVision_main(int argc, char** argv)
5050
std::vector<std::string> x, y, radius;
5151
std::string sphereFile;
5252
bool fillMissingSpheres;
53-
Eigen::Vector2f sphereCenter(0, 0);
54-
double sphereRadius = 1.0;
5553

5654
// clang-format off
5755
po::options_description requiredParams("Required parameters");
@@ -120,12 +118,17 @@ int aliceVision_main(int argc, char** argv)
120118
}
121119
else
122120
{
123-
std::array<float, 3> sphereParam;
124-
sphereParam[0] = sphereCenter(0);
125-
sphereParam[1] = sphereCenter(1);
126-
sphereParam[2] = sphereRadius;
127-
128-
sphereDetection::writeManualSphereJSON(sfmData, sphereParam, fsOutputPath);
121+
if (sphereFile.empty())
122+
{
123+
sphereDetection::writeManualSphereJSON(sfmData, x, y, radius, fsOutputPath, fillMissingSpheres);
124+
}
125+
else
126+
{
127+
if (!sphereDetection::writeManualSphereJSON(sfmData, sphereFile, outputPath, fillMissingSpheres))
128+
{
129+
return EXIT_FAILURE;
130+
}
131+
}
129132
}
130133

131134
ALICEVISION_LOG_INFO("Task done in (s): " + std::to_string(timer.elapsed()));

0 commit comments

Comments
 (0)