mkazhdan / ECHODescriptors

Extended Convolution Histogram of Orientations
13 stars 2 forks source link

Extract sub code #1

Closed de-gozaru closed 2 years ago

de-gozaru commented 2 years ago

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 the Misha 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

twmitchel commented 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.

de-gozaru commented 2 years ago

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!

twmitchel commented 2 years ago

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.

de-gozaru commented 2 years ago

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!

twmitchel commented 2 years ago

@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.

de-gozaru commented 2 years ago

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!

twmitchel commented 2 years ago

@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.

de-gozaru commented 2 years ago

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!

twmitchel commented 2 years ago

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').

de-gozaru commented 2 years ago

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!

twmitchel commented 2 years ago

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.