cardio 2023.1.2__py3-none-any.whl → 2025.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cardio/volume.py CHANGED
@@ -1,116 +1,61 @@
1
1
  import logging
2
- import os
3
2
 
4
3
  import itk
5
4
  import numpy as np
6
- from vtkmodules.vtkCommonDataModel import vtkPiecewiseFunction
7
- from vtkmodules.vtkIOGeometry import vtkOBJReader
8
- from vtkmodules.vtkRenderingCore import (
9
- vtkColorTransferFunction,
10
- vtkRenderer,
11
- vtkVolume,
12
- vtkVolumeProperty,
13
- )
14
- from vtkmodules.vtkRenderingVolume import vtkGPUVolumeRayCastMapper
15
- from vtkmodules.vtkRenderingVolumeOpenGL2 import vtkOpenGLRayCastImageDisplayHelper
5
+ import pydantic as pc
6
+ import vtk
16
7
 
17
- from . import Object
18
-
19
-
20
- def reset_direction(image):
21
- origin = np.asarray(itk.origin(image))
22
- spacing = np.asarray(itk.spacing(image))
23
- size = np.asarray(itk.size(image))
24
- direction = np.asarray(image.GetDirection())
25
-
26
- direction[direction == 1] = 0
27
- origin += np.dot(size, np.dot(np.diag(spacing), direction))
28
- direction = np.identity(3)
29
-
30
- origin = itk.Point[itk.F, 3](origin)
31
- spacing = itk.spacing(image)
32
- size = itk.size(image)
33
- direction = itk.matrix_from_array(direction)
34
-
35
- interpolator = itk.LinearInterpolateImageFunction.New(image)
36
- output = itk.resample_image_filter(
37
- image,
38
- size=size,
39
- interpolator=interpolator,
40
- output_spacing=spacing,
41
- output_origin=origin,
42
- output_direction=direction,
43
- )
44
-
45
- return output
8
+ from .object import Object
9
+ from .transfer_functions import load_preset
10
+ from .utils import InterpolatorType, reset_direction
46
11
 
47
12
 
48
13
  class Volume(Object):
49
- def __init__(self, cfg: str, renderer: vtkRenderer):
50
- super().__init__(cfg, renderer)
51
- self.actors: list[vtkVolume] = []
14
+ """Volume object with transfer functions and clipping support."""
52
15
 
53
- self.ambient: float = cfg["ambient"]
54
- self.diffuse: float = cfg["diffuse"]
55
- self.specular: float = cfg["specular"]
16
+ pattern: str = pc.Field(
17
+ default="${frame}.nii.gz",
18
+ description="Filename pattern with $frame placeholder",
19
+ )
20
+ transfer_function_preset: str = pc.Field(description="Transfer function preset key")
21
+ _actors: list[vtk.vtkVolume] = pc.PrivateAttr(default_factory=list)
56
22
 
57
- frame = 0
58
- while os.path.exists(self.path_for_frame(frame)):
23
+ @pc.model_validator(mode="after")
24
+ def initialize_volume(self):
25
+ """Generate VTK volume actors for all frames."""
26
+ for frame, path in enumerate(self.path_list):
59
27
  logging.info(f"{self.label}: Loading frame {frame}.")
60
- mapper = vtkGPUVolumeRayCastMapper()
61
- actor = vtkVolume()
62
- image = itk.imread(self.path_for_frame(frame))
63
- image = reset_direction(image)
28
+
29
+ image = itk.imread(path)
30
+ image = reset_direction(image, InterpolatorType.LINEAR)
64
31
  image = itk.vtk_image_from_image(image)
65
- mapper.SetInputData(image)
66
- actor.SetMapper(mapper)
67
- self.actors += [actor]
68
- frame += 1
69
32
 
70
- self.setup_property()
33
+ mapper = vtk.vtkGPUVolumeRayCastMapper()
34
+ mapper.SetInputData(image)
71
35
 
72
- def setup_pipeline(self, frame: int):
73
- for a in self.actors:
74
- self.renderer.AddVolume(a)
75
- a.SetVisibility(False)
76
- a.SetProperty(self.property)
77
- if self.visible:
78
- self.actors[frame].SetVisibility(True)
79
- self.renderer.ResetCamera()
36
+ actor = vtk.vtkVolume()
37
+ actor.SetMapper(mapper)
80
38
 
81
- def setup_property(self):
39
+ self._actors.append(actor)
82
40
 
83
- a = 0
84
- b = 500
85
- c = 1000
86
- d = 1150
41
+ return self
87
42
 
88
- # Create transfer mapping scalar value to opacity.
89
- opacityTransferFunction = vtkPiecewiseFunction()
90
- opacityTransferFunction.AddPoint(a, 0.00)
91
- opacityTransferFunction.AddPoint(b, 0.15)
92
- opacityTransferFunction.AddPoint(c, 0.15)
93
- opacityTransferFunction.AddPoint(d, 0.85)
43
+ @property
44
+ def actors(self) -> list[vtk.vtkVolume]:
45
+ return self._actors
94
46
 
95
- # Create transfer mapping scalar value to color.
96
- colorTransferFunction = vtkColorTransferFunction()
97
- colorTransferFunction.AddRGBPoint(a, 0.0, 0.0, 0.0)
98
- colorTransferFunction.AddRGBPoint(b, 1.0, 0.5, 0.3)
99
- colorTransferFunction.AddRGBPoint(c, 1.0, 0.5, 0.3)
100
- colorTransferFunction.AddRGBPoint(d, 1.0, 1.0, 0.9)
47
+ @property
48
+ def preset(self):
49
+ """Load preset based on transfer_function_preset."""
50
+ return load_preset(self.transfer_function_preset)
101
51
 
102
- volumeGradientOpacity = vtkPiecewiseFunction()
103
- volumeGradientOpacity.AddPoint(0, 0.0)
104
- volumeGradientOpacity.AddPoint(90, 0.5)
105
- volumeGradientOpacity.AddPoint(100, 1.0)
52
+ def configure_actors(self):
53
+ """Configure volume properties without adding to renderer."""
54
+ for volume in self._actors:
55
+ volume.SetVisibility(False)
56
+ volume.SetProperty(self.preset.vtk_property)
106
57
 
107
- # The property describes how the data will look.
108
- self.property = vtkVolumeProperty()
109
- self.property.SetColor(colorTransferFunction)
110
- self.property.SetScalarOpacity(opacityTransferFunction)
111
- self.property.SetGradientOpacity(volumeGradientOpacity)
112
- self.property.ShadeOn()
113
- self.property.SetInterpolationTypeToLinear()
114
- self.property.SetAmbient(self.ambient)
115
- self.property.SetDiffuse(self.diffuse)
116
- self.property.SetSpecular(self.specular)
58
+ def apply_preset_to_actors(self):
59
+ """Apply the current preset to all actors."""
60
+ for actor in self._actors:
61
+ actor.SetProperty(self.preset.vtk_property)
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.3
2
+ Name: cardio
3
+ Version: 2025.8.1
4
+ Summary: A simple web-based viewer for 3D and 4D ('cine') medical imaging data.
5
+ Keywords: Medical,Imaging,3D,4D,Visualization
6
+ Author: Davis Marc Vigneault
7
+ Author-email: Davis Marc Vigneault <davis.vigneault@gmail.com>
8
+ License: Apache Software License 2.0
9
+
10
+ Copyright (c) 2023, Davis Marc Vigneault
11
+
12
+ Licensed under the Apache License, Version 2.0 (the "License");
13
+ you may not use this file except in compliance with the License.
14
+ You may obtain a copy of the License at
15
+
16
+ http://www.apache.org/licenses/LICENSE-2.0
17
+
18
+ Unless required by applicable law or agreed to in writing, software
19
+ distributed under the License is distributed on an "AS IS" BASIS,
20
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ See the License for the specific language governing permissions and
22
+ limitations under the License.
23
+ Classifier: Development Status :: 3 - Alpha
24
+ Classifier: Environment :: Web Environment
25
+ Classifier: Intended Audience :: Healthcare Industry
26
+ Classifier: Intended Audience :: Science/Research
27
+ Classifier: License :: OSI Approved :: Apache Software License
28
+ Classifier: Natural Language :: English
29
+ Classifier: Operating System :: OS Independent
30
+ Classifier: Programming Language :: Python :: 3 :: Only
31
+ Classifier: Programming Language :: JavaScript
32
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
33
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
34
+ Classifier: Topic :: Scientific/Engineering :: Visualization
35
+ Requires-Dist: trame-vuetify>=3.0.2
36
+ Requires-Dist: trame-vtk>=2.9.1
37
+ Requires-Dist: trame>=3.11.0
38
+ Requires-Dist: itk>=5.4.4.post1
39
+ Requires-Dist: vtk>=9.5.0
40
+ Requires-Dist: tomlkit>=0.13.3
41
+ Requires-Dist: numpy>=2.2.6
42
+ Requires-Dist: pydantic>=2.11.7
43
+ Requires-Dist: pydantic-settings>=2.0.0
44
+ Requires-Dist: ruff>=0.12.10 ; extra == 'dev'
45
+ Requires-Dist: isort>=6.0.1 ; extra == 'dev'
46
+ Requires-Dist: bumpver>=2025.1131 ; extra == 'dev'
47
+ Requires-Dist: pytest>=8.4.1 ; extra == 'dev'
48
+ Maintainer: Davis Marc Vigneault
49
+ Maintainer-email: Davis Marc Vigneault <davis.vigneault@gmail.com>
50
+ Requires-Python: >=3.10
51
+ Project-URL: repository, https://github.com/sudomakeinstall/cardio
52
+ Provides-Extra: dev
53
+ Description-Content-Type: text/markdown
54
+
55
+ # cardio
56
+
57
+ `cardio` is a simple web-based viewer for 3D and 4D ('cine') medical imaging data,
58
+ built primarily on [trame](https://github.com/kitware/trame),
59
+ [vtk](https://github.com/kitware/vtk), and
60
+ [itk](https://github.com/insightsoftwareconsortium/itk). `cardio` is able to
61
+ render sequences of mesh files (e.g., `\*.obj` files), segmentation files (e.g.
62
+ `\*nii.gz` files with discrete labels) and volume renderings of grayscale images
63
+ (e.g. \*.nii.gz files with continuous values). `cardio` is launched from the
64
+ commandline and may be configured either directly from the commandline, via a static
65
+ TOML configuration file, or a combination of the two.
66
+
67
+ ## Quickstart
68
+
69
+ ### Installation
70
+
71
+ ```bash
72
+ $ cd /path/to/your/project
73
+ $ uv init
74
+ $ uv add cardio
75
+ $ . ./.venv/bin/activate
76
+ (project) cardio --version
77
+ cardio 2025.8.1
78
+ ```
79
+
80
+ ### Developing
81
+
82
+ Ensuring you have all required dependencies:
83
+
84
+ ```bash
85
+ $ uv sync --all-extras
86
+ ```
87
+
88
+ Pre-commit checklist:
89
+
90
+ ```bash
91
+ $ isort .
92
+ $ ruff format
93
+ $ pytest -v
94
+ ```
95
+
96
+ Uploading:
97
+
98
+ ```bash
99
+ $ bumpver update
100
+ $ uv build --no-sources
101
+ $ uv publish --token <pypi_api_key>
102
+ ```
@@ -0,0 +1,22 @@
1
+ cardio/__init__.py,sha256=MsdbwMMtvuZbIS_niBq_ZXvds_jH4oPgkyCPO5heLLU,505
2
+ cardio/app.py,sha256=sJ2IbOrV2X-5XTkORUbxuvqvg3-Iaotkq_ofIjVzJCA,1791
3
+ cardio/assets/bone.toml,sha256=vv8uVYSHIoKuHkNCoBOkGe2_qoEbXMvQO6ypm3mMOtA,675
4
+ cardio/assets/vascular_closed.toml,sha256=XtaZS_Zd6NSAtY3ZlUfiog3T86u9Ii0oSutU2wBQy78,1267
5
+ cardio/assets/vascular_open.toml,sha256=1M3sV1IGt3zh_3vviysKEk9quKfjF9xUBcIq3kxVHFM,879
6
+ cardio/assets/xray.toml,sha256=siPem0OZ2OkWH0e5pizftpItJKGJgxKJ_S2K0316ubQ,693
7
+ cardio/logic.py,sha256=Ir4W1pz_hNlQA3QgzIrh701LJY7qBF4O05qkNKfszJw,15126
8
+ cardio/mesh.py,sha256=DUsjzYsTuUDsICqRK3pj49FtXjQ79CJ0HaEYupEE9R4,9392
9
+ cardio/object.py,sha256=6YnEwXL5CUWoG-RAI8ETZG_DWmWi1URjVMiimCxD1zk,6448
10
+ cardio/property_config.py,sha256=XJYcKeRcq8s9W9jqxzVer75r5jBLuvebv780FYdPV8U,1723
11
+ cardio/scene.py,sha256=u9j2ZDobTvO8snTnNk-n3NmO7ZQ2cSC6maRCfkcMQaM,7401
12
+ cardio/screenshot.py,sha256=l8bLgxnU5O0FlnmsyVAzKwM9Y0401IzcdnDP0WqFSTY,640
13
+ cardio/segmentation.py,sha256=enj1V5Rw42dxjqSRUiylEQcdgvj8A-Do9Z638tf7nc8,6706
14
+ cardio/transfer_functions.py,sha256=oOKShXBOBpDt8VTEZyc4IT9mCMxuYkWCKHE9kzGrs3o,9183
15
+ cardio/types.py,sha256=DYDgA5QmYdU3QQrEgZMouEbMEIf40DJCeXo4V7cDXtg,356
16
+ cardio/ui.py,sha256=ifbXHRSDY2Sm-zcriIk4wVySuF0NwHrZu8NCN098gIY,23180
17
+ cardio/utils.py,sha256=zgyJ2PWTAWIaU8SVA9KF_XFB4251QxYAT6w3cqaIerA,3051
18
+ cardio/volume.py,sha256=vCOUWKeN99Whdv0b9IEalFGUpKuNe4DILKWBL02nUUM,1892
19
+ cardio-2025.8.1.dist-info/WHEEL,sha256=4n27za1eEkOnA7dNjN6C5-O2rUiw6iapszm14Uj-Qmk,79
20
+ cardio-2025.8.1.dist-info/entry_points.txt,sha256=xRd1otqKtW9xmidJ4CFRX1V9KWmsBbtxrgMtDColq3w,40
21
+ cardio-2025.8.1.dist-info/METADATA,sha256=xAxvU4IGTLBcLRuoJ-6rRphuAxz4NQv3g0KTJg5WjXw,3453
22
+ cardio-2025.8.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.13
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -1,2 +1,3 @@
1
1
  [gui_scripts]
2
2
  cardio = cardio.app:main
3
+
__init__.py DELETED
File without changes
@@ -1,15 +0,0 @@
1
- Apache Software License 2.0
2
-
3
- Copyright (c) 2023, Davis Marc Vigneault
4
-
5
- Licensed under the Apache License, Version 2.0 (the "License");
6
- you may not use this file except in compliance with the License.
7
- You may obtain a copy of the License at
8
-
9
- http://www.apache.org/licenses/LICENSE-2.0
10
-
11
- Unless required by applicable law or agreed to in writing, software
12
- distributed under the License is distributed on an "AS IS" BASIS,
13
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- See the License for the specific language governing permissions and
15
- limitations under the License.
@@ -1,69 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: cardio
3
- Version: 2023.1.2
4
- Summary: A simple web-based viewer for 4D ('cine') medical imaging data.
5
- Author-email: Davis Marc Vigneault <davis.vigneault@gmail.com>
6
- Maintainer-email: Davis Marc Vigneault <davis.vigneault@gmail.com>
7
- License: Apache Software License 2.0
8
-
9
- Copyright (c) 2023, Davis Marc Vigneault
10
-
11
- Licensed under the Apache License, Version 2.0 (the "License");
12
- you may not use this file except in compliance with the License.
13
- You may obtain a copy of the License at
14
-
15
- http://www.apache.org/licenses/LICENSE-2.0
16
-
17
- Unless required by applicable law or agreed to in writing, software
18
- distributed under the License is distributed on an "AS IS" BASIS,
19
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- See the License for the specific language governing permissions and
21
- limitations under the License.
22
-
23
- Project-URL: repository, https://github.com/dvigneault/cardio
24
- Keywords: Medical,Imaging,4D,Visualization
25
- Classifier: Development Status :: 3 - Alpha
26
- Classifier: Environment :: Web Environment
27
- Classifier: Intended Audience :: Healthcare Industry
28
- Classifier: Intended Audience :: Science/Research
29
- Classifier: License :: OSI Approved :: Apache Software License
30
- Classifier: Natural Language :: English
31
- Classifier: Operating System :: OS Independent
32
- Classifier: Programming Language :: Python :: 3 :: Only
33
- Classifier: Programming Language :: JavaScript
34
- Classifier: Topic :: Scientific/Engineering :: Image Processing
35
- Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
36
- Classifier: Topic :: Scientific/Engineering :: Visualization
37
- Requires-Python: >=3.10
38
- Description-Content-Type: text/markdown
39
- License-File: LICENSE
40
- Requires-Dist: trame
41
- Requires-Dist: vtk
42
- Requires-Dist: itk
43
- Requires-Dist: tomlkit
44
- Requires-Dist: numpy
45
- Provides-Extra: dev
46
- Requires-Dist: black ; extra == 'dev'
47
- Requires-Dist: isort ; extra == 'dev'
48
- Requires-Dist: pip-tools ; extra == 'dev'
49
- Requires-Dist: pytest ; extra == 'dev'
50
- Requires-Dist: bumpver ; extra == 'dev'
51
- Requires-Dist: build ; extra == 'dev'
52
- Requires-Dist: twine ; extra == 'dev'
53
-
54
- # Cardio
55
-
56
- `cardio` is a simple web-based viewer for 4D ('cine') medical imaging data. `cardio` is able to render sequences of mesh files (e.g., `\*.obj` files) and volume renderings of image files (e.g. \*.nii.gz files). `cardio` is launched from the commandline and configured using a TOML file.
57
-
58
- ## Quickstart
59
-
60
- ```bash
61
- $ python -m venv .venv
62
- $ . ./.venv/bin/activate
63
- (.venv) pip install cardio
64
- (.venv) cardio --config ./examples/cfg-example.toml
65
-
66
- App running at:
67
- - Local: http://localhost:8080/
68
- - Network: http://127.0.0.1:8080/
69
- ```
@@ -1,16 +0,0 @@
1
- __init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- cardio/__init__.py,sha256=urw8Xx4cNfgYfH4mqVXe6udtdluu-Pz-9XN2irQUHIg,316
3
- cardio/app.py,sha256=nFMzMtLobvopWMwPKsb_Qw9gQBAw4aiUNuq8WAkAqQg,607
4
- cardio/logic.py,sha256=te1MTzJTPPP3coe9ntvLBK19irFI0e49tjH2fwmQ_54,4183
5
- cardio/mesh.py,sha256=Jk2LMYx1XdV8RUU83oEJJ5k5BUS39i1tglEXgdmD3nY,1306
6
- cardio/object.py,sha256=sur65ZkkLd6aThnL0DBNo69XkPQ4Ek_Og60Wcp6f8bI,436
7
- cardio/scene.py,sha256=wltKTRAn-RVw9-FzJYonfNxUc6hL4UeAf7wxt3t5BZQ,3182
8
- cardio/screenshot.py,sha256=VRBf9jZtkGzJ1-Gq4rFsazgTuwF9Y-qpq9LsYy2gcX0,744
9
- cardio/ui.py,sha256=oUh_K-SgbZ6cxDK40a7Wm6XCkOxvcXKHVbdRZthAi5o,7024
10
- cardio/volume.py,sha256=7sC6h9dUvZFDONFhUs2D9Cwwvsqyav7N_Z_l1rYgiWY,3882
11
- cardio-2023.1.2.dist-info/LICENSE,sha256=Bt7BKWq-r2ZQvNet9olLms6u19TxM9eU02hAxFnsBbQ,591
12
- cardio-2023.1.2.dist-info/METADATA,sha256=1hC2ucBt8fFmQ6SSg68bTYdtAhTUEB89gMCHhTHHR80,2743
13
- cardio-2023.1.2.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
14
- cardio-2023.1.2.dist-info/entry_points.txt,sha256=sTB22uP2O9JPpPxExkCveTODevrcoIIMvmnx_gmp8AM,39
15
- cardio-2023.1.2.dist-info/top_level.txt,sha256=a10HKI2DqoBdJWkvEOeWgO7cPYy9XHVY2VOGso-7rxI,16
16
- cardio-2023.1.2.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.4)
3
- Root-Is-Purelib: true
4
- Tag: py3-none-any
5
-
@@ -1,2 +0,0 @@
1
- __init__
2
- cardio