From a0e9973123ba8f270c3f488881db6d377ff202ea Mon Sep 17 00:00:00 2001 From: Henrik Kjedsberg Date: Tue, 28 Jun 2022 21:55:33 +0200 Subject: [PATCH 1/6] Prepare for VMTK 1.5 support --- README.md | 4 ++-- .../automated_landmarking_tools.py | 2 +- morphman/common/vtk_wrapper.py | 9 +++++---- morphman/manipulate_branch.py | 4 ++-- morphman/manipulate_surface.py | 2 +- morphman/misc/estimate_alpha_and_beta.py | 2 +- setup.py | 2 +- test/fixtures.py | 17 +++++++---------- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 9bb438b8..23ac225e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Licence morphMan is licensed under the GNU GPL, version 3 or (at your option) any later version. -morphMan is Copyright (2016-2021) by the authors. +morphMan is Copyright (2016-2022) by the authors. Documentation ------------- @@ -56,7 +56,7 @@ Installation For reference, morphMan requires the following dependencies: VTK > 8.1, Numpy <= 1.13, SciPy > 1.0.0, and VMTK 1.4. If you are on Windows, macOS or Linux you can install all the general dependencies through anaconda. -First install Anaconda or Miniconda (preferably the Python 3.6 version). +First install Anaconda or Miniconda (preferably the Python 3.10 version). Then execute the following command conda create -n your_environment -c vmtk -c morphman morphman diff --git a/morphman/automated_landmarking/automated_landmarking_tools.py b/morphman/automated_landmarking/automated_landmarking_tools.py index 4d444046..04e1b6e2 100644 --- a/morphman/automated_landmarking/automated_landmarking_tools.py +++ b/morphman/automated_landmarking/automated_landmarking_tools.py @@ -5,7 +5,7 @@ ## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ## PURPOSE. See the above copyright notices for more information. -from scipy.ndimage.filters import gaussian_filter +from scipy.ndimage import gaussian_filter from scipy.signal import argrelextrema from vmtk import vmtkrenderer from vtk.numpy_interface import dataset_adapter as dsa diff --git a/morphman/common/vtk_wrapper.py b/morphman/common/vtk_wrapper.py index b0754a93..d776b1f3 100644 --- a/morphman/common/vtk_wrapper.py +++ b/morphman/common/vtk_wrapper.py @@ -156,7 +156,7 @@ def read_polydata(filename, datatype=None): elif fileType == "vti": reader = vtk.vtkXMLImageDataReader() elif fileType == "np" and datatype == "vtkIdList": - result = np.load(filename).astype(np.int) + result = np.load(filename, allow_pickle=True).astype(int) id_list = vtk.vtkIdList() id_list.SetNumberOfIds(result.shape[0]) for i in range(result.shape[0]): @@ -446,11 +446,12 @@ def vtk_compute_threshold(surface, name, lower=0, upper=1, threshold_type="betwe vtk_threshold = vtk.vtkThreshold() vtk_threshold.SetInputData(surface) if threshold_type == "between": - vtk_threshold.ThresholdBetween(lower, upper) + vtk_threshold.SetLowerThreshold(lower) + vtk_threshold.SetUpperThreshold(upper) elif threshold_type == "lower": - vtk_threshold.ThresholdByLower(lower) + vtk_threshold.SetLowerThreshold(lower) elif threshold_type == "upper": - vtk_threshold.ThresholdByUpper(upper) + vtk_threshold.SetUpperThreshold(upper) else: print((("%s is not a threshold type. Pleace chose from: upper, lower" + ", or between") % threshold_type)) diff --git a/morphman/manipulate_branch.py b/morphman/manipulate_branch.py index 03692d0e..0bebee6c 100644 --- a/morphman/manipulate_branch.py +++ b/morphman/manipulate_branch.py @@ -155,8 +155,8 @@ def get_centerline_for_splitting_voronoi(centerlines, starting_point, base_path, outlet = list(lines[0].GetPoint(lines[0].GetNumberOfPoints()-1) + lines[0].GetPoint(0)) reversed_cl, _, _ = compute_centerlines(inlet, outlet, base_path + "_outlet_to_branch.vtp", - capped_surface, voronoi=voronoi, - pole_ids=pole_ids, resampling=resampling_step, + capped_surface, + resampling=resampling_step, smooth=False) # Extract each line reversed_cl_main = extract_single_line(reversed_cl, 1) diff --git a/morphman/manipulate_surface.py b/morphman/manipulate_surface.py index 97b7b5f8..1d635910 100644 --- a/morphman/manipulate_surface.py +++ b/morphman/manipulate_surface.py @@ -390,7 +390,7 @@ def read_command_line_surface(input_path=None, output_path=None): else: args = parser.parse_args(["-i" + input_path, "-o" + output_path]) - if args.region_of_interest == "commandline" and "region_points" is not None: + if args.region_of_interest == "commandline" and args.region_points is not None: raise ArgumentTypeError("When setting region of interest to commandline you have to" + " provide the points through the argument '--regions-points'") diff --git a/morphman/misc/estimate_alpha_and_beta.py b/morphman/misc/estimate_alpha_and_beta.py index ec8ab491..98ca5076 100644 --- a/morphman/misc/estimate_alpha_and_beta.py +++ b/morphman/misc/estimate_alpha_and_beta.py @@ -9,7 +9,7 @@ from argparse import ArgumentParser, RawDescriptionHelpFormatter from scipy import interpolate -from scipy.ndimage.filters import gaussian_filter +from scipy.ndimage import gaussian_filter from scipy.signal import argrelextrema # Local import diff --git a/setup.py b/setup.py index 8ba08ad9..08dc9875 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ DEPENDENCIES = [] # 'scipy', 'numpy', 'vtk'] TEST_DEPENDENCIES = [] # 'pytest'] -VERSION = "1.1" +VERSION = "1.2" URL = "https://github.com/KVSlab/morphMan.git" setuptools.setup( diff --git a/test/fixtures.py b/test/fixtures.py index 1fb00158..8e1fb955 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -5,23 +5,19 @@ ## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ## PURPOSE. See the above copyright notices for more information. -from os import system, path +from os import system, path, makedirs from sys import platform import pytest -from morphman.common import get_inlet_and_outlet_centers, get_path_names, compute_centerlines, prepare_surface +from morphman.common import get_inlet_and_outlet_centers, get_path_names, compute_centerlines, prepare_surface def download_testdata(test_path, outputfile): if platform == "darwin": - system("curl {} --output {}".format(test_path, outputfile)) - system("tar -zxvf {}".format(outputfile)) - system("rm {}".format(outputfile)) + system("curl -L {} --output {}".format(test_path, outputfile)) elif platform == "linux" or platform == "linux2": system("wget {}".format(test_path)) - system("tar -zxvf {}".format(outputfile)) - system("rm {}".format(outputfile)) elif platform == "win32": system("bitsadmin /transfer download_model /download /priority high {} {}".format(test_path, outputfile)) system("tar -zxvf {}".format(outputfile)) @@ -33,12 +29,13 @@ def surface_paths(): abs_path = path.dirname(path.abspath(__file__)) # Path to test data - test_path = "http://ecm2.mathcs.emory.edu/aneuriskdata/download/C0001/C0001_models.tar.gz" - outputfile = path.join(abs_path, "C0001_models.tar.gz") + test_path = "https://github.com/hkjeldsberg/AneuriskDatabase/raw/master/models/C0001/surface/model.vtp" + outputfile = path.join(abs_path, "C0001", "surface", "model.vtp") # Download test data if necessary - if not path.exists(path.join(abs_path, "C0001")): + if not path.exists(path.join(abs_path, "C0001", "surface", "model.vtp")): try: + makedirs(path.join(abs_path, "C0001", "surface")) download_testdata(test_path, outputfile) except Exception: raise Exception("Problem downloading the testdata, please do it manually from " From 2d2e2b26d409cc67b7b982661c1abfc9e4298ae3 Mon Sep 17 00:00:00 2001 From: Henrik Kjedsberg Date: Tue, 28 Jun 2022 23:18:31 +0200 Subject: [PATCH 2/6] Fix diverging centerline id --- morphman/common/centerline_operations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/morphman/common/centerline_operations.py b/morphman/common/centerline_operations.py index 6b15a586..57b2c568 100644 --- a/morphman/common/centerline_operations.py +++ b/morphman/common/centerline_operations.py @@ -458,7 +458,7 @@ def get_line_to_change(surface, centerline, region_of_interest, method, region_p # Find diverging ids diverging_ids = [] - main_line = extract_single_line(centerline, 0) + main_line = extract_single_line(centerline, cl_id) id_start = 0 for line in diverging_centerlines: id_end = min([line.GetNumberOfPoints(), main_line.GetNumberOfPoints()]) From d8be5f481a2631df2da5c13908aa8ab49c87635e Mon Sep 17 00:00:00 2001 From: Henrik Kjedsberg Date: Tue, 28 Jun 2022 23:53:44 +0200 Subject: [PATCH 3/6] Update CI for linux and windows Skip two tests for windows (access violation) Improve vtk wrapper tests --- .circleci/config.yml | 11 ++--- appveyor.yml | 33 +++---------- conda-build/conda_build_config.yaml | 9 ++-- conda-build/meta.yaml | 2 +- test/fixtures.py | 9 ++-- test/test_surface_operations.py | 24 +++++----- test/test_vtk_wrapper.py | 73 +++++++++++++++-------------- 7 files changed, 71 insertions(+), 90 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e0594d90..5f2efe2d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ workflows: jobs: install-and-test: docker: - - image: cimg/python:3.6 + - image: cimg/python:3.10 working_directory: ~/repo steps: - checkout @@ -27,11 +27,11 @@ jobs: # Set conda parameters conda config --set restore_free_channel true conda config --set always_yes yes --set changeps1 no - conda config --add channels vmtk + conda config --add channels conda-forge conda config --add channels morphman # Set up environment - conda create -n morphman morphman pytest llvm=3.3 + conda create -n morphman morphman # Activate environment source activate morphman @@ -42,11 +42,6 @@ jobs: # Dependencies for code coverage pip install pytest-cov codecov - # Edit VMTK files - sed -i -e 's/len(self.SourcePoints)\/3/len\(self.SourcePoints\)\/\/3/g' $HOME/miniconda/envs/morphman/lib/python3.6/site-packages/vmtk/vmtkcenterlines.py - sed -i -e 's/len(self.TargetPoints)\/3/len\(self.TargetPoints\)\/\/3/g' $HOME/miniconda/envs/morphman/lib/python3.6/site-packages/vmtk/vmtkcenterlines.py - sed -i -e 's/(len(values) - 1)\/2/\(len\(values\) - 1\)\/\/2/g' $HOME/miniconda/envs/morphman/lib/python3.6/site-packages/vmtk/vmtksurfacecurvature.py - # Run tests cd test pytest --cov=./ diff --git a/appveyor.yml b/appveyor.yml index d62c3d10..a040859d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,19 +17,12 @@ environment: CONDA_INSTALL_LOCN: "C:\\Miniconda-x64" matrix: - - PYTHON: "C:\\Python35_64" - PYTHON_VERSION: "3.5" + - PYTHON: "C:\\Python39_64" + PYTHON_VERSION: "3.9" PYTHON_ARCH: "64" - CONDA_PY: "35" + CONDA_PY: "39" CONDA_NPY: "18" - APP_CONDA_PY: "3.5.1" - - - PYTHON: "C:\\Python36_64" - PYTHON_VERSION: "3.6" - PYTHON_ARCH: "64" - CONDA_PY: "36" - CONDA_NPY: "18" - APP_CONDA_PY: "3.6.1" + APP_CONDA_PY: "3.9.1" platform: - x64 @@ -43,33 +36,21 @@ install: - cmd: conda config --set always_yes yes - cmd: conda update --quiet conda - cmd: conda install --quiet jinja2 conda-build=3.10.5 anaconda-client - - cmd: conda config --set restore_free_channel true # Add custom channels - - cmd: conda config --add channels vmtk + - cmd: conda config --add channels conda-forge - cmd: conda config --add channels morphman - # Install dependencies - - cmd: conda install pytest scipy vtk vmtk python=3.6 - # Set up environment - - cmd: conda create -n morphman_env morphman + - cmd: conda create -n morphman morphman pytest build: false test_script: # Activate environment - cmd: conda init cmd.exe - - cmd: conda activate morphman_env - - # Search and replace in vmtkcenterlines.py for / to // - - cmd: sed -i "s/len(self.SourcePoints)\/3/len\(self.SourcePoints\)\/\/3/g" %CONDA_INSTALL_LOCN%\\Lib\\site-packages\\vmtk\\vmtkcenterlines.py - - cmd: sed -i "s/len(self.TargetPoints)\/3/len\(self.TargetPoints\)\/\/3/g" %CONDA_INSTALL_LOCN%\\Lib\\site-packages\\vmtk\\vmtkcenterlines.py - - cmd: sed -i -e "s/(len(values) - 1)\/2/\(len\(values\) - 1\)\/\/2/g" %CONDA_INSTALL_LOCN%\\Lib\\site-packages\\vmtk\\vmtksurfacecurvature.py + - cmd: conda activate morphman # Start testing - cd .\\test - - ps: Start-FileDownload 'http://ecm2.mathcs.emory.edu/aneuriskdata/download/C0001/C0001_models.tar.gz' - - tar --force-local -zxvf C0001_models.tar.gz - - del /f C0001_models.tar.gz - pytest . diff --git a/conda-build/conda_build_config.yaml b/conda-build/conda_build_config.yaml index fad06c4c..255867ac 100644 --- a/conda-build/conda_build_config.yaml +++ b/conda-build/conda_build_config.yaml @@ -1,9 +1,10 @@ numpy: - - 1.13.* + - 1.23.* python: - - 3.5.1 - - 3.6.1 + - 3.8.* + - 3.9.* + - 3.10.* vtk: - - 8.1.0 + - 9.1.* diff --git a/conda-build/meta.yaml b/conda-build/meta.yaml index f9c6a4eb..cae585da 100644 --- a/conda-build/meta.yaml +++ b/conda-build/meta.yaml @@ -1,6 +1,6 @@ package: name: "morphman" - version: "1.1" + version: "1.2" source: path: ../ diff --git a/test/fixtures.py b/test/fixtures.py index 8e1fb955..45623556 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -17,11 +17,9 @@ def download_testdata(test_path, outputfile): if platform == "darwin": system("curl -L {} --output {}".format(test_path, outputfile)) elif platform == "linux" or platform == "linux2": - system("wget {}".format(test_path)) + system("wget -O {} {}".format(outputfile, test_path)) elif platform == "win32": system("bitsadmin /transfer download_model /download /priority high {} {}".format(test_path, outputfile)) - system("tar -zxvf {}".format(outputfile)) - system("del /f {}".format(outputfile)) @pytest.fixture(scope="module") @@ -29,13 +27,16 @@ def surface_paths(): abs_path = path.dirname(path.abspath(__file__)) # Path to test data + # TODO: Replace with official Aneurisk database when available test_path = "https://github.com/hkjeldsberg/AneuriskDatabase/raw/master/models/C0001/surface/model.vtp" outputfile = path.join(abs_path, "C0001", "surface", "model.vtp") # Download test data if necessary + if not path.exists(path.join(abs_path, "C0001", "surface")): + makedirs(path.join(abs_path, "C0001", "surface")) + if not path.exists(path.join(abs_path, "C0001", "surface", "model.vtp")): try: - makedirs(path.join(abs_path, "C0001", "surface")) download_testdata(test_path, outputfile) except Exception: raise Exception("Problem downloading the testdata, please do it manually from " diff --git a/test/test_surface_operations.py b/test/test_surface_operations.py index 5845030b..7f223e2c 100644 --- a/test/test_surface_operations.py +++ b/test/test_surface_operations.py @@ -7,6 +7,19 @@ from .fixtures import surface_paths from morphman.common.surface_operations import * +import sys +import pytest + +@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") +def test_uncapp_surface(surface_paths): + input_filepath = surface_paths[0] + surface = read_polydata(input_filepath) + capped = vmtk_cap_polydata(surface) + + uncapped = get_uncapped_surface(capped) + + is_capped, _ = is_surface_capped(uncapped) + assert not is_capped def test_relevant_outlets(surface_paths): @@ -62,17 +75,6 @@ def test_capped_surface(surface_paths): assert number_outlets == 7 -def test_uncapp_surface(surface_paths): - input_filepath = surface_paths[0] - surface = read_polydata(input_filepath) - capped = vmtk_cap_polydata(surface) - - uncapped = get_uncapped_surface(capped) - - is_capped, _ = is_surface_capped(uncapped) - assert not is_capped - - def test_if_surface_is_merged(surface_paths): input_filepath = surface_paths[0] base_path = get_path_names(input_filepath) diff --git a/test/test_vtk_wrapper.py b/test/test_vtk_wrapper.py index 52c5d4bb..c8212bac 100644 --- a/test/test_vtk_wrapper.py +++ b/test/test_vtk_wrapper.py @@ -9,6 +9,43 @@ from morphman.common.surface_operations import * from morphman.common.vtk_wrapper import * import os +import sys +import pytest + +@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") +def test_compute_gradients(surface_paths): + input_filepath = surface_paths[0] + surface = read_polydata(input_filepath) + + cell_normals = vtk_compute_polydata_normals(surface, compute_cell_normals=True) + gradients = vtk_compute_normal_gradients(cell_normals) + + assert gradients.GetNumberOfCells() > 0 + + +def test_vtk_threshold(surface_paths): + input_filepath = surface_paths[0] + surface = read_polydata(input_filepath) + + cell_normals = vtk_compute_polydata_normals(surface, compute_cell_normals=True) + normals_threshold = vtk_compute_threshold(cell_normals, "Normals") + + assert normals_threshold.GetNumberOfCells() < cell_normals.GetNumberOfCells() + + +def test_get_cell_data_array(surface_paths): + input_filepath = surface_paths[0] + surface = read_polydata(input_filepath) + dim = 3 + + cell_normals = vtk_compute_polydata_normals(surface, compute_cell_normals=True) + normals_array = get_cell_data_array("Normals", cell_normals, k=dim) + + assert type(normals_array) == np.ndarray + + assert len(normals_array) == surface.GetNumberOfCells() + + assert len(normals_array.T) == dim def test_read_polydata(surface_paths): @@ -76,30 +113,6 @@ def test_compute_normals(surface_paths): assert cell_normals.GetNumberOfCells() > 0 -def test_compute_gradients(surface_paths): - input_filepath = surface_paths[0] - surface = read_polydata(input_filepath) - - cell_normals = vtk_compute_polydata_normals(surface, compute_cell_normals=True) - gradients = vtk_compute_normal_gradients(cell_normals) - - assert gradients.GetNumberOfCells() > 0 - - -def test_get_cell_data_array(surface_paths): - input_filepath = surface_paths[0] - surface = read_polydata(input_filepath) - - cell_normals = vtk_compute_polydata_normals(surface, compute_cell_normals=True) - gradients = vtk_compute_normal_gradients(cell_normals) - - gradient_array = get_cell_data_array("Gradients", gradients, k=9) - - assert type(gradient_array) == np.ndarray - - assert len(gradient_array) == gradients.GetNumberOfCells() - - def test_get_point_data_array(surface_paths): input_filepath = surface_paths[0] base_path = get_path_names(input_filepath) @@ -129,18 +142,6 @@ def test_surface_connectivity(surface_paths): assert connected_surface.GetNumberOfCells() == surface.GetNumberOfCells() -def test_vtk_threshold(surface_paths): - input_filepath = surface_paths[0] - surface = read_polydata(input_filepath) - - cell_normals = vtk_compute_polydata_normals(surface, compute_cell_normals=True) - gradients = vtk_compute_normal_gradients(cell_normals) - - gradients_threshold = vtk_compute_threshold(gradients, "Gradients") - - assert gradients_threshold.GetNumberOfCells() < gradients.GetNumberOfCells() - - def test_get_boundary_edges(surface_paths): input_filepath = surface_paths[0] surface = read_polydata(input_filepath) From ba5522667d84baa7ed48249d3a6ea66cae304ab5 Mon Sep 17 00:00:00 2001 From: Henrik Kjedsberg Date: Wed, 29 Jun 2022 21:14:48 +0200 Subject: [PATCH 4/6] Update download link to Aneurisk in demos --- demo/demo_manipulate_surface.py | 2 +- demo/get_test_data.py | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/demo/demo_manipulate_surface.py b/demo/demo_manipulate_surface.py index 86c2ddab..6ccd2e4a 100644 --- a/demo/demo_manipulate_surface.py +++ b/demo/demo_manipulate_surface.py @@ -44,7 +44,7 @@ default_values["poly_ball_size"] = [250, 250, 250] # Run manipulation - smooth the entire geometry except aneurysm dome -#manipulate_surface(**default_values) +manipulate_surface(**default_values) ### Add noise to the surface # Output file path diff --git a/demo/get_test_data.py b/demo/get_test_data.py index de32c70a..adfbe1a8 100644 --- a/demo/get_test_data.py +++ b/demo/get_test_data.py @@ -5,30 +5,26 @@ ## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ## PURPOSE. See the above copyright notices for more information. -from os import system, path +from os import system, path, makedirs from sys import platform def download_case(case): abs_path = path.dirname(path.abspath(__file__)) - output_file = path.join(abs_path, "{}_models.tar.gz".format(case)) - url = "http://ecm2.mathcs.emory.edu/aneuriskdata/download/{}/{}_models.tar.gz".format(case, case) + output_file = path.join(abs_path, case, "surface", "model.vtp") + url = "https://github.com/hkjeldsberg/AneuriskDatabase/raw/master/models/{}/surface/model.vtp".format(case) + + # Create test data folders + if not path.exists(path.join(abs_path, case, "surface")): + makedirs(path.join(abs_path, case, "surface")) try: if platform == "darwin": - system("curl {} --output {}".format(url, output_file)) - system("tar -zxvf {}".format(output_file)) - system("rm {}".format(output_file)) - + system("curl -L {} --output {}".format(url, output_file)) elif platform == "linux" or platform == "linux2": - system("wget {}".format(url)) - system("tar -zxvf {}".format(output_file)) - system("rm {}".format(output_file)) - + system("wget -O {} {}".format(output_file, url)) elif platform == "win32": system("bitsadmin /transfer download_model /download /priority high {} {}".format(url, output_file)) - system("tar -zxvf {}".format(output_file)) - system("del /f {}".format(output_file)) except: raise RuntimeError("Problem downloading the testdata, please do it manually from " From d57ec8d049cce827997c4945ae08e80b2c38c206 Mon Sep 17 00:00:00 2001 From: Henrik Kjedsberg Date: Wed, 29 Jun 2022 21:59:50 +0200 Subject: [PATCH 5/6] Update documentation to reflect VMTK 1.5.0 --- docs/source/Miscellaneous.rst | 4 +- docs/source/conf.py | 6 +-- docs/source/installation.rst | 60 ++++++++++---------------- docs/source/manipulate_area.rst | 2 +- docs/source/manipulate_bend.rst | 2 +- docs/source/manipulate_bifurcation.rst | 4 +- docs/source/manipulate_branch.rst | 2 +- docs/source/manipulate_curvature.rst | 2 +- docs/source/manipulate_surface.rst | 6 +-- 9 files changed, 34 insertions(+), 54 deletions(-) diff --git a/docs/source/Miscellaneous.rst b/docs/source/Miscellaneous.rst index 2f0cbd05..4f3eda48 100644 --- a/docs/source/Miscellaneous.rst +++ b/docs/source/Miscellaneous.rst @@ -38,7 +38,7 @@ the geometric properties (curvature and torsion) of the centerline, set with 2. Discrete derivatives (``disc``) 3. VMTK (``vmtk``) -To perform landmarking, we will be using the model with `ID C0001 `_ +To perform landmarking, we will be using the model with `ID C0001 `_ from the Aneurisk database. For the commands below we assume that there is a file `./C0001/surface/model.vtp`, relative to where you execute the command. To landmark the surface model, run the following command:: @@ -71,7 +71,7 @@ manipulates only the centerline for a range of ``--alpha`` and ``--beta`` values. The resulting 2D data can be fitted to a surface through cubic spline interpolation, from which one can easily collect appropriate values for ``--alpha`` and ``--beta``. -To estimate :math:`\alpha` and :math:`\beta`, we will be using the model with `ID C0005 `_ +To estimate :math:`\alpha` and :math:`\beta`, we will be using the model with `ID C0005 `_ from the Aneurisk database. For the commands below we assume that there is a file `./C0005/surface/model.vtp`, relative to where you execute the command. Imagine we are interested in changing the bend angle by :math:`\pm 10^{\circ}`. diff --git a/docs/source/conf.py b/docs/source/conf.py index ac59ece4..91242959 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -28,13 +28,13 @@ # -- Project information ----------------------------------------------------- project = 'morphman' -copyright = '2021, Aslak W. Bergersen & Henrik A. Kjeldsberg' +copyright = '2022, Aslak W. Bergersen & Henrik A. Kjeldsberg' author = 'Aslak W. Bergersen & Henrik A. Kjeldsberg' # The short X.Y version. -version = '1.1' +version = '1.2' # The full version, including alpha/beta/rc tags -release = '1.1' +release = '1.2' # -- General configuration --------------------------------------------------- diff --git a/docs/source/installation.rst b/docs/source/installation.rst index de911a44..447d1fcc 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -1,30 +1,35 @@ .. title:: Installation +.. highlight:: console ============ Installation ============ + morphMan (morphological manipulation) is a collection of scripts to objectively manipulate morphological features of patient-specific vascular geometries. The project is accessible through -`GitHub `_ and `Anaconda `_. +`GitHub `_ and `Anaconda.org `_. Compatibility and Dependencies ============================== The general dependencies of morphMan are -* VMTK 1.4.0 -* VTK 8.1.0 -* Numpy <= 1.13 -* SciPy 1.1.0 -* Python (2.7 or >=3.5) +* VMTK 1.5.0 +* VTK 9.1.0 +* Numpy 1.23 +* SciPy 1.8.1 +* Python >=3.8 Basic Installation ================== We recommend that you can install morphMan through Anaconda. -First, install Anaconda or Miniconda (preferably the Python 3.6 version). -Then execute the following command in a terminal window:: +First, install `Anaconda `_ or `Miniconda `_. +Then execute the following command in a terminal window to create a Conda environment with morphMan installed:: + + $ conda create -n your_environment -c conda-forge -c morphman morphman - $ conda create -n your_environment -c vmtk -c morphman morphman +.. note:: + Replace ``your_environment`` with the environment name. You can then activate your environment by running ``source activate your_environment``. Now you are all set, and can start using morphMan. morphMan can be accessed by opening a Python console @@ -39,32 +44,6 @@ Alternatively you can use one of the six main methods of manipulation directly t followed by the command line arguments for the selected method. A detailed explanation for usage of morphMan is described in :ref:`getting_started`. -.. WARNING:: The VMTK version 1.4, the one currently distributed with Anaconda, has a Python3 bug in `vmtkcenterlines` and `vmtksurfacecurvature`. As a workaround you have to change these files. To find out where it is located please execute:: - - $ which vmtkcenterlines - /Users/[Name]/anaconda3/envs/[your_environment]/bin/vmtkcenterlines - $ python -V - Python 3.6.2 :: Continuum Analytics, Inc. - - Now copy the path up until ``[your_environment]`` and add ``lib/python3.6/site-packages/vmtk/vmtkcenterlines.py``. Please change the path separation symbol to match your operating system and change ``python3.6`` to the python version you are using. If you are using Miniconda, replace `anaconda3` with `miniconda3`. Using this path you can run the two following lines:: - - $ sed -i -e 's/len(self.SourcePoints)\/3/len\(self.SourcePoints\)\/\/3/g' /Users/[Name]/anaconda3/envs/[your_environment]/lib/python3.6/site-packages/vmtk/vmtkcenterlines.py - $ sed -i -e 's/len(self.TargetPoints)\/3/len\(self.TargetPoints\)\/\/3/g' /Users/[Name]/anaconda3/envs/[your_environment]/lib/python3.6/site-packages/vmtk/vmtkcenterlines.py - - Similarly, for `vmtksurfacecurvature.py`, run the following command:: - - $ sed -i -e 's/(len(values) - 1)\/2/\(len\(values\) - 1\)\/\/2/g' /Users/[Name]/anaconda3/envs/[your_environment]/lib/python3.6/site-packages/vmtk/vmtksurfacecurvature.py - - -.. WARNING:: Some users may experience the following Python compatibility issue:: - - ModuleNotFoundError: No module named 'vtkRenderingOpenGL2Python' - - To fix this issue, a temporary solution is the install the ``llvm`` library directly in the virtual environment, using the following commands:: - - $ conda config --set restore_free_channel true - $ conda install llvm=3.3 - Development version =================== @@ -72,12 +51,13 @@ Downloading ~~~~~~~~~~~ The latest development version of morphMan can be found on the official `morphMan git repository `_ on GitHub. -Make sure Git (>=1.6) is installed, which is needed to clone the repository. +Make sure `Git `_ is installed, which is needed to clone the repository. To clone the morphMan repository, navigate to the directory where you wish morphMan to be stored, type the following command, and press Enter:: - $ git clone https://github.com/KVSlab/morphMan + $ git clone https://github.com/KVSlab/morphMan +If it not already present, this will install Python for you. After the source distribution has been downloaded, all the files required will be located in the newly created ``morphMan`` folder. @@ -85,7 +65,11 @@ Building ~~~~~~~~ In order to build and install morphMan, navigate into the ``morphMan`` folder, where a ``setup.py`` file will be located. First, make sure that all dependencies are installed. Then, building and installation of morphMan -can be performed by simply running the following command from the terminal window:: +can be performed with ``pip`` by running the following command:: + + $ python -m pip install . + +Alternatively, morphMan can be installed using Python directly (deprecated):: $ python setup.py install diff --git a/docs/source/manipulate_area.rst b/docs/source/manipulate_area.rst index 889a5118..4bb69ae4 100644 --- a/docs/source/manipulate_area.rst +++ b/docs/source/manipulate_area.rst @@ -13,7 +13,7 @@ demo folder where we show how to run this tutorial from a Python script, please run the demos. In this tutorial, we are using the model with -`ID C0002 `_ +`ID C0002 `_ from the Aneurisk database. For the commands below we assume that there is a file `./C0002/surface/model.vtp`, relative to where you execute the command. For changing the area you first need to define which segment you want to alter. For ``morphman-area`` there are diff --git a/docs/source/manipulate_bend.rst b/docs/source/manipulate_bend.rst index 06bbf20c..8982e686 100644 --- a/docs/source/manipulate_bend.rst +++ b/docs/source/manipulate_bend.rst @@ -24,7 +24,7 @@ respectively. For a detailed description on how we have defined of the vectors :math:`\alpha` and :math:`\beta`, see [1]_. In this tutorial, we are using the model with -`ID C0005 `_ +`ID C0005 `_ from the Aneurisk database. For the commands below we assume that there is a folder a `./C0005/surface/model.vtp`, relative to where you execute the command. diff --git a/docs/source/manipulate_bifurcation.rst b/docs/source/manipulate_bifurcation.rst index 4b0b812f..c0903fbe 100644 --- a/docs/source/manipulate_bifurcation.rst +++ b/docs/source/manipulate_bifurcation.rst @@ -18,7 +18,7 @@ The algorithm builds on previous work of Ford et al. [1]_ Figure 1: An illustration of the goal of ``morphman-bifurcation``. In this tutorial, we are using the model with -`ID C0005 `_ +`ID C0005 `_ from the Aneurisk database. For the commands below we assume that there is a file `./C0005/surface/model.vtp`, relative to where you execute the command. Performing the manipulation can be achieved by running ``morphman-bifurcation`` in the terminal, followed by the @@ -62,7 +62,7 @@ The default is to rotate both branches, but if either ``--keep-fixed-1`` or fixed, respectively. Furthermore, if both parameters are set to **True** then the algorithm can be used to remove an aneurysm (a balloon-shaped bleb on the artery), see Figure 4. To this specific tutorial, we have used the model -with `ID C0066 `_ +with `ID C0066 `_ , which harbors an aneurysm located at the terminal bifurcation in the internal carotid artery. .. figure:: remove_aneurysm.png diff --git a/docs/source/manipulate_branch.rst b/docs/source/manipulate_branch.rst index e017f7a5..ab1697f0 100644 --- a/docs/source/manipulate_branch.rst +++ b/docs/source/manipulate_branch.rst @@ -21,7 +21,7 @@ run the demos. Figure 1: An illustration of the desired output from the method. In this tutorial, we are using the model with -`ID C0002 `_ +`ID C0002 `_ from the Aneurisk database. For the commands below we assume that there is a file `./C0002/surface/model.vtp`, relative to where you execute the command. diff --git a/docs/source/manipulate_curvature.rst b/docs/source/manipulate_curvature.rst index 42d34129..2231c377 100644 --- a/docs/source/manipulate_curvature.rst +++ b/docs/source/manipulate_curvature.rst @@ -19,7 +19,7 @@ run the demos. Figure 1: An illustration of the desired output from the method. In this tutorial, we are using the model with -`ID C0005 `_ +`ID C0005 `_ from the Aneurisk database. For the commands below we assume that there is a file `./C0005/surface/model.vtp`, relative to where you execute the command. diff --git a/docs/source/manipulate_surface.rst b/docs/source/manipulate_surface.rst index 1b9d0f41..ffcb3b81 100644 --- a/docs/source/manipulate_surface.rst +++ b/docs/source/manipulate_surface.rst @@ -11,14 +11,12 @@ either remove or add points to the Voronoi diagram. An advantage of this, compar to more classical smoothing methods, is that the change in surface is purely local, and does not effect the cross-sectional area. -The algorithm builds on previous work of Ford et al. [1]_ - .. figure:: Surface_illustration.png Figure 1: An illustration of the goal of ``morphman-surface``. In this tutorial, we are using the model with -`ID C0005 `_ +`ID C0005 `_ from the Aneurisk database. For the commands below we assume that there is a file `./C0005/surface/model.vtp`, relative to where you execute the command. Performing the manipulation can be achieved by running ``morphman-surface`` in the terminal, followed by the @@ -50,5 +48,3 @@ You can reproduce the results in Figure 3 by running the following command:: For additional information, beyond this tutorial, on the script and input parameters, please run ``morphman-surface -h`` or confer with the :meth:`manipulate_surface`. - -.. [1] Ford, M.D., Hoi, Y., Piccinelli, M., Antiga, L. and Steinman, D.A., 2009. An objective approach to digital removal of saccular aneurysms: technique and applications. The British Journal of Radiology, 82(special_issue_1), pp.S55-S61. From 0ee05385caa82fe1a876b2ecdaab20e3805818c4 Mon Sep 17 00:00:00 2001 From: Henrik Kjedsberg Date: Wed, 29 Jun 2022 22:09:59 +0200 Subject: [PATCH 6/6] Update installation --- docs/source/installation.rst | 6 +++--- test/fixtures.py | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/source/installation.rst b/docs/source/installation.rst index 447d1fcc..79315dae 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -1,13 +1,13 @@ .. title:: Installation -.. highlight:: console ============ Installation ============ +.. highlight:: console morphMan (morphological manipulation) is a collection of scripts to objectively manipulate morphological features of patient-specific vascular geometries. The project is accessible through -`GitHub `_ and `Anaconda.org `_. +`GitHub `_ and `Anaconda `_. Compatibility and Dependencies @@ -31,7 +31,7 @@ Then execute the following command in a terminal window to create a Conda enviro .. note:: Replace ``your_environment`` with the environment name. -You can then activate your environment by running ``source activate your_environment``. +You can then activate your environment by running ``conda activate your_environment`` or ``source activate your_environment``. Now you are all set, and can start using morphMan. morphMan can be accessed by opening a Python console and typing:: diff --git a/test/fixtures.py b/test/fixtures.py index 45623556..08f34fa8 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -13,13 +13,13 @@ from morphman.common import get_inlet_and_outlet_centers, get_path_names, compute_centerlines, prepare_surface -def download_testdata(test_path, outputfile): +def download_testdata(test_path, output_file): if platform == "darwin": - system("curl -L {} --output {}".format(test_path, outputfile)) + system("curl -L {} --output {}".format(test_path, output_file)) elif platform == "linux" or platform == "linux2": - system("wget -O {} {}".format(outputfile, test_path)) + system("wget -O {} {}".format(output_file, test_path)) elif platform == "win32": - system("bitsadmin /transfer download_model /download /priority high {} {}".format(test_path, outputfile)) + system("bitsadmin /transfer download_model /download /priority high {} {}".format(test_path, output_file)) @pytest.fixture(scope="module") @@ -29,15 +29,16 @@ def surface_paths(): # Path to test data # TODO: Replace with official Aneurisk database when available test_path = "https://github.com/hkjeldsberg/AneuriskDatabase/raw/master/models/C0001/surface/model.vtp" - outputfile = path.join(abs_path, "C0001", "surface", "model.vtp") + output_file = path.join(abs_path, "C0001", "surface", "model.vtp") - # Download test data if necessary + # Create test data folders if not path.exists(path.join(abs_path, "C0001", "surface")): makedirs(path.join(abs_path, "C0001", "surface")) + # Download test data if necessary if not path.exists(path.join(abs_path, "C0001", "surface", "model.vtp")): try: - download_testdata(test_path, outputfile) + download_testdata(test_path, output_file) except Exception: raise Exception("Problem downloading the testdata, please do it manually from " + test_path + " and extract the compressed tarball in the test folder")