cardio 2025.10.1__py3-none-any.whl → 2026.1.0__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/__init__.py +1 -1
- cardio/app.py +0 -2
- cardio/blend_transfer_functions.py +0 -3
- cardio/color_transfer_function.py +0 -2
- cardio/logic.py +254 -172
- cardio/mesh.py +0 -3
- cardio/object.py +0 -2
- cardio/orientation.py +6 -3
- cardio/piecewise_function.py +0 -2
- cardio/property_config.py +0 -3
- cardio/rotation.py +211 -0
- cardio/scene.py +51 -22
- cardio/segmentation.py +1 -4
- cardio/transfer_function_pair.py +0 -2
- cardio/types.py +0 -2
- cardio/ui.py +350 -173
- cardio/utils.py +0 -7
- cardio/volume.py +174 -44
- cardio/volume_property.py +0 -2
- cardio/volume_property_presets.py +0 -3
- cardio/window_level.py +0 -2
- {cardio-2025.10.1.dist-info → cardio-2026.1.0.dist-info}/METADATA +7 -8
- cardio-2026.1.0.dist-info/RECORD +30 -0
- cardio-2025.10.1.dist-info/RECORD +0 -29
- {cardio-2025.10.1.dist-info → cardio-2026.1.0.dist-info}/WHEEL +0 -0
- {cardio-2025.10.1.dist-info → cardio-2026.1.0.dist-info}/entry_points.txt +0 -0
cardio/volume.py
CHANGED
|
@@ -30,6 +30,9 @@ class Volume(Object):
|
|
|
30
30
|
_mpr_actors: dict[str, list[vtk.vtkImageActor]] = pc.PrivateAttr(
|
|
31
31
|
default_factory=dict
|
|
32
32
|
)
|
|
33
|
+
_crosshair_actors: dict[str, dict[str, vtk.vtkActor]] = pc.PrivateAttr(
|
|
34
|
+
default_factory=dict
|
|
35
|
+
)
|
|
33
36
|
|
|
34
37
|
@pc.model_validator(mode="after")
|
|
35
38
|
def initialize_volume(self):
|
|
@@ -134,6 +137,104 @@ class Volume(Object):
|
|
|
134
137
|
return self.create_mpr_actors(frame)
|
|
135
138
|
return self._mpr_actors[frame]
|
|
136
139
|
|
|
140
|
+
def create_crosshair_actors(self, colors: dict, line_width: float = 1.5) -> dict:
|
|
141
|
+
"""Create 2D crosshair overlay actors for each MPR view.
|
|
142
|
+
|
|
143
|
+
Uses screen-space 2D actors that always appear centered in the view.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
colors: Dict mapping view names to RGB tuples
|
|
147
|
+
line_width: Width of the crosshair lines
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Dict mapping view names to dicts with line actors
|
|
151
|
+
"""
|
|
152
|
+
crosshairs = {}
|
|
153
|
+
|
|
154
|
+
for view_name in ["axial", "sagittal", "coronal"]:
|
|
155
|
+
view_crosshairs = {}
|
|
156
|
+
|
|
157
|
+
for line_name in ["line1", "line2"]:
|
|
158
|
+
# Create 2D line using normalized viewport coordinates
|
|
159
|
+
points = vtk.vtkPoints()
|
|
160
|
+
lines = vtk.vtkCellArray()
|
|
161
|
+
|
|
162
|
+
# Placeholder points - will set based on line orientation
|
|
163
|
+
if line_name == "line1":
|
|
164
|
+
# Vertical line (one of the other planes)
|
|
165
|
+
points.InsertNextPoint(0.5, 0.0, 0.0)
|
|
166
|
+
points.InsertNextPoint(0.5, 1.0, 0.0)
|
|
167
|
+
else:
|
|
168
|
+
# Horizontal line (other plane)
|
|
169
|
+
points.InsertNextPoint(0.0, 0.5, 0.0)
|
|
170
|
+
points.InsertNextPoint(1.0, 0.5, 0.0)
|
|
171
|
+
|
|
172
|
+
line = vtk.vtkLine()
|
|
173
|
+
line.GetPointIds().SetId(0, 0)
|
|
174
|
+
line.GetPointIds().SetId(1, 1)
|
|
175
|
+
lines.InsertNextCell(line)
|
|
176
|
+
|
|
177
|
+
polydata = vtk.vtkPolyData()
|
|
178
|
+
polydata.SetPoints(points)
|
|
179
|
+
polydata.SetLines(lines)
|
|
180
|
+
|
|
181
|
+
# Use coordinate transform to map normalized coords to viewport
|
|
182
|
+
coord = vtk.vtkCoordinate()
|
|
183
|
+
coord.SetCoordinateSystemToNormalizedViewport()
|
|
184
|
+
|
|
185
|
+
mapper = vtk.vtkPolyDataMapper2D()
|
|
186
|
+
mapper.SetInputData(polydata)
|
|
187
|
+
mapper.SetTransformCoordinate(coord)
|
|
188
|
+
|
|
189
|
+
actor = vtk.vtkActor2D()
|
|
190
|
+
actor.SetMapper(mapper)
|
|
191
|
+
actor.GetProperty().SetLineWidth(line_width)
|
|
192
|
+
actor.SetVisibility(False)
|
|
193
|
+
|
|
194
|
+
view_crosshairs[line_name] = {
|
|
195
|
+
"polydata": polydata,
|
|
196
|
+
"actor": actor,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
# Set colors based on which planes the lines represent
|
|
200
|
+
if view_name == "axial":
|
|
201
|
+
view_crosshairs["line1"]["actor"].GetProperty().SetColor(
|
|
202
|
+
*colors.get("sagittal", (1, 0, 0))
|
|
203
|
+
)
|
|
204
|
+
view_crosshairs["line2"]["actor"].GetProperty().SetColor(
|
|
205
|
+
*colors.get("coronal", (0, 1, 0))
|
|
206
|
+
)
|
|
207
|
+
elif view_name == "sagittal":
|
|
208
|
+
view_crosshairs["line1"]["actor"].GetProperty().SetColor(
|
|
209
|
+
*colors.get("coronal", (0, 1, 0))
|
|
210
|
+
)
|
|
211
|
+
view_crosshairs["line2"]["actor"].GetProperty().SetColor(
|
|
212
|
+
*colors.get("axial", (0, 0, 1))
|
|
213
|
+
)
|
|
214
|
+
else: # coronal
|
|
215
|
+
view_crosshairs["line1"]["actor"].GetProperty().SetColor(
|
|
216
|
+
*colors.get("sagittal", (1, 0, 0))
|
|
217
|
+
)
|
|
218
|
+
view_crosshairs["line2"]["actor"].GetProperty().SetColor(
|
|
219
|
+
*colors.get("axial", (0, 0, 1))
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
crosshairs[view_name] = view_crosshairs
|
|
223
|
+
|
|
224
|
+
self._crosshair_actors = crosshairs
|
|
225
|
+
return crosshairs
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def crosshair_actors(self) -> dict:
|
|
229
|
+
"""Get crosshair actors."""
|
|
230
|
+
return self._crosshair_actors
|
|
231
|
+
|
|
232
|
+
def set_crosshairs_visible(self, visible: bool):
|
|
233
|
+
"""Set visibility of all crosshair actors."""
|
|
234
|
+
for view_crosshairs in self._crosshair_actors.values():
|
|
235
|
+
for line_data in view_crosshairs.values():
|
|
236
|
+
line_data["actor"].SetVisibility(visible)
|
|
237
|
+
|
|
137
238
|
def _get_mpr_coordinate_systems(self):
|
|
138
239
|
"""Get coordinate system transformation matrices for MPR views."""
|
|
139
240
|
view_axcodes = {
|
|
@@ -197,75 +298,104 @@ class Volume(Object):
|
|
|
197
298
|
|
|
198
299
|
return bounds
|
|
199
300
|
|
|
301
|
+
def _build_cumulative_rotation(
|
|
302
|
+
self, rotation_sequence: list, rotation_angles: dict, angle_units=None
|
|
303
|
+
) -> np.ndarray:
|
|
304
|
+
"""Build cumulative rotation matrix from sequence of rotations."""
|
|
305
|
+
from .orientation import AngleUnits
|
|
306
|
+
|
|
307
|
+
if angle_units is None:
|
|
308
|
+
angle_units = AngleUnits.DEGREES
|
|
309
|
+
|
|
310
|
+
cumulative_rotation = np.eye(3)
|
|
311
|
+
if rotation_sequence and rotation_angles:
|
|
312
|
+
for i, rotation in enumerate(rotation_sequence):
|
|
313
|
+
angle = rotation_angles.get(i, 0)
|
|
314
|
+
rotation_matrix = euler_angle_to_rotation_matrix(
|
|
315
|
+
EulerAxis(rotation["axis"]), angle, angle_units
|
|
316
|
+
)
|
|
317
|
+
cumulative_rotation = cumulative_rotation @ rotation_matrix
|
|
318
|
+
return cumulative_rotation
|
|
319
|
+
|
|
320
|
+
def get_scroll_vector(
|
|
321
|
+
self,
|
|
322
|
+
view_name: str,
|
|
323
|
+
rotation_sequence: list = None,
|
|
324
|
+
rotation_angles: dict = None,
|
|
325
|
+
angle_units=None,
|
|
326
|
+
) -> np.ndarray:
|
|
327
|
+
"""Get the current normal vector for a view after rotation.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
view_name: One of "axial", "sagittal", "coronal"
|
|
331
|
+
rotation_sequence: List of rotation definitions
|
|
332
|
+
rotation_angles: Dict mapping rotation index to angle
|
|
333
|
+
angle_units: AngleUnits enum (degrees or radians)
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
3D unit vector representing the scroll direction for this view
|
|
337
|
+
"""
|
|
338
|
+
base_normals = {
|
|
339
|
+
"axial": np.array([0.0, 0.0, 1.0]),
|
|
340
|
+
"sagittal": np.array([1.0, 0.0, 0.0]),
|
|
341
|
+
"coronal": np.array([0.0, 1.0, 0.0]),
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if view_name not in base_normals:
|
|
345
|
+
return np.array([0.0, 0.0, 1.0])
|
|
346
|
+
|
|
347
|
+
cumulative_rotation = self._build_cumulative_rotation(
|
|
348
|
+
rotation_sequence, rotation_angles, angle_units
|
|
349
|
+
)
|
|
350
|
+
return cumulative_rotation @ base_normals[view_name]
|
|
351
|
+
|
|
200
352
|
def update_slice_positions(
|
|
201
353
|
self,
|
|
202
354
|
frame: int,
|
|
203
|
-
|
|
204
|
-
sagittal_pos: float,
|
|
205
|
-
coronal_pos: float,
|
|
355
|
+
origin: list,
|
|
206
356
|
rotation_sequence: list = None,
|
|
207
357
|
rotation_angles: dict = None,
|
|
358
|
+
angle_units=None,
|
|
208
359
|
):
|
|
209
360
|
"""Update slice positions for MPR views with optional rotation.
|
|
210
361
|
|
|
211
362
|
Args:
|
|
212
363
|
frame: Frame index
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
364
|
+
origin: [x, y, z] position in LPS coordinates (shared by all views)
|
|
365
|
+
rotation_sequence: List of rotation definitions
|
|
366
|
+
rotation_angles: Dict mapping rotation index to angle
|
|
367
|
+
angle_units: AngleUnits enum (degrees or radians), defaults to DEGREES
|
|
216
368
|
"""
|
|
369
|
+
from .orientation import AngleUnits
|
|
370
|
+
|
|
371
|
+
if angle_units is None:
|
|
372
|
+
angle_units = AngleUnits.DEGREES
|
|
217
373
|
if frame not in self._mpr_actors:
|
|
218
374
|
return
|
|
219
375
|
|
|
220
|
-
volume_actor = self._actors[frame]
|
|
221
|
-
image_data = volume_actor.GetMapper().GetInput()
|
|
222
|
-
bounds = image_data.GetBounds()
|
|
223
|
-
|
|
224
376
|
actors = self._mpr_actors[frame]
|
|
225
377
|
|
|
226
|
-
# Clamp positions to volume bounds
|
|
227
|
-
axial_pos = max(bounds[4], min(bounds[5], axial_pos)) # Z bounds
|
|
228
|
-
sagittal_pos = max(bounds[0], min(bounds[1], sagittal_pos)) # X bounds
|
|
229
|
-
coronal_pos = max(bounds[2], min(bounds[3], coronal_pos)) # Y bounds
|
|
230
|
-
|
|
231
378
|
# Get coordinate system transformations for each MPR view
|
|
232
379
|
transforms = self._get_mpr_coordinate_systems()
|
|
233
380
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
sagittal_origin = [sagittal_pos, center[1], center[2]]
|
|
239
|
-
coronal_origin = [center[0], coronal_pos, center[2]]
|
|
381
|
+
# Build cumulative rotation matrix
|
|
382
|
+
cumulative_rotation = self._build_cumulative_rotation(
|
|
383
|
+
rotation_sequence, rotation_angles, angle_units
|
|
384
|
+
)
|
|
240
385
|
|
|
241
|
-
#
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
angle = rotation_angles.get(i, 0)
|
|
246
|
-
rotation_matrix = euler_angle_to_rotation_matrix(
|
|
247
|
-
EulerAxis(rotation["axis"]), angle
|
|
248
|
-
)
|
|
249
|
-
cumulative_rotation = cumulative_rotation @ rotation_matrix
|
|
386
|
+
# Apply rotation to base transforms
|
|
387
|
+
axial_transform = cumulative_rotation @ transforms["axial"]
|
|
388
|
+
sagittal_transform = cumulative_rotation @ transforms["sagittal"]
|
|
389
|
+
coronal_transform = cumulative_rotation @ transforms["coronal"]
|
|
250
390
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
sagittal_transform = cumulative_rotation @ transforms["sagittal"]
|
|
254
|
-
coronal_transform = cumulative_rotation @ transforms["coronal"]
|
|
255
|
-
else:
|
|
256
|
-
# Use base transforms without rotation
|
|
257
|
-
axial_transform = transforms["axial"]
|
|
258
|
-
sagittal_transform = transforms["sagittal"]
|
|
259
|
-
coronal_transform = transforms["coronal"]
|
|
260
|
-
|
|
261
|
-
# Update slices with translated origins and rotated transforms
|
|
262
|
-
axial_matrix = create_vtk_reslice_matrix(axial_transform, axial_origin)
|
|
391
|
+
# All views share the same origin
|
|
392
|
+
axial_matrix = create_vtk_reslice_matrix(axial_transform, origin)
|
|
263
393
|
actors["axial"]["reslice"].SetResliceAxes(axial_matrix)
|
|
264
394
|
|
|
265
|
-
sagittal_matrix = create_vtk_reslice_matrix(sagittal_transform,
|
|
395
|
+
sagittal_matrix = create_vtk_reslice_matrix(sagittal_transform, origin)
|
|
266
396
|
actors["sagittal"]["reslice"].SetResliceAxes(sagittal_matrix)
|
|
267
397
|
|
|
268
|
-
coronal_matrix = create_vtk_reslice_matrix(coronal_transform,
|
|
398
|
+
coronal_matrix = create_vtk_reslice_matrix(coronal_transform, origin)
|
|
269
399
|
actors["coronal"]["reslice"].SetResliceAxes(coronal_matrix)
|
|
270
400
|
|
|
271
401
|
def update_mpr_window_level(self, frame: int, window: float, level: float):
|
cardio/volume_property.py
CHANGED
cardio/window_level.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: cardio
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2026.1.0
|
|
4
4
|
Summary: A simple web-based viewer for 3D and 4D ('cine') medical imaging data.
|
|
5
5
|
Keywords: Medical,Imaging,3D,4D,Visualization
|
|
6
6
|
Author: Davis Marc Vigneault
|
|
@@ -59,12 +59,11 @@ Description-Content-Type: text/markdown
|
|
|
59
59
|
`cardio` is a simple web-based viewer for 3D and 4D ('cine') medical imaging data,
|
|
60
60
|
built primarily on [trame](https://github.com/kitware/trame),
|
|
61
61
|
[vtk](https://github.com/kitware/vtk), and
|
|
62
|
-
[itk](https://github.com/insightsoftwareconsortium/itk). `cardio`
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
commandline
|
|
67
|
-
TOML configuration file, or a combination of the two.
|
|
62
|
+
[itk](https://github.com/insightsoftwareconsortium/itk). `cardio` can render sequences
|
|
63
|
+
of mesh files (e.g., `\*.obj` files), segmentation files (e.g., `\*nii.gz` files with
|
|
64
|
+
discrete labels) and volume renderings of grayscale images (e.g., `\*.nii.gz` files with
|
|
65
|
+
continuous values). `cardio` is launched from the commandline and may be configured via
|
|
66
|
+
commandline arguments, a static TOML configuration file, or a combination of the two.
|
|
68
67
|
|
|
69
68
|
## Quickstart
|
|
70
69
|
|
|
@@ -76,7 +75,7 @@ $ uv init
|
|
|
76
75
|
$ uv add cardio
|
|
77
76
|
$ . ./.venv/bin/activate
|
|
78
77
|
(project) cardio --version
|
|
79
|
-
cardio
|
|
78
|
+
cardio 2026.1.0
|
|
80
79
|
```
|
|
81
80
|
|
|
82
81
|
### Developing
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
cardio/__init__.py,sha256=WZ7MfzISF8ryIC9NdIyub4mP6DQBWsMX766IPcWihXg,601
|
|
2
|
+
cardio/app.py,sha256=h-Xh57Txw3Hom-fDv08YxjXzovuIxY8_5qPy6MJThZs,1354
|
|
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/blend_transfer_functions.py,sha256=fkLDYGMj_QXYs0vmXYT_B1tgTfl3YICLYimtWlxrmbQ,2958
|
|
8
|
+
cardio/color_transfer_function.py,sha256=uTyPdwxi0HjR4wm418cQN9-q9SspkkeqvLNqXaF3zzg,792
|
|
9
|
+
cardio/logic.py,sha256=pjAqiJc_3pfUpB9hXWiSYJTmbG4c1omuUvuT2gshPNo,40431
|
|
10
|
+
cardio/mesh.py,sha256=wYdU0BU84eXrrHp0U0VLwYW7ZpRJ6GbT5Kl_-K6CBzY,9356
|
|
11
|
+
cardio/object.py,sha256=98A32VpFR4UtVqW8dZsRJR13VVyUoJJ20uoOZBgN4js,6168
|
|
12
|
+
cardio/orientation.py,sha256=zOw3R284izAcKXnCCYYFOzOPBqgiE8om8q2JDWTQFoY,6256
|
|
13
|
+
cardio/piecewise_function.py,sha256=X-_C-BVStufmFjfF8IbkqKk9Xw_jh00JUmjC22ZqeqQ,764
|
|
14
|
+
cardio/property_config.py,sha256=YrWIyCoSAfJPigkhriIQybQpJantGnXjT4nJfrtIJco,1689
|
|
15
|
+
cardio/rotation.py,sha256=eUUk74kBpPr-YCZdIAcU5pIX6FKeVGT8dRg2YnaS2yE,7204
|
|
16
|
+
cardio/scene.py,sha256=2oq-zVMSHj9PhNToSMbk8RzJ3jKzo7oaAvDn_U4vcPM,15583
|
|
17
|
+
cardio/screenshot.py,sha256=l8bLgxnU5O0FlnmsyVAzKwM9Y0401IzcdnDP0WqFSTY,640
|
|
18
|
+
cardio/segmentation.py,sha256=KT1ClgultXyGpZDdpYxor38GflY7uCgRzfA8JEGQVaU,6642
|
|
19
|
+
cardio/transfer_function_pair.py,sha256=_J0qXA0InUPpvfWPcW492KGSYAqeb12htCzKBSpWHwo,780
|
|
20
|
+
cardio/types.py,sha256=jxSZjvxEJ03OThfupT2CG9UHsFklwbWeFrUozNXro2I,333
|
|
21
|
+
cardio/ui.py,sha256=uYyO1-Lysi5guFDv4k3HSGJ12Ro27B1yxkmS_PFbd-M,53189
|
|
22
|
+
cardio/utils.py,sha256=ao4a7_vMjGBxTOMhZ7r0D0W4ujiwKPS0i8Xfmn3Gv9k,1497
|
|
23
|
+
cardio/volume.py,sha256=sdQ7gtX4jQDD9U8U95xD9LIV_1hpykj8NTCo1_aIKVM,15035
|
|
24
|
+
cardio/volume_property.py,sha256=-EUMV9sWCaetgGjnqIWxPp39qrxEZKTNDJ5GHUgLMlk,1619
|
|
25
|
+
cardio/volume_property_presets.py,sha256=4-hjo-dukm5sMMmWidbWnVXq0IN4sWpBnDITY9MqUFg,1625
|
|
26
|
+
cardio/window_level.py,sha256=XMkwLAHcmsEYcI0SoHySQZvptq4VwX2gj--ps3hV8AQ,784
|
|
27
|
+
cardio-2026.1.0.dist-info/WHEEL,sha256=4n27za1eEkOnA7dNjN6C5-O2rUiw6iapszm14Uj-Qmk,79
|
|
28
|
+
cardio-2026.1.0.dist-info/entry_points.txt,sha256=xRd1otqKtW9xmidJ4CFRX1V9KWmsBbtxrgMtDColq3w,40
|
|
29
|
+
cardio-2026.1.0.dist-info/METADATA,sha256=xulm4Dgn_80ZFMHSKEBtxnoEfYKFFf3Pfb3aNM1fgzw,3520
|
|
30
|
+
cardio-2026.1.0.dist-info/RECORD,,
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
cardio/__init__.py,sha256=cVW5yofdKIbjqc0sf_VVnIMah9BvAgELy7IzZR50IZQ,602
|
|
2
|
-
cardio/app.py,sha256=TEzgA03EAgI7HSCHhYwYb8tsnAptsrpcysV5CytfAq4,1379
|
|
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/blend_transfer_functions.py,sha256=s5U4hO810oE434wIkPmAP2mrAfqFb4xxxi3hHf_k8og,2982
|
|
8
|
-
cardio/color_transfer_function.py,sha256=KV4j11AXYeaYGeJWBc9I-WZf7Shrm5xjQVq-0bq9Qc8,817
|
|
9
|
-
cardio/logic.py,sha256=a73JJ2b8t-TYggYMGI1IGpn0Q6AFD8I1JNz9fn6QeDk,37557
|
|
10
|
-
cardio/mesh.py,sha256=XIJX2Ldv1Bw82yykE0N4IlQ0xE2r6xitjxsbEvEKrcI,9390
|
|
11
|
-
cardio/object.py,sha256=FvMzhO9gyHhXgME8B6fcnWH74HmsYNoUjpVKUWEpWhM,6191
|
|
12
|
-
cardio/orientation.py,sha256=J3bqZbv8vfl4loGl7ksmuyqWb3zFAz-TVSIahKcg0pc,6145
|
|
13
|
-
cardio/piecewise_function.py,sha256=bwtwgrAMGkgu1krnvsOF9gRMaZb6smsS9jLrgBecSbo,789
|
|
14
|
-
cardio/property_config.py,sha256=XJYcKeRcq8s9W9jqxzVer75r5jBLuvebv780FYdPV8U,1723
|
|
15
|
-
cardio/scene.py,sha256=9jskdEARyJjk7QBIcMt5X2HsnikTAJdoRoLSI0LxcJE,14301
|
|
16
|
-
cardio/screenshot.py,sha256=l8bLgxnU5O0FlnmsyVAzKwM9Y0401IzcdnDP0WqFSTY,640
|
|
17
|
-
cardio/segmentation.py,sha256=SK9f834lld08qYH9l2Ligml212u7MzfcOEgTz8wnpzs,6676
|
|
18
|
-
cardio/transfer_function_pair.py,sha256=90PQXByCL6mMaODo7Yfd-lmdFtCKhcBZbNaiH-PTds0,805
|
|
19
|
-
cardio/types.py,sha256=DYDgA5QmYdU3QQrEgZMouEbMEIf40DJCeXo4V7cDXtg,356
|
|
20
|
-
cardio/ui.py,sha256=wsRujwiNtMeq65R4bx-myxSPDhJT0RskwvBWlGenmHk,42901
|
|
21
|
-
cardio/utils.py,sha256=tFUQ4FxfidTH6GjEIKQwguqhO9T_wJ2Vk0IhbEfxRGA,1616
|
|
22
|
-
cardio/volume.py,sha256=k7NYZCwsmoAbs8mNWDC51gS6nlzPqD9JhDr1iyUQ0cs,10377
|
|
23
|
-
cardio/volume_property.py,sha256=6T2r67SSIDl8F6ZlQvgMCZESLxuXVVAUjOC50lgQEmk,1644
|
|
24
|
-
cardio/volume_property_presets.py,sha256=U2a2MnyCjryzOLEADs3OLSMMmAUnXq82mYK7OVXbQV0,1659
|
|
25
|
-
cardio/window_level.py,sha256=gjk39Iv6jMJ52y6jydOjxBZBsI1nZQMs2CdWWTshQoE,807
|
|
26
|
-
cardio-2025.10.1.dist-info/WHEEL,sha256=4n27za1eEkOnA7dNjN6C5-O2rUiw6iapszm14Uj-Qmk,79
|
|
27
|
-
cardio-2025.10.1.dist-info/entry_points.txt,sha256=xRd1otqKtW9xmidJ4CFRX1V9KWmsBbtxrgMtDColq3w,40
|
|
28
|
-
cardio-2025.10.1.dist-info/METADATA,sha256=0GkZB7yixZKd4nFaAHgWtgCA6VxlV_pbUYdHokFROD4,3540
|
|
29
|
-
cardio-2025.10.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|