Code Monkey home page Code Monkey logo

fastgeodis's People

Contributors

danielskatz avatar jacobmerson avatar masadcv avatar reubendo avatar tvercaut avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

fastgeodis's Issues

[BUG] Improve CUDA kernels to reduce number of invocations

As reported in openjournals/joss-reviews#4532 in the comment openjournals/joss-reviews#4532 (comment)

The cuda kernels are called many times (invocations == number of rows/planes). As indicated by reviewer, this may incur additional costs for setting up and running kernels each time on new row.

An expected behviour here would be to setup and call kernel for each pass once. This will reduce the overhead added by many calls and would potentially improve the overall execution efficiency of the current algorithms.

Question about the weighting factor v

Hi,

I am trying to tune the Geodesic Distance for the MSD Spleen dataset and wonder how exactly the v parameter should be fine-tuned.

The documentation states that it is a "weighting factor for establishing relationship between unary and spatial distances". My guess at looking at the code and re-reading the GeoS paper is that it balances the spatial and appearance correlation between the pixels/voxels, similarly to the energy terms in CRFs.

However, I could not really identify in which equation in GeoS I should look for this parameter so that I have a better understanding of how to tune it. Do high values of v enhance spatial or appearance correlation?

I would be grateful if you could shed some light onto this!

Thanks for the wonderful work!

Best,
Zdravko

[BUG] pip install bug

FastGeodis/geodis_fastmarch.cpp: In functiona'at::Tensor gradient2d(at::Tensor)':
FastGeodis/geodis_fastmarch.cpp:87:46: error: 'kSame' is not a member of 'torch
87
.padding(torch::kSame)
FastGeodis/geodis_fastmarch.cpp:95:46: error: 'kSame' is not a member of 'torch'
95
.padding(torch::kSame)
FastGeodis/geodis_fastmarch.cpp: In function 'at::Tensor gradient3d(at::Tensor)':
FastGeodis/geodis_fastmarch.cpp:281:46: error: 'kSame' is not a member of 'torch'
281
.padding(torch::kSame)
FastGeodis/geodis_fastmarch.cpp:289:46: error: 'kSame' is not a member of
N'torch
289
.padding(torch::kSame)
FastGeodis/geodis_fastmarch.cpp:297:46: error: 'kSame' is not a member of 'torch'
297
.padding(torch::kSame)

623b5dd5-666d-4b3a-b202-74bba324e54e
00dc13a5-9cab-4833-acc1-2abbd8eec94d

[FEATURE] Add link back to github in reads the docs

Is your feature request related to a problem? Please describe.
The link to teh source code currentlly does not feature prominently on https://masad.ml/FastGeodis/

Describe the solution you'd like
Something along the lines of:

  • Add a simple "Source code" section in the sidebar menu
  • Replace "view page source" in the top right by "improve this page"

Additional context
A random example of this:
https://pylops.readthedocs.io/en/stable/

This can maybe be implemented through conf.py:
https://sphinx-rtd-theme.readthedocs.io/en/stable/configuring.html#confval-vcs_pageview_mode
https://github.com/PyLops/pylops/blob/c5844c4a4b25cdb74a5cef12b926d6d91da20095/docs/source/conf.py#L121-L143

how to get equivalent result

Thanks for the fast fix for the padding issue!

I found the definition of "geodesic distance transform (GDT)" seems different from what I understand.

I need a function like "bwdistgeodesic" in (matlab), in this senario, it is very close to the traditional distance transform, which is also used for binary image. The only difference is that, the distance calculation cannot transmit through the "0" values in GDT.

but when I try FastGeodis, I found the basic logic differs from "bwdistgeodesic". the distance value only grows when face image gradient

import numpy as np
import torch
import FastGeodis
BW = np.array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 11],
                            [1, 1, 1, 1, 1, 1, 0, 0, 1, 1],
                            [1, 1, 1, 1, 1, 1, 0, 0, 1, 1],
                            [1, 1, 1, 1, 1, 1, 0, 0, 1, 1],
                            [0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
                            [0, 0, 0, 0, 1, 1, 0, 1, 1, 0],
                            [0, 1, 0, 0, 1, 1, 0, 0, 0, 0],
                            [0, 1, 1, 1, 1, 1, 1, 0, 1, 0],
                            [0, 1, 1, 0, 0, 0, 1, 1, 1, 0],
                            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]])

C = [1, 2, 3, 3, 3]
R = [3, 3, 3, 1, 2]
seed_img = np.zeros_like(BW)
seed_img[C,R] = 1
v = 1e10
# lamb = 0.0 (Euclidean) or 1.0 (Geodesic) (or (0.0, 1.0) (mixture)
lamb = 1.0
iterations = 2
geodesic_dist = FastGeodis.generalised_geodesic2d(
                        torch.from_numpy(BW).cuda()[None,None ].float(),
                        1-torch.from_numpy(seed_img).cuda()[None,None],
                        v, lamb, iterations)

but i get the following result:
image

what I expect is:
image

as far as I understand, this lib is designed to use image gradient as energy barrier, is there a simple way for me to reproduce the expected result?

Question on the meaning of parameters of generalised_geodesic3d

Hi all,

I have recently discovered your implementation of FastGeodis. I am however unable to understand how I am supposed to make it work.

Say we have a 3D binary mask in tensor format (i.e [B, C, X, Y, Z]) if I wanted to simply do the distance transform of this mask as in scipy.ndimage.morphology.distance_transform_edt, how should I proceed?

To go further with my question I don't really understand the documentation on:

  • image – input image, can be grayscale or multiple channels.
  • softmask – softmask in range [0, 1] with seed information.
  • spacing – spacing for 3D data
  • v – weighting factor for establishing relationship between unary and spatial distances.
    To what should I set those if I just want to extract the euclidian distance transform of my mask ?

Thanks!

[FEATURE] multiple batch input for generalised_geodesic2d

ValueError: FastGeodis currently only supports single batch input.
when using FastGeodis.generalised_geodesic2d, v=1.0e10, lamb=0.0, iter=1

  • Is there any timeline on implementing multiple batch input
  • Currently I run each batch independantly and concatenate them after

[General Question] Threshold for Geodesic Distance

Hi there! First of all, this is a wonderful implementation and I have had a very pleasant experience so far.

I have a general question of understanding regarding Geodesic Distances as a whole. I have applied your method to the MSD Spleen dataset and got good results when training the MONAI Label DeepEdit model (instead of using Gaussian Heatmaps as guidance, I replaced it with GeoDis maps).

However, it required a lot of manual tuning of the threshold for the Geodesic Distance. I struggled to find a systematic and consistent way to justify my choice for such a threshold. It seems that MIDeepSeg tackles this exact problem and the authors state that other methods simply empirically find the optimal threshold value (i.e. you have to do a grid search and train multiple models).

My question would be: Is there a systematic way to find this threshold or is it problem-specific and requires a grid search?

Here are some more images which describe my problem:

  • Large threshold leads to few errors but also does not really cover the spleen fully

  • Small threshold "bleeds out" into the background, eventually degrading to Euclidean Distance
    geo_th_exp

  • Increasing the threshold minimizes the overlap with the background (error), but also minimizes the overlap with the spleen (gt)
    corr_err

[BUG] Not compiled with CUDA support.

Describe the bug
Thank you for the work! FastGeodis is not being installed with CUDA support no matter the install method.

To Reproduce
Steps to reproduce the behavior:

  1. pip install FastGeodis --no-build-isolation
  2. See below example.
  3. See error below.

example

import FastGeodis as fd
import torch
device = torch.device('cuda')
a = torch.rand(1,1,512,512).to(device)
b = torch.ones_like(a).to(device)
fd.generalised_geodesic2d(a, b, 256, 0., 1)

error

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Input In [1], in <cell line: 6>()
      4 a = torch.rand(1,1,512,512).to(device)
      5 b = torch.ones_like(a).to(device)
----> 6 fd.generalised_geodesic2d(a, b, 256, 0., 1)

File /opt/conda/envs/deepselect/lib/python3.8/site-packages/FastGeodis/__init__.py:62, in generalised_geodesic2d(image, softmask, v, lamb, iter)
     36 def generalised_geodesic2d(
     37     image: torch.Tensor, 
     38     softmask: torch.Tensor, 
   (...)
     41     iter: int = 2
     42 ):
     43     r"""Computes Generalised Geodesic Distance using FastGeodis raster scanning.
     44     For more details on generalised geodesic distance, check the following reference:
     45 
   (...)
     60         torch.Tensor with distance transform
     61     """
---> 62     return FastGeodisCpp.generalised_geodesic2d(
     63         image, softmask, v, lamb, 1 - lamb, iter
     64     )

RuntimeError: Not compiled with CUDA support.

Expected behavior
Distance map calculation on GPU.

Desktop (please complete the following information):

  • OS: Ubuntu 20.04
  • Torch: 1.12.0+cu113
  • GPU: A100

Thank you for the amazing work!

[BUG] FastGeodis.generalised_geodesic2d is slower on CPU than sp.ndimage.distance_transform_cdt

Thank you for the lib, the GPU acceleration saved my day!

When looking at the time performances of FastGeodis.generalised_geodesic2d versus the corresponding Euclidean sp.ndimage.distance_transform_cdt:

  • FastGeodis implementation on CPU is slower
  • FastGeodis implementation on GPU has a regime where it is slower

This might be expected, but is a little bit conterintuitive, specially looking at the plots from the README. However, I totally understand that this latter plot is on Non-Euclidean space

Capture

import torch
import time
from functools import partial
import scipy as sp
import FastGeodis
import matplotlib.pyplot as plt
import numpy as np

device = "cuda" if torch.cuda.is_available() else "cpu"
print(device)

generalised_geodesic2d = partial(
    FastGeodis.generalised_geodesic2d, v=1.0e10, lamb=0.0, iter=1
)
distance_transform_cdt = sp.ndimage.distance_transform_cdt

nb_warmup = 5
nb_repeates = 10
sizes = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096]  # , 8194]
times = {
    "FastGeodis-generalised_geodesic2d-gpu": [],
    "FastGeodis-generalised_geodesic2d-cpu": [],
    "scipy-distance_transform_cdt-cpu": [],
}

# Compare values
for size in sizes:
    # Setup the image
    image = torch.ones((1, 1, size, size))
    image[0, 0, int(size // 2) : int(size // 2) + 1, :] = 0.0

    ## For GPU-FastGeodis
    image = image.to(device)
    with torch.no_grad():
        euclidean_dist = generalised_geodesic2d(
            image=image,
            softmask=image,
        )
    image = image[0, 0]
    image = image.detach().cpu().numpy()
    euclidean_dist = euclidean_dist.detach().cpu().numpy()[0, 0]

    # For scipy
    np_euclidean_dist = distance_transform_cdt(image)

    # Plot
    # plt.imshow(euclidean_dist)
    # plt.grid()
    # plt.show()
    # plt.imshow(np_euclidean_dist)
    # plt.grid()
    # plt.show()

    print(
        (euclidean_dist - np_euclidean_dist).min(),
        (euclidean_dist - np_euclidean_dist).max(),
    )

# Compare time
for size in sizes:
    # Setup the image
    image = torch.ones((1, 1, size, size))
    image[0, 0, int(size // 2) : int(size // 2) + 1, :] = 0.0

    ## For GPU-FastGeodis
    image = image.to(device)
    with torch.no_grad():
        for _ in range(nb_warmup):
            euclidean_dist = generalised_geodesic2d(
                image=image,
                softmask=image,
            )
        start = time.time()
        for _ in range(nb_repeates):
            euclidean_dist = generalised_geodesic2d(
                image=image,
                softmask=image,
            )
        end = time.time()
    times["FastGeodis-generalised_geodesic2d-gpu"] += [end - start]
    
    ## For GPU-FastGeodis
    image = image.detach().cpu()
    with torch.no_grad():
        for _ in range(nb_warmup):
            euclidean_dist = generalised_geodesic2d(
                image=image,
                softmask=image,
            )
        start = time.time()
        for _ in range(nb_repeates):
            euclidean_dist = generalised_geodesic2d(
                image=image,
                softmask=image,
            )
        end = time.time()
    times["FastGeodis-generalised_geodesic2d-cpu"] += [end - start]

    # For scipy
    np_image = image.detach().cpu().numpy()[0, 0]
    for _ in range(nb_warmup):
        euclidean_dist = distance_transform_cdt(np_image)
    start = time.time()
    for _ in range(nb_repeates):
        euclidean_dist = distance_transform_cdt(np_image)
    end = time.time()
    times["scipy-distance_transform_cdt-cpu"] += [end - start]

sizes = np.array(sizes)
for k in times.keys():
    times[k] = np.array(times[k])
    print(k, times[k])

for k in times.keys():
    plt.plot(sizes, times[k], marker="o", label=rf"{k}")
plt.xscale("log")
plt.yscale("log")
plt.xlabel("Size")
plt.ylabel("Time [s]")
plt.legend()
plt.grid()
plt.show()

plt.plot(
    sizes,
    times["FastGeodis-generalised_geodesic2d-gpu"] / times["scipy-distance_transform_cdt-cpu"],
    marker="o",
    label=rf"{k}",
)
plt.plot(
    sizes,
    times["FastGeodis-generalised_geodesic2d-cpu"] / times["scipy-distance_transform_cdt-cpu"],
    marker="o",
    label=rf"{k}",
)
plt.xscale("log")
plt.yscale("log")
plt.xlabel("Size")
plt.ylabel("Time / distance_transform_cdt-cpu")
plt.legend()
plt.grid()
plt.show()

[BUG] install error with CUDA 11.6

Describe the bug
Attempting to install on linux machine with cuda 11.6 is giving pytorch mismatch error

To Reproduce

$ pip install torch --pre --extra-index-url https://download.pytorch.org/whl/nightly/cu116 
$ cd FastGeodis
$ pip install -e .
Obtaining file:///lore/mersoj/FastGeodis
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done
Installing collected packages: FastGeodis
  Running setup.py develop for FastGeodis
    ERROR: Command errored out with exit status 1:
     command: /lore/mersoj/geodis/bin/python -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/lore/mersoj/FastGeodis/setup.py'"'"'; __file__='"'"'/lore/mersoj/FastGeodis/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' develop --no-deps
         cwd: /lore/mersoj/FastGeodis/
    Complete output (56 lines):
    setup.py with torch 1.12.0+cu102
    BUILD_CPP=True, BUILD_CUDA=True, TORCH_VERSION=11200.
    running develop
    /tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/command/easy_install.py:144: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.
      warnings.warn(
    /tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
      warnings.warn(
    running egg_info
    writing FastGeodis.egg-info/PKG-INFO
    writing dependency_links to FastGeodis.egg-info/dependency_links.txt
    writing top-level names to FastGeodis.egg-info/top_level.txt
    /tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/torch/utils/cpp_extension.py:411: UserWarning: Attempted to use ninja as the BuildExtension backend but we could not find ninja.. Falling back to using the slow distutils backend.
      warnings.warn(msg.format('we could not find ninja.'))
    reading manifest file 'FastGeodis.egg-info/SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    adding license file 'LICENSE'
    writing manifest file 'FastGeodis.egg-info/SOURCES.txt'
    running build_ext
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/lore/mersoj/FastGeodis/setup.py", line 123, in <module>
        setup(
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/__init__.py", line 87, in setup
        return distutils.core.setup(**attrs)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/_distutils/core.py", line 177, in setup
        return run_commands(dist)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/_distutils/core.py", line 193, in run_commands
        dist.run_commands()
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/_distutils/dist.py", line 968, in run_commands
        self.run_command(cmd)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/dist.py", line 1217, in run_command
        super().run_command(command)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/_distutils/dist.py", line 987, in run_command
        cmd_obj.run()
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/command/develop.py", line 34, in run
        self.install_for_development()
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/command/develop.py", line 114, in install_for_development
        self.run_command('build_ext')
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/_distutils/cmd.py", line 317, in run_command
        self.distribution.run_command(command)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/dist.py", line 1217, in run_command
        super().run_command(command)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/_distutils/dist.py", line 987, in run_command
        cmd_obj.run()
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/command/build_ext.py", line 79, in run
        _build_ext.run(self)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py", line 339, in run
        self.build_extensions()
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/torch/utils/cpp_extension.py", line 434, in build_extensions
        self._check_cuda_version(compiler_name, compiler_version)
      File "/tmp/pip-build-env-wm8mya_7/overlay/lib/python3.9/site-packages/torch/utils/cpp_extension.py", line 812, in _check_cuda_version
        raise RuntimeError(CUDA_MISMATCH_MESSAGE.format(cuda_str_version, torch.version.cuda))
    RuntimeError:
    The detected CUDA version (11.6) mismatches the version that was used to compile
    PyTorch (10.2). Please make sure to use the same CUDA versions.
    
    ----------------------------------------
ERROR: Command errored out with exit status 1: /lore/mersoj/geodis/bin/python -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/lore/mersoj/FastGeodis/setup.py'"'"'; __file__='"'"'/lore/mersoj/FastGeodis/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' develop --no-deps Check the logs for full command output.

Note: I can import python and pytorch and it runs GPU code without issue. I think this must be an installation with FastGeodis. However, I'm not sure since I don't have experience using pytorch.

Expected behavior
FastGeodis installs

Desktop (please complete the following information):

  • OS: RHEL7, CUDA 11.6

[BUG] Generalised distance not possible with wave-front methods

Describe the bug
As reported here: #42 (comment)
generalised implementation of distance transforms is not possible with wave-front methods (fast march/pixel queue)

There is a need to modify relevant functions to just distance transform (removing generalised)

For pixel queue method, this also means removing the use of soft mask and parameter v and initial distance to a large values.

[FEATURE] GPU implementation of accurate Euclidean Distance Transforms

Is your feature request related to a problem? Please describe.
The package currently provide GPU-based approximations of Geodesic and Euclidean distance transforms.

Following #42 fast marching now allows for more accurate computations of Euclidean distance transforms but this is limited to CPU operations and remains an approximation.

Describe the solution you'd like
Having a GPU implementation of an exact Euclidean Distance Transform would strengthen the package.

Describe alternatives you've considered
Rely on third party libs for this. e.g. CUCIM, Tensorflow or PBA+
https://docs.rapids.ai/api/cucim/stable/api/#cucim.core.operations.morphology.distance_transform_edt
https://www.tensorflow.org/addons/api_docs/python/tfa/image/euclidean_dist_transform
https://github.com/orzzzjq/Parallel-Banding-Algorithm-plus

Having this integrated in FastGeodis withouth the need for external dependencies would nonetheless be nice and make the pytorch link tighter.

Additional context
This feature request has been voice earlier, e.g.:
#40 (comment)
Project-MONAI/MONAI#1332 (comment)

The CUCIM code, based on PBA+ is released under MIT, seems fairly standalone, and could thus be copy-pasted in this repo for convenience:
https://github.com/rapidsai/cucim/tree/main/python/cucim/src/cucim/core/operations/morphology

IMPORT ERROR: undefined symbol

Describe the bug
Hi, I have the following error when trying to import FastGeodis for my project,

`
Exception has occurred: ImportError

/home/***/anaconda3/envs/torch/lib/python3.9/site-packages/FastGeodisCpp.cpython-39-x86_64-linux-gnu.so: undefined symbol:
_ZN2at4_ops5zeros4callEN3c108ArrayRefINS2_6SymIntEEENS2_8optionalINS2_10ScalarTypeEEENS6_INS2_6LayoutEEENS6_INS2_6DeviceEEENS6_IbEE

File "/home//Documents//model/networks.py", line 40, in

import FastGeodis

File "/home//Documents//run_***.py", line 55, in

from model.networks import *

File "/home//Documents//main.py", line 81, in

from run_*** import *

ImportError: /home/***/anaconda3/envs/torch/lib/python3.9/site-packages/FastGeodisCpp.cpython-39-x86_64-linux-gnu.so: undefined symbol:
_ZN2at4_ops5zeros4callEN3c108ArrayRefINS2_6SymIntEEENS2_8optionalINS2_10ScalarTypeEEENS6_INS2
`

Desktop

  • OS: Ubuntu
  • Version 18.04

Environment

  • Python 3.9.13
  • Pytorch 1.12.1
  • CUDA 11.3.1
  • GCC 7.5.0

Additional context
I have the same issue when trying to compile the cpp and cu files locally.

[BUG] "Fast marching" implementation doe not use Eikonal update formula

Describe the bug
Having looked through the code, it seems that the implementation of geodis_fastmarch.cpp does not use any Eikonal update formula:

l_dist = 0.0;
if (channel == 1)
{
l_dist = l1distance_fastmarch(
image_ptr[0][0][h][w],
image_ptr[0][0][nh][nw]);
}
else
{
for (int c_i=0; c_i < channel; c_i++)
{
l_dist += l1distance_fastmarch(
image_ptr[0][c_i][h][w],
image_ptr[0][c_i][nh][nw]);
}
}
delta_dis = l_eucl * space_dis + l_grad * l_dist;
old_dis = distance_ptr[0][0][nh][nw];
new_dis = distance_ptr[0][0][h][w] + delta_dis;

As such, it probably isn't really implementing fast marching.

To Reproduce
Look at the output of the current fastmarching for Euclidean distance:

plt.imshow(euclidean_dist_fastmarch)

Star artefacts are as pronounced as those in Toivanen approach. See also #40

Expected behavior
A much better approximation of the distance map should be achievable through fast marching.

Additional context
A good description of fast marching can be found in the following technical report:
Bærentzen, J. A. (2001). On the implementation of fast marching methods for 3D lattices.
http://www2.imm.dtu.dk/pubdb/pubs/841-full.html

A python wrapper for a basic c++ implementation of fast marching can be found in the scikit-fmm package.

A standalone c++, header-only implementation of fast marcing can be found here:
https://github.com/tvercaut/fast-marching-method
It would make sense to replace teh current implementation in the FastGeodis repo by that provided in fast-marching-method.

pip install has issues detecting dependencies on conda

If a system has pytorch pre-installed using conda - then poetry (pyproject.toml) does not detect it and installs pytorch using pip

This causes issues especially if there is a mismatch between CUDA version for pytorch from pip and the CUDA version available on system

To reproduce:

  • Start a docker imagedocker run --gpus all -it --rm nvcr.io/nvidia/pytorch:21.10-py3
  • Install FastGeodis using pip: pip install FastGeodis

The above gives the following error:

{rocessing FastGeodis-1.0.0rc2.tar.gz
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: torch>=1.8.0 in /opt/conda/lib/python3.8/site-packages (from FastGeodis==1.0.0rc2) (1.9.0a0+2ecb2c7)
Requirement already satisfied: typing-extensions in /opt/conda/lib/python3.8/site-packages (from torch>=1.8.0->FastGeodis==1.0.0rc2) (3.7.4.3)
Building wheels for collected packages: FastGeodis
  Building wheel for FastGeodis (pyproject.toml) ... error
  error: subprocess-exited-with-error
  
  × Building wheel for FastGeodis (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [69 lines of output]
      setup.py with torch 1.11.0+cu102
      BUILD_CPP=True, BUILD_CUDA=True, TORCH_VERSION=11100.
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.linux-x86_64-cpython-38
      creating build/lib.linux-x86_64-cpython-38/FastGeodis
      copying FastGeodis/__init__.py -> build/lib.linux-x86_64-cpython-38/FastGeodis
      running build_ext
      /tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/torch/_masked/__init__.py:223: UserWarning: Failed to initialize NumPy: numpy.core.multiarray failed to import (Triggered internally at  ../torch/csrc/utils/tensor_numpy.cpp:68.)
        example_input = torch.tensor([[-3, -2, -1], [0, 1, 2]])
      Traceback (most recent call last):
        File "/opt/conda/lib/python3.8/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 363, in <module>
          main()
        File "/opt/conda/lib/python3.8/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 345, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
        File "/opt/conda/lib/python3.8/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 261, in build_wheel
          return _build_backend().build_wheel(wheel_directory, config_settings,
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 244, in build_wheel
          return self._build_with_temp_dir(['bdist_wheel'], '.whl',
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 229, in _build_with_temp_dir
          self.run_setup()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 174, in run_setup
          exec(compile(code, __file__, 'exec'), locals())
        File "setup.py", line 123, in <module>
          setup(
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/__init__.py", line 87, in setup
          return distutils.core.setup(**attrs)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/core.py", line 177, in setup
          return run_commands(dist)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/core.py", line 193, in run_commands
          dist.run_commands()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/dist.py", line 968, in run_commands
          self.run_command(cmd)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/dist.py", line 1229, in run_command
          super().run_command(command)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/dist.py", line 987, in run_command
          cmd_obj.run()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/wheel/bdist_wheel.py", line 299, in run
          self.run_command('build')
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/cmd.py", line 317, in run_command
          self.distribution.run_command(command)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/dist.py", line 1229, in run_command
          super().run_command(command)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/dist.py", line 987, in run_command
          cmd_obj.run()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/command/build.py", line 24, in run
          super().run()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/command/build.py", line 131, in run
          self.run_command(cmd_name)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/cmd.py", line 317, in run_command
          self.distribution.run_command(command)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/dist.py", line 1229, in run_command
          super().run_command(command)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/dist.py", line 987, in run_command
          cmd_obj.run()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/command/build_ext.py", line 79, in run
          _build_ext.run(self)
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/setuptools/_distutils/command/build_ext.py", line 339, in run
          self.build_extensions()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/torch/utils/cpp_extension.py", line 410, in build_extensions
          self._check_cuda_version()
        File "/tmp/pip-build-env-9or841db/overlay/lib/python3.8/site-packages/torch/utils/cpp_extension.py", line 787, in _check_cuda_version
          raise RuntimeError(CUDA_MISMATCH_MESSAGE.format(cuda_str_version, torch.version.cuda))
      RuntimeError:
      The detected CUDA version (11.3) mismatches the version that was used to compile
      PyTorch (10.2). Please make sure to use the same CUDA versions.
      
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for FastGeodis
Failed to build FastGeodis
ERROR: Could not build wheels for FastGeodis, which is required to install pyproject.toml-based projects

Discussion on the lambda parameter

Hi,

The current implementation based on Guotai's code allows for balancing the contribution of the image gradient versus the spatial distances in the metric (lambda parameter). However, the balancing process seems strange to me:

More precisely, let be given a path between a and b (x0 = a, x1, ··· , xn−1, xn = b). In the current implementation, the length of the path corresponds to:

image
where d correspond to the Euclidean distance.

  1. If lambda=0, the metric is Euclidean.
  2. If lambda=1, only the image gradient information is supposed to used in the metric. I don't think that the gradient is computed properly and I have already opened an issue here
  3. If 0<lambda<1, the formulation is uncommon to me.

For 3., I would suggest using a more standard formulation that is closed to the one in GeoS:
image
(I think that the approximation of the gradient is better, but I am very happy to get feedbacks on that!)

I have implemented this version for the FastGeodis but not for the FastMarching. Here are some results for different values of lambda:

Figure_1
Figure_2
Figure_3

Let me know what you think.

Reuben

[BUG] test errors

Describe the bug
Many tests failing/skipped. I suspect the skipped tests are gpu tests since I'm running on a CPU only system at the moment.

To Reproduce

$ python -m unittest
cpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.sssscpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.ssscpu
2
Ecpu
2
Ecpu
2
Essscpu
3
Ecpu
3
Ecpu
3
Essscpu
3
Ecpu
3
Ecpu
3
Essscpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.ssscpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.ssscpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.sssscpu
2
Ecpu
2
Ecpu
2
Essscpu
3
Ecpu
3
Ecpu
3
Essscpu
3
Ecpu
3
Ecpu
3
Essscpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.ssscpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.ssscpu
2
.cpu
2
.cpu
2
.ssscpu
3
.cpu
3
.cpu
3
.sss
======================================================================
ERROR: test_ill_shape_00_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 140, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 73, in fastgeodis_generalised_geodesic_distance_2d
    return FastGeodis.generalised_geodesic2d(image, softmask, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 62, in generalised_geodesic2d
    return FastGeodisCpp.generalised_geodesic2d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_01_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 140, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 73, in fastgeodis_generalised_geodesic_distance_2d
    return FastGeodis.generalised_geodesic2d(image, softmask, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 62, in generalised_geodesic2d
    return FastGeodisCpp.generalised_geodesic2d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_02_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 140, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 73, in fastgeodis_generalised_geodesic_distance_2d
    return FastGeodis.generalised_geodesic2d(image, softmask, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 62, in generalised_geodesic2d
    return FastGeodisCpp.generalised_geodesic2d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_06_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 140, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_07_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 140, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_08_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 140, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_spacing_0_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 304, in test_ill_spacing
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_spacing_1_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 304, in test_ill_spacing
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_spacing_2_cpu (tests.test_fastgeodis.TestFastGeodis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 304, in test_ill_spacing
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_00_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 348, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 73, in fastgeodis_generalised_geodesic_distance_2d
    return FastGeodis.generalised_geodesic2d(image, softmask, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 62, in generalised_geodesic2d
    return FastGeodisCpp.generalised_geodesic2d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_01_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 348, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 73, in fastgeodis_generalised_geodesic_distance_2d
    return FastGeodis.generalised_geodesic2d(image, softmask, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 62, in generalised_geodesic2d
    return FastGeodisCpp.generalised_geodesic2d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_02_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 348, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 73, in fastgeodis_generalised_geodesic_distance_2d
    return FastGeodis.generalised_geodesic2d(image, softmask, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 62, in generalised_geodesic2d
    return FastGeodisCpp.generalised_geodesic2d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_06_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 348, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_07_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 348, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_shape_08_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 348, in test_ill_shape
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_spacing_0_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 462, in test_ill_spacing
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_spacing_1_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 462, in test_ill_spacing
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

======================================================================
ERROR: test_ill_spacing_2_cpu (tests.test_fastgeodis.TestFastGeodisSigned)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jacobmerson/geodis/lib/python3.9/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 67, in wrapper
    return fn(*args, **kwargs)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 462, in test_ill_spacing
    geodesic_dist = geodis_func(image, mask, 1e10, 1.0, 2)
  File "/Users/jacobmerson/FastGeodis/tests/test_fastgeodis.py", line 79, in fastgeodis_generalised_geodesic_distance_3d
    return FastGeodis.generalised_geodesic3d(image, softmask, spacing, v, lamb, iter)
  File "/Users/jacobmerson/FastGeodis/FastGeodis/__init__.py", line 95, in generalised_geodesic3d
    return FastGeodisCpp.generalised_geodesic3d(
RuntimeError: Caught an unknown exception!

----------------------------------------------------------------------
Ran 134 tests in 5.071s

FAILED (errors=18, skipped=68)

Expected behavior
passing tests

Desktop (please complete the following information):

  • OS: Mac OS
  • Version 12.3.1

[FEATURE] Clarify that the results are approximations

Is your feature request related to a problem? Please describe.
The current documentation is implicit about the fact that the computed distances are approximations.

Describe the solution you'd like
The documentation could clarify that the balance in this repo is towards speed rather than accuracy.

Additional context
It might also be good to say that for the specific case of Euclidean Distance Maps, exact results can be achieved with other packages (albeit not on necessarilly on GPU):

[BUG] Testing for torch.cuda.is_available (the function not its return value) is always true

Describe the bug
Examples and notebooks make use of a construct along the lines of

device = "cuda" if torch.cuda.is_available else "cpu"

However torch.cuda.is_available is a function. One should thus test for the return value of the function rather than the function itsef. E.g.

device = "cuda" if torch.cuda.is_available() else "cpu"

To Reproduce
Run an example notebok in colab with no GPU:
https://colab.research.google.com/github/masadcv/FastGeodis/blob/master/samples/simpledemo2d.ipynb

Expected behavior
The examples and notebooks should run on CPU as well.

[BUG] GPU support only for single GPU, and the GPU ID must be "cuda:0"

Describe the bug
When you have multiple GPUs, and you want to specify a GPU (other than "cuda:0") to use, it will generate error messages, such as "CUDA error: an illegal memory access was encountered", or "CUDA error: invalid device ordinal".

To Reproduce
Steps to reproduce the behavior:

  1. Use a GPU other than the default "cuda:0". For example, generate your input on "cuda:1"
  2. Get your input to the FastGeodis function
  3. See the CUDA error

Expected behavior
Users should be able to specify which GPU to use.

Desktop (please complete the following information):

  • OS: Ubuntu
  • Version 22.04

Could you help us fix the issue? Thank you.

[BUG] Missing Symbol in Cpp backend

First of all, thanks for the great work! I have been looking for something like that for quite some time.

Describe the bug
Unfortunately, I do not manage to to get the library running as I get the error of an undefined symbol:

>>> import FastGeodis
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/denninger/anaconda3/envs/nimbro_soccer/lib/python3.10/site-packages/FastGeodis/__init__.py", line 34, in <module>
    import FastGeodisCpp
ImportError: /home/denninger/anaconda3/envs/nimbro_soccer/lib/python3.10/site-packages/FastGeodisCpp.cpython-310-x86_64-linux-gnu.so: undefined symbol: _ZN2at4_ops14conv2d_padding4callERKNS_6TensorES4_RKSt8optionalIS2_EN3c108ArrayRefINS9_6SymIntEEENS9_17basic_string_viewIcEESC_SB_

To Reproduce
I have installed the library via Pip and through the release published on GitHub. Both give the same error when trying to import FastGeodis

Desktop:

  • OS: Ubuntu 20.4.6
  • Python: 3.10.3
  • Virtual Environemnt: Conda
  • PyTorch: 2.1.2
  • Cuda-Toolkit: 12.1

Maybe somebody sees what I did wrong and can help me to fix this issue!
Greetings, Luis

[FEATURE] Add an API to provide signed distance maps

Is your feature request related to a problem? Please describe.
In several applications, having a signed distance map is helpful.

Describe the solution you'd like
Providing a simple API to get signed distance maps in FastGeodis would be great.

Describe alternatives you've considered
Compute two distance maps (one with the mask and another one with the inverted mask) and substract these

Additional context
Project-MONAI/MONAI#4603

Non-deterministic behaviour from cuda-version generalised_geodesic3d

Is your feature request related to a problem? Please describe.
The cuda-version generalised_geodesic3d has shown non-deterministic behaviour. Given the same inputs, it returns different output (geodesic map) at different runs. This is not ideal for reproducibility.
Please use the following code to reproduce the output I've observed.

"""
Demo of randomness from cuda-version generalised_geodesic3d.
"""
from typing import Tuple
import numpy as np

import torch
import FastGeodis


def torch_seed(seed: int = 42):
    # Pytorch seeding:
    torch.manual_seed(seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    if torch.cuda.is_available():
        torch.cuda.manual_seed_all(seed)
        torch.cuda.manual_seed(seed)


def demo_geodesic_distance3d(
    input_image: torch.Tensor,
    seed_map: torch.Tensor,
    spacing: Tuple[float, float, float],
    device: str,
):
    """
    Demo of 3d geodesic distance.
    """
    # Compute geodesic map using cuda-version FastGeodis
    device = "cuda"
    input_image_pt = input_image.to(device)
    seed_image_pt = (1 - seed_map).to(device)

    fastgeodis_output = np.squeeze(
        FastGeodis.generalised_geodesic3d(
            input_image_pt, seed_image_pt, spacing, 1e10, 1.0
        )
        .cpu()
        .numpy()
    )
    print(f"Sum of fastGeodis output: {np.sum(fastgeodis_output)}")


if __name__ == "__main__":
    torch_seed()
    image: torch.Tensor = torch.randint(
        low=0, high=256, size=(1, 1, 150, 150, 150)
    ).to(torch.float32)
    spacing: Tuple[int, int, int] = (1.0, 1.0, 1.0)
    seed_map: torch.Tensor = torch.full_like(image, 0)
    seed_map[0, 0, 4, 100, 50] = 1
    device: str = "cuda"

    # Compute geodesic map for multiple times using the same inputs
    for i in range(3):
        demo_geodesic_distance3d(
            input_image=image,
            spacing=spacing,
            seed_map=seed_map,
            device=device,
        )

Output - the output from generalised_geodesic3d is different at three runs:

Sum of fastGeodis output: 2537535232.0
Sum of fastGeodis output: 2542801664.0
Sum of fastGeodis output: 2540248320.0

Describe the solution you'd like
I'm not sure where the randomness comes from, but It would be nice to seed everything in the cuda-version implementation.

Additional context
FastGeodis==1.0.3

[BUG] ImportError: undefined symbol: _ZN3c104cuda20CUDACachingAllocator9allocatorE

Describe the bug
I use virtual environment and all my pytorch and cuda versions are compatible with FastGeodis. I downloaded FastGeodis with all three combination:
-pip install FastGeodis
-pip install git+https://github.com/masadcv/FastGeodis
-pip install FastGeodis --no-build-isolation
Important Note: I have tried to delete and create new virtual env or conda env. It did not solve my problem.

But, still I got this error:
import FastGeodis
File "/home/umut_dundar_smartalpha_ai/alpha_trainer/.venv/lib/python3.8/site-packages/FastGeodis/init.py", line 33, in
import FastGeodisCpp
ImportError: /home/umut_dundar_smartalpha_ai/alpha_trainer/.venv/lib/python3.8/site-packages/FastGeodisCpp.cpython-38-x86_64-linux-gnu.so: undefined symbol: _ZN3c104cuda20CUDACachingAllocator9allocatorE

It can not find the FastGeodisCpp file in FastGeodis library.

Expected behavior
I want to know how can I fix it.

Desktop (please complete the following information):

  • Ubuntu 22.04
  • aiohttp 3.8.4

CUDA VERSION == 11.8.0
efficientnet-pytorch 0.7.1
FastGeodis 1.0.3
filelock 3.12.0
flatbuffers 23.5.26
flatten-dict 0.4.2
flufl.lock 7.1.1
frozenlist 1.3.3
fsspec 2023.5.0
funcy 2.0
gitdb 4.0.10
GitPython 3.1.31
google-api-core 2.11.0
google-auth 2.19.0
google-cloud-core 2.3.2
google-cloud-storage 2.9.0
google-crc32c 1.5.0
google-resumable-media 2.5.0
googleapis-common-protos 1.59.0
grandalf 0.8
huggingface-hub 0.14.1
humanfriendly 10.0
hydra-colorlog 1.2.0
hydra-core 1.3.2
idna 3.4
imageio 2.30.0
importlib-resources 5.12.0
iterative-stratification 0.1.7
iterative-telemetry 0.0.8
joblib 1.2.0
kombu 5.2.4
kornia 0.6.12
lazy-loader 0.2
lightning-utilities 0.8.0
markdown-it-py 2.2.0
mdurl 0.1.2
mpmath 1.3.0
multidict 6.0.4
munch 3.0.0
nanotime 0.5.2
networkx 3.1
numpy 1.24.3
omegaconf 2.3.0
onnx 1.14.0
onnxruntime 1.15.0
onnxsim 0.4.28
opencv-python-headless 4.7.0.72
orjson 3.8.14
packaging 23.1
pandas 2.0.2
pathspec 0.11.1
pathtools 0.1.2
Pillow 9.5.0
pip 20.0.2
pkg-resources 0.0.0
platformdirs 3.5.1
pretrainedmodels 0.7.4
prompt-toolkit 3.0.38
protobuf 4.23.2
psutil 5.9.5
pyasn1 0.5.0
pyasn1-modules 0.3.0
pycparser 2.21
pydot 1.4.2
pygit2 1.12.1
Pygments 2.15.1
pygtrie 2.5.0
pyparsing 3.0.9
python-dateutil 2.8.2
pytorch-lightning 1.9.5
pytorch-ranger 0.1.1
pytz 2023.3
PyWavelets 1.4.1
PyYAML 6.0
qudida 0.0.4
regex 2023.5.5
requests 2.31.0
rich 13.4.1
rsa 4.9
ruamel.yaml 0.17.31
ruamel.yaml.clib 0.2.7
safetensors 0.3.1
scikit-image 0.20.0
scikit-learn 1.2.2
scipy 1.10.1
scmrepo 1.0.3
segmentation-models-pytorch 0.3.3
sentry-sdk 1.24.0
setproctitle 1.3.2
setuptools 44.0.0
shortuuid 1.0.11
shtab 1.6.1
six 1.16.0
smmap 5.0.0
sqltrie 0.3.1
sympy 1.12
tabulate 0.9.0
threadpoolctl 3.1.0
tifffile 2023.4.12
timm 0.9.2
tokenizers 0.13.3
tomlkit 0.11.8
torch 1.13.1+cu117
torch-optimizer 0.3.0
torchmetrics 0.11.0
torchvision 0.14.1+cu117
tqdm 4.65.0
transformers 4.29.2

[FEATURE] Provide optimised version of signed geodesic and euclidean distance transform

Is your feature request related to a problem? Please describe.
Currently the library support signed distance transforms by taking two distance transforms and subtracting them.
This could be optimised further for example as discussed here #9

Describe the solution you'd like
Implement signed distance transforms with better optimisation

Describe alternatives you've considered
Using the current signed distance transform methods provided in FastGeodis. These work but have room for further optimisation

Additional context
This could improve interactive segmentation methods execution time, especially implementation for method called Geos from:

Criminisi, Antonio, Toby Sharp, and Andrew Blake. "Geos: Geodesic image segmentation." European Conference on Computer Vision. Springer, Berlin, Heidelberg, 2008.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.