33#include "DGtal/base/Common.h"
34#include "DGtal/base/BasicFunctors.h"
35#include "DGtal/helpers/StdDefs.h"
36#include "DGtal/io/readers/GenericReader.h"
37#include "DGtal/io/viewers/PolyscopeViewer.h"
38#include <DGtal/images/ImageContainerBySTLVector.h>
40#include "DGtal/io/Color.h"
41#include "DGtal/images/ImageLinearCellEmbedder.h"
42#include "DGtal/images/ImageSelector.h"
43#include <DGtal/base/ConstAlias.h>
44#include <DGtal/kernel/BasicPointFunctors.h>
45#include <DGtal/topology/helpers/Surfaces.h>
46#include <DGtal/io/colormaps/GradientColorMap.h>
47#include <DGtal/io/colormaps/GrayscaleColorMap.h>
48#include <DGtal/topology/SetOfSurfels.h>
49#include <DGtal/topology/DigitalSurface.h>
50#include "DGtal/shapes/TriangulatedSurface.h"
51#include "DGtal/shapes/MeshHelpers.h"
104static int posSliceZ = 0;
105static int maxPosSliceZ = 0;
106static Z2i::Point imagePtInf;
107static Z2i::Point imagePtSup;
108static float startTime = 0.0;
109static bool showText =
true;
110static bool show_ui =
false;
111static string message =
"Press W to display interface";
114template<
typename TImage2D,
typename TPo
int3D >
115struct Image3DPredicatFrom2DImage{
116 typedef TPoint3D Point3D;
120 Image3DPredicatFrom2DImage(DGtal::ConstAlias<TImage2D> anImage,
double aScale):myImageRef(anImage),
124 bool operator()(
const Point3D &aPoint)
const {
125 functors::Projector<SpaceND<2, typename TImage2D::Integer> > projXY;
126 return (*myImageRef)(projXY(aPoint))*myScale >= aPoint[2];
128 CountedConstPtrOrConstPtr<TImage2D> myImageRef;
134polyscope::SurfaceMesh *
135initSlice(
string name,
const Z2i::Point &ptLow,
const Z2i::Point &ptUp) {
136 polyscope::SurfaceMesh * res;
137 std::vector<glm::vec3> vertices = {{ptLow[0], ptLow[1], 0},
138 {ptUp[0], ptLow[1], 0},
139 {ptUp[0], ptUp[1], 0},
140 {ptLow[0], ptUp[1], 0}};
142 std::vector<std::vector<size_t>> faces = {{0, 1, 2, 3}};
143 res = polyscope::registerSurfaceMesh(name, vertices, faces);
144 res->setSurfaceColor({0.2, 0.2, .9});
145 res->setTransparency(0.5);
148void updateSlice(
string name,
const Z2i::Point &ptLow,
const Z2i::Point &ptUp){
149 polyscope::SurfaceMesh * sm = polyscope::getSurfaceMesh(name);
150 std::vector<glm::vec3> vertices = {{ptLow[0], ptLow[1], posSliceZ},
151 {ptUp[0], ptLow[1], posSliceZ},
152 {ptUp[0], ptUp[1], posSliceZ},
153 {ptLow[0], ptUp[1], posSliceZ}};
154 sm->updateVertexPositions(vertices);
155 stringstream ss; ss <<
"Slice position: "; ss << posSliceZ;
157 startTime = ImGui::GetTime();
163void callbackFaceID() {
164 ImGuiIO& io = ImGui::GetIO();
165 if (ImGui::IsKeyPressed(ImGuiKey_W))
169 if (ImGui::IsKeyPressed(ImGuiKey_UpArrow))
171 if (posSliceZ <= maxPosSliceZ) {
173 updateSlice(
"sliceplane", imagePtInf, imagePtSup);
176 if (ImGui::IsKeyPressed(ImGuiKey_DownArrow))
180 updateSlice(
"sliceplane", imagePtInf, imagePtSup);
186 float totalWidth = ImGui::GetContentRegionAvail().x;
187 float sliderWidth = (totalWidth - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
188 ImGui::Begin(
"Editing tools");
189 ImGui::Text(
"Slice positio, :");
190 ImGui::PushItemWidth(sliderWidth);
191 if (ImGui::SliderInt(
"##z axis", &posSliceZ, 0,
192 maxPosSliceZ,
"slice %i"))
194 updateSlice(
"sliceplane", imagePtInf, imagePtSup);
198 ImGui::PopItemWidth();
200 ImGui::Text(
"Polyscope interface:");
202 if (ImGui::Button(
"show "))
204 polyscope::options::buildGui=
true;
207 if (ImGui::Button(
"hide"))
209 polyscope::options::buildGui=
false;
212 ImGui::Text(
"Keys:");
213 ImGui::Text(
"UP/DOWN arrow : Move slice");
214 ImGui::Text(
"W: Hide/Show this panel");
222 ImDrawList* drawList = ImGui::GetBackgroundDrawList();
223 drawList->AddText(pos, IM_COL32(25, 25, 255, 255), message.c_str());
224 if (ImGui::GetTime() - startTime > 10.0 )
232typedef ImageSelector < Domain, int>::Type Image;
236int main(
int argc,
char** argv )
241 std::string inputFileName;
243 bool colorMap {
false};
244 std::string colorTextureImage;
245 app.description(
"Displays 2D image as heightmap by using QGLviewer.\n Exemple of use: visualisation/3dHeightMapViewer ${DGtal}/examples/samples/church.pgm -s 0.2");
247 app.add_option(
"-i,--input,1", inputFileName,
"2d input image representing the height map (given as grayscape image cast into 8 bits)." )
249 ->check(CLI::ExistingFile);
250 app.add_option(
"--scale,-s",scale,
"set the scale of the maximal level. (default 1.0)");
251 app.add_flag(
"--colorMap,-c", colorMap,
"define the heightmap color with a pre-defined colormap (GradientColorMap)");
252 app.add_option(
"--colorTextureImage,-t", colorTextureImage,
"define the heightmap color from a given color image (32 bits image).");
256 app.get_formatter()->column_width(40);
257 CLI11_PARSE(app, argc, argv);
261 typedef DGtal::ImageContainerBySTLVector<Z2i::Domain, unsigned char> Image2DG ;
262 typedef DGtal::ImageContainerBySTLVector<Z2i::Domain, unsigned int> Image2DCol ;
264 Image2DG image = GenericReader<Image2DG>::import( inputFileName );
265 Image2DCol imageTexture(image.domain());
266 Image2DG::Value maxHeight = *std::max_element(image.begin(), image.end()) * scale;
267 trace.info()<<
"Max height from scale:" << maxHeight << std::endl;
268 GradientColorMap<Image2DG::Value,CMAP_JET> gradientShade( 0, std::numeric_limits<Image2DG::Value>::max());
269 GrayscaleColorMap<Image2DG::Value> grayShade(0, std::numeric_limits<Image2DG::Value>::max());
271 if(colorTextureImage !=
""){
272 imageTexture = GenericReader<Image2DCol>::import( colorTextureImage );
275 imagePtInf = Z2i::Point(image.domain().lowerBound()[0],
276 image.domain().lowerBound()[1]);
278 imagePtSup = Z2i::Point(image.domain().upperBound()[0],
279 image.domain().upperBound()[1]);
280 maxPosSliceZ = maxHeight;
283 s <<
"3dHeightMapViewer - DGtalTools: ";
284 string name = inputFileName.substr(inputFileName.find_last_of(
"/")+1,inputFileName.size()) ;
285 s <<
" " << name <<
" (W key to display settings)";
286 polyscope::options::programName = s.str();
287 polyscope::options::buildGui=
false;
288 polyscope::options::groundPlaneMode = polyscope::GroundPlaneMode::None;
289 polyscope::view::setNavigateStyle(polyscope::NavigateStyle::Free);
291 PolyscopeViewer viewer;
292 bool intAdjacency =
true;
293 polyscope::SurfaceMesh *slicePlane;
294 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
295 typedef KSpace::SurfelSet SurfelSet;
296 typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels;
297 typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface;
299 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
300 MySurfelAdjacency surfAdj( intAdjacency );
304 K.init(Z3i::Point(0,0,0),Z3i::Point(image.domain().upperBound()[0], image.domain().upperBound()[1], maxHeight+1),
true);
306 Image3DPredicatFrom2DImage<Image2DG, Z3i::Point> image3Dpredicate(image, scale);
307 trace.info() <<
"Constructing boundary... ";
308 MySetOfSurfels theSetOfSurfels( K, surfAdj );
310 Surfaces<KSpace>::sMakeBoundary( theSetOfSurfels.surfelSet(),
311 K, image3Dpredicate, Z3i::Point(0,0,0),
312 Z3i::Point(image.domain().upperBound()[0], image.domain().upperBound()[1], maxHeight+1) );
313 trace.info() <<
"[done]"<< std::endl;
315 MyDigitalSurface digSurf( theSetOfSurfels );
316 trace.info() <<
"Digital surface has " << digSurf.size() <<
" surfels."
319 trace.beginBlock(
"Making triangulated surface. " );
320 typedef CanonicEmbedder< Space > TrivialEmbedder;
321 typedef ImageLinearCellEmbedder< KSpace,Image , TrivialEmbedder > CellEmbedder;
322 typedef CellEmbedder::Value RealPoint;
323 typedef TriangulatedSurface< RealPoint > TriMesh;
324 typedef Mesh< RealPoint > ViewMesh;
325 typedef std::map< MyDigitalSurface::Vertex, TriMesh::Index > VertexMap;
328 TrivialEmbedder trivialEmbedder;
329 CellEmbedder cellEmbedder;
330 Image::Domain d (Z3i::Point(0,0,0),Z3i::Point(image.domain().upperBound()[0], image.domain().upperBound()[1], maxHeight+1));
332 for (
auto p : imageE.domain()){
333 imageE.setValue(p, image3Dpredicate(p));
335 cellEmbedder.init(K, imageE, trivialEmbedder, 0);
337 MeshHelpers::digitalSurface2DualTriangulatedSurface
338 ( digSurf, cellEmbedder, trimesh, vmap );
339 MeshHelpers::triangulatedSurface2Mesh( trimesh, viewmesh );
340 trace.info() <<
"Mesh has " << viewmesh.nbVertex()
341 <<
" vertices and " << viewmesh.nbFaces() <<
" faces." << std::endl;
343 for (
unsigned int i = 0; i < viewmesh.nbFaces(); i++){
344 auto b = viewmesh.getFaceBarycenter(i);
345 auto bp = Z2i::Point(b[0], b[1]);
346 auto val = image(bp);
347 if (image.domain().isInside(bp)){
349 viewmesh.setFaceColor(i,gradientShade(val));
350 }
else if (colorTextureImage !=
"") {
351 viewmesh.setFaceColor(i, DGtal::Color(imageTexture(bp)));
353 viewmesh.setFaceColor(i, grayShade(val));
358 slicePlane = initSlice(
"sliceplane", image.domain().lowerBound(), image.domain().upperBound());
360 viewer.drawColor(Color(150,0,0,254));
362 polyscope::state::userCallback = callbackFaceID;