Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there a way to write the border of a digital set to an OBJ? #1409

Closed
psarahdactyl opened this issue Apr 18, 2019 · 15 comments
Closed

Is there a way to write the border of a digital set to an OBJ? #1409

psarahdactyl opened this issue Apr 18, 2019 · 15 comments

Comments

@psarahdactyl
Copy link

I want to avoid marching cube type artifacts in my obj files, where some of the surface is missing on the boundaries of the voxel grid. I get these when I make a DigitalSurface or a TrianglulatedSurface from a BinaryImage of my DigitalSet.

In this example, which I've gotten running on my own DigitalSet, I want to write out just the border voxels to an OBJ. Is there a way to do this?

@copyme
Copy link
Member

copyme commented Apr 18, 2019

@psarahdactyl If you want to write the border points in cases like in one from the example you refer to then you can use something like this

#include <iostream>
#include "DGtal/base/Common.h"

#include "DGtal/io/readers/VolReader.h"
#include "DGtal/io/Color.h"
#include "DGtal/images/ImageSelector.h"
#include "DGtal/helpers/StdDefs.h"
#include "ConfigExamples.h"
#include "DGtal/io/boards/Board3D.h"

///////////////////////////////////////////////////////////////////////////////

using namespace std;
using namespace DGtal;

///////////////////////////////////////////////////////////////////////////////

int main( int argc, char** argv )
{
 typedef SpaceND< 3,int > Z3;
 typedef MetricAdjacency< Z3, 1 > Adj6;
 typedef MetricAdjacency< Z3, 2 > Adj18;
 typedef DigitalTopology< Adj6, Adj18 > DT6_18;

 Adj6 adj6;
 Adj18 adj18;
 DT6_18 dt6_18( adj6, adj18, JORDAN_DT );

 typedef Z3::Point Point;
 typedef HyperRectDomain< Z3 > Domain;
 typedef Domain::ConstIterator DomainConstIterator;
 typedef DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet;
 typedef Object<DT6_18, DigitalSet> ObjectType;

 Point p1( -50, -50, -50 );
 Point p2( 50, 50, 50 );
 Domain domain( p1, p2 );
 Point c( 0, 0 );
 // diamond of radius 30
 DigitalSet diamond_set( domain );
 for ( DomainConstIterator it = domain.begin(); it != domain.end(); ++it )
   {
     if ( (*it - c ).norm1() <= 30 ) diamond_set.insertNew( *it );
   }
 ObjectType diamond( dt6_18, diamond_set );
 // The following line takes almost no time.
 ObjectType diamond_clone( diamond );
 // Since one of the objects is modified, the set is duplicated at the following line
 diamond_clone.pointSet().erase( c );
 ObjectType bdiamond = diamond.border(); // one component
 ObjectType bdiamond_clone = diamond_clone.border(); // two components

 Board3D<> board;
 board << SetMode3D(domain.className(), "Paving");
 board << CustomColors3D(Color(250, 0,0),Color(250, 0,0));

 for(auto it : bdiamond_clone.pointSet())
   board << it;

 board.saveOBJ("/home/kacper/dgtalBoard3D-1bis-points.obj");

 return 0;

}

image

It is basically the example with some lines changed at the very end.

@psarahdactyl
Copy link
Author

thank you so much! I wasn't quite sure how to use the Board class.

@copyme
Copy link
Member

copyme commented Apr 18, 2019

@psarahdactyl Great! Could you please close the issue if the solution helped you out.

@copyme
Copy link
Member

copyme commented Apr 18, 2019

@psarahdactyl By the way, you do not need the loop over points. You can send the object directly, i.e., replace

 for(auto it : bdiamond_clone.pointSet())
   board << it; 

with board << bdiamond_clone; Board3D more or less works like Viewer3D – you can send an object to it and control its appearance by modifiers: modes like Paving or colors, etc. I am not the best person to explain this stuff but I am sure that we can help you with your further questions. So do not hesitate to ask. Also, examples are a good starting point. Good luck!

@psarahdactyl psarahdactyl reopened this May 1, 2019
@psarahdactyl
Copy link
Author

Sorry to ask so many questions, but say now I want to get the vertices and faces of the voxel geometry. I have been looking around the documentation and the inline header files for Display3D and Board3D and see that there is an addCube function which seems to deal with the actual geometry. Is there an easier way exposed to the user where I can access this? Maybe through the PointSet?

@dcoeurjo
Copy link
Member

dcoeurjo commented May 1, 2019

You should have a look to the brand new Shortcuts https://dgtal.org/doc/stable/moduleShortcuts.html

There are direct methods to export a digital surface to OBJ (either primal or dual surface) or to obtain easy vertices/faces accessors.

@dcoeurjo
Copy link
Member

dcoeurjo commented May 1, 2019

Like getSurfelRange or getPointelRange

@psarahdactyl
Copy link
Author

psarahdactyl commented May 1, 2019

Do I first need to make the DigitalTopology into a DigitalSurface?

typedef DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet;

typedef MetricAdjacency< Z3, 2 > Adj18;
typedef DigitalTopology< Adj6, Adj18 > DT6_18;
Adj6 adj6;
Adj18 adj18;
DT6_18 dt6_18( adj6, adj18, JORDAN_DT );
typedef Object<DT6_18, DigitalSet> ObjectType;

typedef DigitalSetBoundary< Z3i::KSpace, DigitalSet > Boundary;

ObjectType b_scene = sc.border();
DigitalSet border = b_scene.pointSet();
Boundary boundary(Z3, border, Adj18);

I was trying to make a DigitalSetBoundary because it has a surfel iterator but I can't figure out how to use the constructor on line 192 of DigitalSetBoundary.h
https://dgtal.org/doc/stable/classDGtal_1_1DigitalSetBoundary.html#aa8c18e7161085386f2aa9328a8382f11

@psarahdactyl
Copy link
Author

I'm having trouble understanding what aKSpace is. in the documentation it says it's a cellular grid space. Is this the same this as a Khalimsky space typedef KhalimskySpaceND<3,int> KSpace;?

DigitalSetBoundary( ConstAlias<KSpace> aKSpace,
                         const DigitalSet & aSet,
                         const Adjacency & adj = Adjacency( true ) );

@dcoeurjo
Copy link
Member

dcoeurjo commented May 6, 2019

Yes it is.
If you want to construct a digital surface from a set, a binary image, or a point predicate (all these objects are really close), the makeLightDigitalSurface or makeDigitalSurface in the Shortcuts doc would do the job.

In most situations, no need to manually construct the KSpace, it is usually given by the container.

@psarahdactyl
Copy link
Author

Thank you!

@gaoalexander
Copy link

Yes it is. If you want to construct a digital surface from a set, a binary image, or a point predicate (all these objects are really close), the makeLightDigitalSurface or makeDigitalSurface in the Shortcuts doc would do the job.

In most situations, no need to manually construct the KSpace, it is usually given by the container.

Hi @dcoeurjo,

I had a short follow-up question to this: it appears that makeDigitalSurface as documented here can accept either an "indexed digital surface" or a "binary image" as input types. It's still not clear to me how I can use these functions with the "digital set" type as input.

Wonder if you're able to clarify (i.e. how can I obtain a digital surface given a digital set)? I am basically trying to import a triangle mesh from an OBJ file, voxelize it, obtain its digital surface (boundary), and save the result back as a quadrilateral mesh OBJ file.

Thank you very much.

@JacquesOlivierLachaud
Copy link
Member

Hello
If you wish to construct the digital surface that is the boundary of a digital set, you can have a look at this doc
https://dgtal-team.github.io/doc-pr/pr1736/moduleDigitalSurfaces.html#dgtal_digsurf_sec1_1
A DigitalSetBoundary class correspond to your purpose.

@JacquesOlivierLachaud
Copy link
Member

JacquesOlivierLachaud commented Jul 4, 2024

Otherwise there are helper functions that simply builds the set of cells forming the boundary (2-cells in 3D). This can be done by scanning the whole image as:

KSpace::SCellSet boundary;
Surfaces<KSpace>::sMakeBoundary( boundary, ks, set3d,
                                   image.domain().lowerBound(),
                                   image.domain().upperBound() );

where ks is your KSpace and set3d is a DigitalSet.

@dcoeurjo
Copy link
Member

dcoeurjo commented Jul 4, 2024

Alternatively, you can use the mesh2vol, volFillInterior and volBoundary2obj tools from https://github.com/DGtal-team/DGtalTools if you want to from the command line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants