Skip to content

Commit 5869c98

Browse files
authored
Merge pull request #1752 from alicevision/dev/generateDepth
depthmap rendering
2 parents 27f250b + d3f7f4c commit 5869c98

File tree

6 files changed

+351
-3
lines changed

6 files changed

+351
-3
lines changed

src/aliceVision/mesh/MeshIntersection.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ bool MeshIntersection::initialize(const std::string & pathToModel)
2828
return true;
2929
}
3030

31-
bool MeshIntersection::peek(Vec3 & output, const camera::IntrinsicBase & intrinsic, const Vec2 & imageCoords)
31+
bool MeshIntersection::peekPoint(Vec3 & output, const camera::IntrinsicBase & intrinsic, const Vec2 & imageCoords)
3232
{
3333
const Vec3 posCamera = _pose.center();
3434
const Vec3 wdir = intrinsic.backproject(imageCoords, true, _pose, 1.0);
@@ -58,5 +58,35 @@ bool MeshIntersection::peek(Vec3 & output, const camera::IntrinsicBase & intrins
5858
return true;
5959
}
6060

61+
bool MeshIntersection::peekNormal(Vec3 & output, const camera::IntrinsicBase & intrinsic, const Vec2 & imageCoords)
62+
{
63+
const Vec3 posCamera = _pose.center();
64+
const Vec3 wdir = intrinsic.backproject(imageCoords, true, _pose, 1.0);
65+
const Vec3 dir = (wdir - posCamera).normalized();
66+
67+
//Create geogram ray from alicevision ray
68+
GEO::Ray ray;
69+
ray.origin.x = posCamera.x();
70+
ray.origin.y = -posCamera.y();
71+
ray.origin.z = -posCamera.z();
72+
ray.direction.x = dir.x();
73+
ray.direction.y = -dir.y();
74+
ray.direction.z = -dir.z();
75+
76+
GEO::MeshFacetsAABB::Intersection intersection;
77+
if (!_aabb.ray_nearest_intersection(ray, intersection))
78+
{
79+
return false;
80+
}
81+
82+
const GEO::vec3 n = GEO::normalize(intersection.N);
83+
84+
output.x() = n.x;
85+
output.y() = -n.y;
86+
output.z() = -n.z;
87+
88+
return true;
89+
}
90+
6191
}
6292
}

src/aliceVision/mesh/MeshIntersection.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,16 @@ class MeshIntersection
3737
* @param imageCoords the camera observation we want to use to estimate its 'depth'
3838
* @return true if the ray intersect the mesh.
3939
*/
40-
bool peek(Vec3 & output, const camera::IntrinsicBase & intrinsic, const Vec2 & imageCoords);
40+
bool peekPoint(Vec3 & output, const camera::IntrinsicBase & intrinsic, const Vec2 & imageCoords);
41+
42+
/**
43+
* @brief peek a point and get its normal on the mesh given a input camera observation
44+
* @param output the output measured normal
45+
* @param intrinsic the camera intrinsics to use for ray computation
46+
* @param imageCoords the camera observation we want to use to estimate its 'depth'
47+
* @return true if the ray intersect the mesh.
48+
*/
49+
bool peekNormal(Vec3 & output, const camera::IntrinsicBase & intrinsic, const Vec2 & imageCoords);
4150

4251
private:
4352
GEO::Mesh _mesh;

src/software/utils/CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,32 @@ if(ALICEVISION_BUILD_MVS)
399399
Geogram::geogram
400400
${Boost_LIBRARIES}
401401
)
402+
403+
# Rendering of depthmaps
404+
alicevision_add_software(aliceVision_depthMapRendering
405+
SOURCE main_depthMapRendering.cpp
406+
FOLDER ${FOLDER_SOFTWARE_UTILS}
407+
LINKS aliceVision_system
408+
aliceVision_cmdline
409+
aliceVision_feature
410+
aliceVision_mesh
411+
aliceVision_sfm
412+
aliceVision_sfmData
413+
aliceVision_sfmDataIO
414+
)
415+
416+
# Rendering of normalmaps
417+
alicevision_add_software(aliceVision_normalMapRendering
418+
SOURCE main_normalMapRendering.cpp
419+
FOLDER ${FOLDER_SOFTWARE_UTILS}
420+
LINKS aliceVision_system
421+
aliceVision_cmdline
422+
aliceVision_feature
423+
aliceVision_mesh
424+
aliceVision_sfm
425+
aliceVision_sfmData
426+
aliceVision_sfmDataIO
427+
)
402428

403429
# Mesh Remove Unseen Faces
404430
alicevision_add_software(aliceVision_meshRemoveUnseenFaces
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
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/sfmData/SfMData.hpp>
8+
#include <aliceVision/sfmDataIO/sfmDataIO.hpp>
9+
#include <aliceVision/system/Logger.hpp>
10+
#include <aliceVision/cmdline/cmdline.hpp>
11+
#include <aliceVision/system/main.hpp>
12+
#include <aliceVision/image/Image.hpp>
13+
#include <aliceVision/mesh/MeshIntersection.hpp>
14+
15+
#include <filesystem>
16+
17+
18+
19+
// These constants define the current software version.
20+
// They must be updated when the command line is changed.
21+
#define ALICEVISION_SOFTWARE_VERSION_MAJOR 1
22+
#define ALICEVISION_SOFTWARE_VERSION_MINOR 0
23+
24+
using namespace aliceVision;
25+
26+
namespace po = boost::program_options;
27+
28+
int aliceVision_main(int argc, char** argv)
29+
{
30+
// command-line parameters
31+
std::string sfmDataFilename;
32+
std::string meshFilename;
33+
std::string outputDirectory;
34+
35+
// clang-format off
36+
po::options_description requiredParams("Required parameters");
37+
requiredParams.add_options()
38+
("input,i", po::value<std::string>(&sfmDataFilename)->required(),
39+
"SfMData file.")
40+
("mesh,i", po::value<std::string>(&meshFilename)->required(),
41+
"mesh file.")
42+
("output,o", po::value<std::string>(&outputDirectory)->required(),
43+
"Output directory for depthmaps.");
44+
// clang-format on
45+
46+
CmdLine cmdline("AliceVision depthmapRendering");
47+
cmdline.add(requiredParams);
48+
if (!cmdline.execute(argc, argv))
49+
{
50+
return EXIT_FAILURE;
51+
}
52+
53+
// set maxThreads
54+
HardwareContext hwc = cmdline.getHardwareContext();
55+
omp_set_num_threads(hwc.getMaxThreads());
56+
57+
std::filesystem::path pathOutputDirectory(outputDirectory);
58+
59+
// Load input scene
60+
sfmData::SfMData sfmData;
61+
if (!sfmDataIO::load(sfmData, sfmDataFilename, sfmDataIO::ESfMData::ALL))
62+
{
63+
ALICEVISION_LOG_ERROR("The input SfMData file '" << sfmDataFilename << "' cannot be read");
64+
return EXIT_FAILURE;
65+
}
66+
67+
//Load mesh in the mesh intersection object
68+
ALICEVISION_LOG_INFO("Loading mesh");
69+
mesh::MeshIntersection mi;
70+
if (!mi.initialize(meshFilename))
71+
{
72+
return EXIT_FAILURE;
73+
}
74+
75+
for (const auto & [index, view] : sfmData.getViews())
76+
{
77+
if (!sfmData.isPoseAndIntrinsicDefined(index))
78+
{
79+
continue;
80+
}
81+
82+
83+
ALICEVISION_LOG_INFO("Generating depthmap for view " << index);
84+
85+
//Retrieve metadatas for copying in the depthmap
86+
oiio::ParamValueList metadata = image::readImageMetadata(view->getImageInfo()->getImagePath());
87+
88+
const auto & intrinsic = sfmData.getIntrinsicSharedPtr(*view);
89+
std::shared_ptr<camera::Pinhole> pinHole = std::dynamic_pointer_cast<camera::Pinhole>(intrinsic);
90+
if (!pinHole)
91+
{
92+
ALICEVISION_LOG_INFO("This view is not a pinhole camera. Ignoring.");
93+
continue;
94+
}
95+
96+
const auto pose = sfmData.getPose(*view).getTransform();
97+
98+
Vec3 center = pose.center();
99+
100+
mi.setPose(pose);
101+
102+
int w = view->getImageInfo()->getWidth();
103+
int h = view->getImageInfo()->getHeight();
104+
105+
image::Image<float> image(w, h, 0.0f);
106+
image::Image<unsigned char> mask(w, h, 0);
107+
108+
#pragma omp parallel for
109+
for (int i = 0; i < h; i++)
110+
{
111+
for (int j = 0; j < w; j++)
112+
{
113+
Vec2 pt;
114+
pt.x() = j;
115+
pt.y() = i;
116+
117+
//Find the 3d point
118+
//Which is the intersection of the ray and the mesh
119+
Vec3 pt3d;
120+
if (!mi.peekPoint(pt3d, *intrinsic, pt))
121+
{
122+
continue;
123+
}
124+
125+
//Assume depth map contains length to camera center
126+
double length = (pt3d - center).norm();
127+
image(i, j) = length;
128+
mask(i, j) = 255;
129+
}
130+
}
131+
132+
133+
//Store metadata used for 3D Viewer
134+
Eigen::Matrix<double, 3, 3, Eigen::RowMajor> iCamArr = pose.rotation().transpose() * pinHole->K().inverse();
135+
metadata.push_back(oiio::ParamValue("AliceVision:CArr", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::VEC3), 1, &center[0]));
136+
metadata.push_back(oiio::ParamValue("AliceVision:iCamArr", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX33), 1, iCamArr.data()));
137+
138+
139+
//Store depthmap
140+
auto path = (pathOutputDirectory / (std::to_string(index) + "_depthMap.exr"));
141+
ALICEVISION_LOG_INFO("Ouput depthmap to " << path);
142+
image::writeImage(path.string(), image, image::ImageWriteOptions(), metadata);
143+
144+
//Store mask
145+
path = (pathOutputDirectory / (std::to_string(index) + "_mask.exr"));
146+
ALICEVISION_LOG_INFO("Ouput mask to " << path);
147+
image::writeImage(path.string(), mask, image::ImageWriteOptions(), metadata);
148+
}
149+
150+
return EXIT_SUCCESS;
151+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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/sfmData/SfMData.hpp>
8+
#include <aliceVision/sfmDataIO/sfmDataIO.hpp>
9+
#include <aliceVision/system/Logger.hpp>
10+
#include <aliceVision/cmdline/cmdline.hpp>
11+
#include <aliceVision/system/main.hpp>
12+
#include <aliceVision/image/Image.hpp>
13+
#include <aliceVision/mesh/MeshIntersection.hpp>
14+
15+
#include <filesystem>
16+
17+
18+
19+
// These constants define the current software version.
20+
// They must be updated when the command line is changed.
21+
#define ALICEVISION_SOFTWARE_VERSION_MAJOR 1
22+
#define ALICEVISION_SOFTWARE_VERSION_MINOR 0
23+
24+
using namespace aliceVision;
25+
26+
namespace po = boost::program_options;
27+
28+
int aliceVision_main(int argc, char** argv)
29+
{
30+
// command-line parameters
31+
std::string sfmDataFilename;
32+
std::string meshFilename;
33+
std::string outputDirectory;
34+
35+
// clang-format off
36+
po::options_description requiredParams("Required parameters");
37+
requiredParams.add_options()
38+
("input,i", po::value<std::string>(&sfmDataFilename)->required(),
39+
"SfMData file.")
40+
("mesh,i", po::value<std::string>(&meshFilename)->required(),
41+
"mesh file.")
42+
("output,o", po::value<std::string>(&outputDirectory)->required(),
43+
"Output directory for depthmaps.");
44+
// clang-format on
45+
46+
CmdLine cmdline("AliceVision normalmapRendering");
47+
cmdline.add(requiredParams);
48+
if (!cmdline.execute(argc, argv))
49+
{
50+
return EXIT_FAILURE;
51+
}
52+
53+
// set maxThreads
54+
HardwareContext hwc = cmdline.getHardwareContext();
55+
omp_set_num_threads(hwc.getMaxThreads());
56+
57+
std::filesystem::path pathOutputDirectory(outputDirectory);
58+
59+
// Load input scene
60+
sfmData::SfMData sfmData;
61+
if (!sfmDataIO::load(sfmData, sfmDataFilename, sfmDataIO::ESfMData::ALL))
62+
{
63+
ALICEVISION_LOG_ERROR("The input SfMData file '" << sfmDataFilename << "' cannot be read");
64+
return EXIT_FAILURE;
65+
}
66+
67+
//Load mesh in the mesh intersection object
68+
ALICEVISION_LOG_INFO("Loading mesh");
69+
mesh::MeshIntersection mi;
70+
if (!mi.initialize(meshFilename))
71+
{
72+
return EXIT_FAILURE;
73+
}
74+
75+
for (const auto & [index, view] : sfmData.getViews())
76+
{
77+
if (!sfmData.isPoseAndIntrinsicDefined(index))
78+
{
79+
continue;
80+
}
81+
82+
83+
ALICEVISION_LOG_INFO("Generating depthmap for view " << index);
84+
85+
//Retrieve metadatas for copying in the depthmap
86+
oiio::ParamValueList metadata = image::readImageMetadata(view->getImageInfo()->getImagePath());
87+
88+
const auto & intrinsic = sfmData.getIntrinsicSharedPtr(*view);
89+
const auto pose = sfmData.getPose(*view);
90+
91+
Vec3 center = pose.getTransform().center();
92+
93+
mi.setPose(pose.getTransform());
94+
95+
int w = view->getImageInfo()->getWidth();
96+
int h = view->getImageInfo()->getHeight();
97+
image::Image<image::RGBfColor> image(w, h, image::RGBfColor(0.0f,0.0f,0.0f));
98+
99+
#pragma omp parallel for
100+
for (int i = 0; i < h; i++)
101+
{
102+
for (int j = 0; j < w; j++)
103+
{
104+
Vec2 pt;
105+
pt.x() = j;
106+
pt.y() = i;
107+
108+
//Find the 3d point
109+
//Which is the intersection of the ray and the mesh
110+
//And get its normal
111+
Vec3 normal;
112+
if (!mi.peekNormal(normal, *intrinsic, pt))
113+
{
114+
continue;
115+
}
116+
117+
Vec3 cnormal = pose.getTransform().rotation() * normal;
118+
119+
auto & rgb = image(i, j);
120+
rgb.r() = cnormal.x();
121+
rgb.g() = cnormal.y();
122+
rgb.b() = cnormal.z();
123+
}
124+
}
125+
126+
auto path = (pathOutputDirectory / (std::to_string(index) + "_normalMap.exr"));
127+
ALICEVISION_LOG_INFO("Ouput to " << path);
128+
image::writeImage(path.string(), image, image::ImageWriteOptions(), metadata);
129+
}
130+
131+
return EXIT_SUCCESS;
132+
}

src/software/utils/main_sfmTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ bool parseLineUp(const std::string & lineUpFilename, const std::string & tracksF
409409
const Vec2 & imageCoords = trackitem.coords;
410410

411411
Vec3 pt3d;
412-
if (!meshIntersection.peek(pt3d, *intrinsic, imageCoords))
412+
if (!meshIntersection.peekPoint(pt3d, *intrinsic, imageCoords))
413413
{
414414
continue;
415415
}

0 commit comments

Comments
 (0)