Closed de-gozaru closed 2 years ago
Hi @de-gozaru,
Thanks for your kind words - we're happy to help you get things working.
You're correct that the GetDescriptor.*
files depend on several libraries (Eigen, Spectra, and DGPC) in addition to a collection of headers + inline files titled Misha
. All of these directories are contained in the Include
directory in the repo. You don't need to install the Misha
directory, you only need to make sure that your project has access to the directory Include/Misha
.
@mkazhdan is the Visual Studio expert so he can provide additional device as to how to get things running in VS.
Hi @twmitchel @mkazhdan
Thank you for your answer, I indeed just had to include the libraries in the Include folder. However, I have a question, how to include OpenMesh in my CMakeLists.txt (I'm not using the image libs such as JPEG or PNG)?
I tried something like this:
find_package( OpenMesh REQUIRED )
include_directories( ${OPENMESH_INCLUDE_DIRS} )
link_directories( ${OPENMESH_LIBRARY_DIRS} )
but cmake is complaining about not finding it!
Can you please tell me how to include and link OpenMesh?
Thank you in advance!
Hi @de-gozaru,
Is there a reason you need to compute the descriptors using the geodesic distance, or would using the biharmonic distance be fine?
In our experiments we found the biharmonic distance to be the most effective. Only the computation of the descriptors using the geodesic distance relies on OpenMesh.
Hi @twmitchel
Thank you for your answer!
Indeed, I'm not intending to compute the descriptors using the geodesic distance! How should I proceed to remove the dependency on OpenMesh? I understand that it's used in DGPC, and is defined in multiple files, is there a minimal way to change the files so it drops the dependency on OpenMesh?
Thank you in advance!
@de-gozaru
I believe the only files (besides GetDescriptor.*
) that include DGPC
and its dependency OpenMesh
are the Include/Misha/TriMesh.*
files.
To remove the OpenMesh dependency try the following:
In the file Include/Misha/TriMesh.h
comment out lines 45 - 51 and lines 113 - 125.
In the file Include/Misha/TriMesh.inl
comment out lines 254 - 318.
In GetDescriptor/GetDescriptor.inl
comment out lines 272 - 278 and lines 288 - 294.
In GetDescriptor/GetDescriptor.cpp
comment out lines 292 - 302, line 336, line 363, line 368.
In GetDescriptor/GetDescriptor.inl
you might also try commenting out line 42 in addition to replacing line 49 with
const static std::string DistanceNames[] = { "biharmonic" , "diffusion" , "commute" };
However, doing these last two things in GetDescriptor.inl
might have some unintended downstream consequences. In any case, make sure not to invoke the executable with the geodesic
flag.
Also, make sure you don't try to build, include, or link DGPC
in your CMakeLitsts.txt
file.
Try these edits and let me know how it goes - I may have missed a file that includes DGPC
in which case you'll get an error during compiling.
Hi @twmitchel
Thank you so much for your response!
I succeeded to compile the code and run it on an artificial example. The code outputs a descriptor of size 1024 x 1024
. This feature is somehow very big (dimension > 1M )! what is a good resolution for the descriptor from your experience? Is the size used in the paper 11 x 11
a good size? In general, from you experience, what is the best choice for the params of the GetDescriptor
function?
Thank you in advance!
@de-gozaru Glad to hear you're able to get it working.
Did you run the following example?
% GetDescriptor --in wolf0.ply --spec wolf0.spec --vertex 1000 --out wolf0.1000.jpeg --hRadius 10 --resolution 1024 --dev 0.005--verbose
If you did, the actual descriptor size is 21 x 21
but in this case your output file is a .jpeg
image which is a visualization of the computed descriptor of resolution 1024 x 1024
-- not the actual descriptor itself.
If you want to get the actual descriptor, your output file should be a .txt
file, which will give you the actual values of the (vectorized descriptor), e.g. the following command would output the actual descriptor of resolution 21 x 21
GetDescriptor --in wolf0.ply --spec wolf0.spec --vertex 1000 --out wolf0.1000.txt --hRadius 10 --verbose
Take a look at explanation of the parameters for GetDescriptor in the Executables section of the README
(click on GetDescriptor to see them). That should help you get a sense of how to use the command line interface and the role of each parameter.
To answer your second question, the default values in the code and those we specified in the paper are typically those we found to work best in practice. The two most impactful parameters you should play with are hRadius
(which controls the resolution of descriptor) and tau
which controls the support radius on the mesh for computing the descriptor.
Generally speaking, we found an hRadius
between 3
and 10
to be most effective in practice. Smaller values of hRadius
correspond to lower resolution descriptors which are more stable but less distinctive. Higher values define higher resolution descriptors which are more distinctive but less repeatable. In practice we found hRadius = 5
(corresponding to an 11 x 11
to be a good compromise between distinctiveness and repeatability, but a different value might be more suitable for your use case.
The other critical parameter is tau
which determines the size of the support region for the descriptor. Specifically, the descriptor will include the contributions of all points/triangles whose distance (biharmonic, geodesic, etc.) is less than or equal to
where |M| is the area of the mesh computed relative to the chosen distance. If you want to describe a relative small feature (one contained in region whose surface area is small relative to the total surface area of the mesh) then you want to use a smaller value of tau
. If you want to describe larger features then you want larger values for tau
. The correct value of tau
really depends on your use case and is perhaps more important than hRadius
in computing effective descriptors, so be sure to play around with it and see what's best for you.
Hi @twmitchel
Thank you for your response!
Here is my modified code:
if( source_node )
{
if( IsSpectral( distance_type ) ) F = spectralEcho< float , NSamples >( tMesh , spectrum , signal , dualFrameField , source_node , rho , nRadialBins , weightFunction );
else {};
// else F = geodesicEcho< float , NSamples >( tMesh , signal , dualFrameField , source_node , rho , nRadialBins , weightFunction );
}
std::cout << "Resolution before: " << F.res(0) << " " << F.res(1) << std::endl;
// returns: Resolution before: 21 21
std::cout << "ResampleSignal" << std::endl;
// noDisk is false by default, so the signal is resampled to a disk
if( noDisk ) F = ResampleSignal( F , out_resolution , out_resolution );
else F = ResampleSignalDisk( F , out_resolution , out_resolution );
std::cout << "TransposeSignal" << std::endl;
F = TransposeSignal( F );
std::cout << "Resolution: " << F.res(0) << " " << F.res(1) << std::endl;
// returns: Resolution: 1024 1024
std::cout << "value: " << F(0, 1) << std::endl;
So my question is, if the out_resolution
is not setup (in my code, out_resolution
is a parameter to the function I rewrite, that has a default value of 1024 as in your code), the signal will be resampled to its initial value, meaning it will not be sampled, is this correct?
My second question is that is the sampling of the signal is really necessary, or it's just for the visualization aspect, espacially the disk sampling? My use case is that I want to compute a feature for each point in my input shape, and use these features as input to a neural network, so a feature of dimension 441 (21 X 21) is ok for me?
Thank you in advance!
Hi @de-gozaru,
ResampleSignal
and ResampleSignalDisk
are only for the purposes of visualization.
The output of spectralEcho
is your descriptor. You shouldn't call either of the ResampleSignal*
functions after spectralEcho
(and can ignore them and the out_resolution
parameter entirely).
For an input to a neural network, I'd recommend starting with a histogram radius of hRadius = 5
corresponding to an 11 x 11
resolution descriptor (i.e. 121
channel input features). If your meshes (training and/or testing) are very clean (not noisy) you can try going to a higher resolution (hRadius = 7, 8, 9
). Conversely, if you meshes (training and/or testing) are very noisy, you might try decreasing the descriptor resolution ('hRadius = 4, 3').
Hi @twmitchel
Thank you for your response, it makes sense to me!
Just one last esthetic question, the signal that is output by spectralEcho
is a 2D grid, but for my use case, I'll flatten it to a 1D vector (I think this will change nothing), so my question is, in my scenario, is the function TransposeSignal
really necessary, or it is also just for visualization purposes?
Thank you in advance!
Hi @de-gozaru,
There are no issue in flattening the descriptor to a 1D feature vector. All transpose signal does is literally transpose the 2D histogram i,j -> j,i
- we used it just for visualization purposes.
I'm going to close this issue now since it seems like you've got things working. If you run into problems or have other questions feel free to open another issue or email me at thomas.w.mitchel "at" gmail.com.
Hi @mkazhdan
Congrats on the great work and thank you of open sourcing the code.
I'm contacting you because I want to extract the sub part of you code that only compute the descriptors, and use it in another project. This corresponds to the
GetDescriptor.*
files. However, the latter requires theMisha
library. Can you please tell me how to install it?Thank you in advance.
PS: I apologize in advance for my lack of fluency in cpp PS 2: I'm using visual studio code on Ubuntu