Diff of /docs/image/main.html [000000] .. [9173ee]

Switch to unified view

a b/docs/image/main.html
1
<!doctype html>
2
<html lang="en">
3
<head>
4
<meta charset="utf-8">
5
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
6
<meta name="generator" content="pdoc 0.10.0" />
7
<title>pymskt.image.main API documentation</title>
8
<meta name="description" content="" />
9
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
10
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
11
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
12
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
13
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
14
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
15
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
16
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
17
</head>
18
<body>
19
<main>
20
<article id="content">
21
<header>
22
<h1 class="title">Module <code>pymskt.image.main</code></h1>
23
</header>
24
<section id="section-intro">
25
<details class="source">
26
<summary>
27
<span>Expand source code</span>
28
</summary>
29
<pre><code class="python">from typing import Optional
30
import os
31
import vtk
32
import SimpleITK as sitk
33
import numpy as np
34
from vtk.util.numpy_support import numpy_to_vtk
35
36
37
def set_vtk_image_origin(vtk_image, new_origin=(0, 0, 0)):
38
    &#34;&#34;&#34;
39
    Reset the origin of a `vtk_image`
40
41
    Parameters
42
    ----------
43
    vtk_image : vtk.image
44
        VTK image that we want to change the origin of. 
45
    new_origin : tuple, optional
46
        New origin to asign to `vtk_image`, by default (0, 0, 0)
47
48
    Returns
49
    -------
50
    vtk.Filter
51
        End of VTK filter pipeline after applying origin change. 
52
    &#34;&#34;&#34;    
53
54
    change_origin = vtk.vtkImageChangeInformation()
55
    change_origin.SetInputConnection(vtk_image.GetOutputPort())
56
    change_origin.SetOutputOrigin(new_origin)
57
    change_origin.Update()
58
    return change_origin
59
60
def read_nrrd(path, set_origin_zero=False):
61
    &#34;&#34;&#34;
62
    Read NRRD image file into vtk. Enables usage of marching cubes
63
    and other functions that work on image data.
64
65
    Parameters
66
    ----------
67
    path : str
68
        Path to `.nrrd` medical image to read in. 
69
    set_origin_zero : bool, optional
70
        Bool to determine if origin should be set to zeros, by default False
71
72
    Returns
73
    -------
74
    vtk.Filter
75
        End of VTK filter pipeline. 
76
    &#34;&#34;&#34;    
77
78
    image_reader = vtk.vtkNrrdReader()
79
    image_reader.SetFileName(path)
80
    image_reader.Update()
81
    if set_origin_zero is True:
82
        change_origin = set_vtk_image_origin(image_reader, new_origin=(0, 0, 0))
83
        return change_origin
84
    elif set_origin_zero is False:
85
        return image_reader
86
87
88
def set_seg_border_to_zeros(seg_image,
89
                            border_size=1):
90
    &#34;&#34;&#34;
91
    Utility function to ensure that all segmentations are &#34;closed&#34; after marching cubes. 
92
    If the segmentation extends to the edges of the image then the surface wont be closed 
93
    at the places it touches the edges. 
94
95
    Parameters
96
    ----------
97
    seg_image : SimpleITK.Image
98
        Image of a segmentation. 
99
    border_size : int, optional
100
        The size of the border to set around the edges of the 3D image, by default 1
101
102
    Returns
103
    -------
104
    SimpleITK.Image
105
        The image with border set to 0 (background). 
106
    &#34;&#34;&#34;    
107
108
    seg_array = sitk.GetArrayFromImage(seg_image)
109
    new_seg_array = np.zeros_like(seg_array)
110
    new_seg_array[border_size:-border_size, border_size:-border_size, border_size:-border_size] = seg_array[border_size:-border_size, border_size:-border_size, border_size:-border_size]
111
    new_seg_image = sitk.GetImageFromArray(new_seg_array)
112
    new_seg_image.CopyInformation(seg_image)
113
    return new_seg_image
114
115
116
def smooth_image(image, label_idx, variance=1.0):
117
    &#34;&#34;&#34;
118
    Smooth a single label in a SimpleITK image. Used as pre-processing for 
119
    bones/cartilage before applying marching cubes. Helps obtain smooth surfaces. 
120
121
    Parameters
122
    ----------
123
    image : SimpleITK.Image
124
        Image to be smoothed. 
125
    label_idx : int
126
        Integer of the tissue of interest to be smoothed in the image. 
127
    variance : float, optional
128
        The size of the smoothing, by default 1.0
129
130
    Returns
131
    -------
132
    SimpleITK.Image
133
        Image of only the label (tissue) of interest after being smoothed. 
134
    &#34;&#34;&#34;    
135
    new_image = binarize_segmentation_image(image, label_idx)
136
137
    new_image = sitk.Cast(new_image, sitk.sitkFloat32)
138
139
    gauss_filter = sitk.DiscreteGaussianImageFilter()
140
    gauss_filter.SetVariance(variance)
141
    #     gauss_filter.SetUseImageSpacingOn
142
    gauss_filter.SetUseImageSpacing(True)
143
    filtered_new_image = gauss_filter.Execute(new_image)
144
145
    return filtered_new_image
146
147
def binarize_segmentation_image(seg_image, label_idx):
148
    &#34;&#34;&#34;
149
    Return segmentation that is only 0s/1s, with 1s where label_idx is
150
    located in the image. 
151
152
    Parameters
153
    ----------
154
    seg_image : SimpleITK.Image
155
        Segmentation image that contains data we want to binarize
156
    label_idx : int
157
        Integer/label that we want to extract (binarize) from the
158
        `seg_image`.
159
160
    Returns
161
    -------
162
    SimpleITK.Image
163
        New segmentation image that is binarized. 
164
    &#34;&#34;&#34;    
165
    array = sitk.GetArrayFromImage(seg_image)
166
    array_ = np.zeros_like(array)
167
    array_[array == label_idx] = 1
168
    new_seg_image = sitk.GetImageFromArray(array_)
169
    new_seg_image.CopyInformation(seg_image)
170
    return new_seg_image
171
172
def crop_bone_based_on_width(seg_image,
173
                             bone_idx,
174
                             np_med_lat_axis=0,
175
                             np_inf_sup_axis=1,
176
                             bone_crop_distal=True,
177
                             value_to_reassign=0,
178
                             percent_width_to_crop_height=1.0):
179
    &#34;&#34;&#34;
180
    Crop the bone labelmap of a SimpleITK.Image so that it is proportional to the
181
    bones medial/lateral width. 
182
183
    Parameters
184
    ----------
185
    seg_image : SimpleITK.Image
186
        Image to be cropped. 
187
    bone_idx : int
188
        Label_index of the bone to be cropped. 
189
    np_med_lat_axis : int, optional
190
        Medial/lateral axis, by default 0
191
    np_inf_sup_axis : int, optional
192
        Inferior/superir axis, by default 1
193
    bone_crop_distal : bool, optional
194
        Boolean of cropping should occur distal or proximally, by default True
195
    value_to_reassign : int, optional
196
        Value to replace bone label with, by default 0
197
    percent_width_to_crop_height : float, optional
198
        Bone length as a proportion of width, by default 1.0
199
200
    Returns
201
    -------
202
    SimpleITK.Image
203
        Image after bone is cropped as a proportion of the bone&#39;s width. 
204
    &#34;&#34;&#34;    
205
    seg_array = sitk.GetArrayFromImage(seg_image)
206
    loc_bone = np.where(seg_array == bone_idx)
207
    med_lat_width_bone_mm = (np.max(loc_bone[np_med_lat_axis]) - np.min(loc_bone[np_med_lat_axis])) * \
208
                            seg_image.GetSpacing()[::-1][np_med_lat_axis]
209
    inf_sup_crop_in_pixels = (med_lat_width_bone_mm / seg_image.GetSpacing()[::-1][
210
        np_inf_sup_axis]) * percent_width_to_crop_height
211
    if bone_crop_distal is True:
212
        bone_distal_idx = np.max(loc_bone[np_inf_sup_axis])
213
        bone_proximal_idx = bone_distal_idx - inf_sup_crop_in_pixels
214
        if bone_proximal_idx &lt; 1:
215
            bone_proximal_idx = 1
216
217
    elif bone_crop_distal is False:
218
        bone_proximal_idx = np.min(loc_bone[np_inf_sup_axis])
219
        bone_distal_idx = bone_proximal_idx + inf_sup_crop_in_pixels
220
        if bone_distal_idx &gt; seg_array.shape[np_inf_sup_axis]:
221
            bone_distal_idx = seg_array.shape[np_inf_sup_axis] - 1
222
223
    max_inf_sup_idx = max(bone_distal_idx, bone_proximal_idx)
224
    min_inf_sup_idx = min(bone_distal_idx, bone_proximal_idx)
225
226
    idx_bone_to_keep = np.where(
227
        (loc_bone[np_inf_sup_axis] &gt; min_inf_sup_idx) &amp; (loc_bone[np_inf_sup_axis] &lt; max_inf_sup_idx))
228
    loc_bone_to_remove = tuple([np.delete(x, idx_bone_to_keep) for x in loc_bone])
229
230
    seg_array[loc_bone_to_remove] = value_to_reassign
231
232
    new_seg_image = sitk.GetImageFromArray(seg_array)
233
    new_seg_image.CopyInformation(seg_image)
234
235
    return new_seg_image
236
237
def apply_transform_retain_array(image, transform, interpolator=sitk.sitkNearestNeighbor):
238
    &#34;&#34;&#34;
239
    This function will move the actual image in space but keep the underlying array the same. 
240
    So, in x/y/z land the pixels are in a new location, but the actual underlying data array 
241
    is the same. 
242
243
    Parameters
244
    ----------
245
    image : SimpleITK.Image
246
        Image to be transformed.
247
    transform : SimpleITK.Transform
248
        Transform to apply
249
    interpolator : SimpleITK.Interpolator, optional
250
        Interpolator type to use, by default sitk.sitkNearestNeighbor
251
252
    Returns
253
    -------
254
    SimpleITK.Image
255
        New image after applying the appropriate transform.
256
    
257
    Notes
258
    -----
259
    I have a feeling that this is overkill.
260
    &#34;&#34;&#34;    
261
262
    inverse_transform = transform.GetInverse()
263
    new_origin = inverse_transform.TransformPoint(image.GetOrigin())
264
265
    new_x = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((image.GetSize()[0], 0, 0)))
266
    new_y = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, image.GetSize()[1], 0)))
267
    new_z = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, 0, image.GetSize()[2])))
268
269
    # Create x-axis vector
270
    new_x_vector = np.asarray(new_x) - np.asarray(new_origin)
271
    new_x_vector /= np.sqrt(np.sum(np.square(new_x_vector)))
272
    # Create y-axis vector
273
    new_y_vector = np.asarray(new_y) - np.asarray(new_origin)
274
    new_y_vector /= np.sqrt(np.sum(np.square(new_y_vector)))
275
    # Create z-axis vector
276
    new_z_vector = np.asarray(new_z) - np.asarray(new_origin)
277
    new_z_vector /= np.sqrt(np.sum(np.square(new_z_vector)))
278
    # New image size (shape)
279
    new_size = image.GetSize()
280
    # New image spacing 
281
    new_spacing = image.GetSpacing()
282
    # Create 3x3 transformation matrix from the x/y/z unit vectors. 
283
    new_three_by_three = np.zeros((3,3))
284
    new_three_by_three[:,0] = new_x_vector
285
    new_three_by_three[:,1] = new_y_vector
286
    new_three_by_three[:,2] = new_z_vector
287
288
    new_image = sitk.Resample(image, 
289
                              new_size,
290
                              transform,
291
                              interpolator,
292
                              new_origin, 
293
                              new_spacing,
294
                              new_three_by_three.flatten().tolist())
295
    return new_image
296
297
def create_vtk_image(
298
    origin: Optional[int] = [0, 0, 0],
299
    dimensions: Optional[list] = [20, 20, 20],
300
    spacing: Optional[float] = [1., 1., 1.],
301
    scalar: Optional[float] = 20.,
302
    data: Optional[np.ndarray] = None
303
):
304
    &#34;&#34;&#34;
305
    Function to create a 3D vtkimage from a numpy array
306
    OR to create a uniform image (all same value)
307
308
    Parameters
309
    ----------
310
    origin : Optional[int], optional
311
        X/Y/Z origin of the image, by default [0, 0, 0]
312
    dimensions : Optional[list], optional
313
        Size of the image along each dimension, by default [20, 20, 20]
314
    spacing : Optional[float], optional
315
        Image spacing along each dimension, by default [1., 1., 1.]
316
    scalar : Optional[float], optional
317
        Scalar value to use for a uniform image, by default 20.
318
    data : Optional[np.ndarray], optional
319
        Data for a non-uniform image, by default None
320
    &#34;&#34;&#34;    
321
    
322
    if data is None:
323
        data = np.ones(dimensions) * scalar
324
    else:
325
        if len(data.shape) == 3:
326
            dimensions = data.shape
327
        else:
328
            dimensions = [1, 1, 1]
329
            for idx, dim_size in enumerate(data.shape):
330
                dimensions[idx] = dim_size
331
    vtk_array = numpy_to_vtk(data.flatten(order=&#39;F&#39;))
332
    vtk_array.SetName(&#39;test&#39;)
333
334
    # points = vtk.vtkDoubleArray()
335
    # points.SetName(&#39;test&#39;)
336
    # points.SetNumberOfComponents(1)
337
    # points.SetNumberOfTuples(np.product(dimensions))
338
    # for x in range(dimensions[0]):
339
    #   for y in range(dimensions[1]):
340
    #      for z in range(dimensions[2]):
341
    #         points.SetValue(
342
    #            (z * dimensions[0] * dimensions[1]) + (x * dimensions[1]) + y,
343
    #            array[x, y, z]
344
    #         )
345
346
    vtk_image = vtk.vtkImageData()
347
    vtk_image.SetOrigin(*origin)
348
    vtk_image.SetDimensions(*dimensions)
349
    vtk_image.SetSpacing(*spacing)
350
    vtk_image.GetPointData().SetScalars(vtk_array)            
351
352
# 
353
    return vtk_image</code></pre>
354
</details>
355
</section>
356
<section>
357
</section>
358
<section>
359
</section>
360
<section>
361
<h2 class="section-title" id="header-functions">Functions</h2>
362
<dl>
363
<dt id="pymskt.image.main.apply_transform_retain_array"><code class="name flex">
364
<span>def <span class="ident">apply_transform_retain_array</span></span>(<span>image, transform, interpolator=1)</span>
365
</code></dt>
366
<dd>
367
<div class="desc"><p>This function will move the actual image in space but keep the underlying array the same.
368
So, in x/y/z land the pixels are in a new location, but the actual underlying data array
369
is the same. </p>
370
<h2 id="parameters">Parameters</h2>
371
<dl>
372
<dt><strong><code>image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
373
<dd>Image to be transformed.</dd>
374
<dt><strong><code>transform</code></strong> :&ensp;<code>SimpleITK.Transform</code></dt>
375
<dd>Transform to apply</dd>
376
<dt><strong><code>interpolator</code></strong> :&ensp;<code>SimpleITK.Interpolator</code>, optional</dt>
377
<dd>Interpolator type to use, by default sitk.sitkNearestNeighbor</dd>
378
</dl>
379
<h2 id="returns">Returns</h2>
380
<dl>
381
<dt><code>SimpleITK.Image</code></dt>
382
<dd>New image after applying the appropriate transform.</dd>
383
</dl>
384
<h2 id="notes">Notes</h2>
385
<p>I have a feeling that this is overkill.</p></div>
386
<details class="source">
387
<summary>
388
<span>Expand source code</span>
389
</summary>
390
<pre><code class="python">def apply_transform_retain_array(image, transform, interpolator=sitk.sitkNearestNeighbor):
391
    &#34;&#34;&#34;
392
    This function will move the actual image in space but keep the underlying array the same. 
393
    So, in x/y/z land the pixels are in a new location, but the actual underlying data array 
394
    is the same. 
395
396
    Parameters
397
    ----------
398
    image : SimpleITK.Image
399
        Image to be transformed.
400
    transform : SimpleITK.Transform
401
        Transform to apply
402
    interpolator : SimpleITK.Interpolator, optional
403
        Interpolator type to use, by default sitk.sitkNearestNeighbor
404
405
    Returns
406
    -------
407
    SimpleITK.Image
408
        New image after applying the appropriate transform.
409
    
410
    Notes
411
    -----
412
    I have a feeling that this is overkill.
413
    &#34;&#34;&#34;    
414
415
    inverse_transform = transform.GetInverse()
416
    new_origin = inverse_transform.TransformPoint(image.GetOrigin())
417
418
    new_x = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((image.GetSize()[0], 0, 0)))
419
    new_y = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, image.GetSize()[1], 0)))
420
    new_z = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, 0, image.GetSize()[2])))
421
422
    # Create x-axis vector
423
    new_x_vector = np.asarray(new_x) - np.asarray(new_origin)
424
    new_x_vector /= np.sqrt(np.sum(np.square(new_x_vector)))
425
    # Create y-axis vector
426
    new_y_vector = np.asarray(new_y) - np.asarray(new_origin)
427
    new_y_vector /= np.sqrt(np.sum(np.square(new_y_vector)))
428
    # Create z-axis vector
429
    new_z_vector = np.asarray(new_z) - np.asarray(new_origin)
430
    new_z_vector /= np.sqrt(np.sum(np.square(new_z_vector)))
431
    # New image size (shape)
432
    new_size = image.GetSize()
433
    # New image spacing 
434
    new_spacing = image.GetSpacing()
435
    # Create 3x3 transformation matrix from the x/y/z unit vectors. 
436
    new_three_by_three = np.zeros((3,3))
437
    new_three_by_three[:,0] = new_x_vector
438
    new_three_by_three[:,1] = new_y_vector
439
    new_three_by_three[:,2] = new_z_vector
440
441
    new_image = sitk.Resample(image, 
442
                              new_size,
443
                              transform,
444
                              interpolator,
445
                              new_origin, 
446
                              new_spacing,
447
                              new_three_by_three.flatten().tolist())
448
    return new_image</code></pre>
449
</details>
450
</dd>
451
<dt id="pymskt.image.main.binarize_segmentation_image"><code class="name flex">
452
<span>def <span class="ident">binarize_segmentation_image</span></span>(<span>seg_image, label_idx)</span>
453
</code></dt>
454
<dd>
455
<div class="desc"><p>Return segmentation that is only 0s/1s, with 1s where label_idx is
456
located in the image. </p>
457
<h2 id="parameters">Parameters</h2>
458
<dl>
459
<dt><strong><code>seg_image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
460
<dd>Segmentation image that contains data we want to binarize</dd>
461
<dt><strong><code>label_idx</code></strong> :&ensp;<code>int</code></dt>
462
<dd>Integer/label that we want to extract (binarize) from the
463
<code>seg_image</code>.</dd>
464
</dl>
465
<h2 id="returns">Returns</h2>
466
<dl>
467
<dt><code>SimpleITK.Image</code></dt>
468
<dd>New segmentation image that is binarized.</dd>
469
</dl></div>
470
<details class="source">
471
<summary>
472
<span>Expand source code</span>
473
</summary>
474
<pre><code class="python">def binarize_segmentation_image(seg_image, label_idx):
475
    &#34;&#34;&#34;
476
    Return segmentation that is only 0s/1s, with 1s where label_idx is
477
    located in the image. 
478
479
    Parameters
480
    ----------
481
    seg_image : SimpleITK.Image
482
        Segmentation image that contains data we want to binarize
483
    label_idx : int
484
        Integer/label that we want to extract (binarize) from the
485
        `seg_image`.
486
487
    Returns
488
    -------
489
    SimpleITK.Image
490
        New segmentation image that is binarized. 
491
    &#34;&#34;&#34;    
492
    array = sitk.GetArrayFromImage(seg_image)
493
    array_ = np.zeros_like(array)
494
    array_[array == label_idx] = 1
495
    new_seg_image = sitk.GetImageFromArray(array_)
496
    new_seg_image.CopyInformation(seg_image)
497
    return new_seg_image</code></pre>
498
</details>
499
</dd>
500
<dt id="pymskt.image.main.create_vtk_image"><code class="name flex">
501
<span>def <span class="ident">create_vtk_image</span></span>(<span>origin: Optional[int] = [0, 0, 0], dimensions: Optional[list] = [20, 20, 20], spacing: Optional[float] = [1.0, 1.0, 1.0], scalar: Optional[float] = 20.0, data: Optional[numpy.ndarray] = None)</span>
502
</code></dt>
503
<dd>
504
<div class="desc"><p>Function to create a 3D vtkimage from a numpy array
505
OR to create a uniform image (all same value)</p>
506
<h2 id="parameters">Parameters</h2>
507
<dl>
508
<dt><strong><code>origin</code></strong> :&ensp;<code>Optional[int]</code>, optional</dt>
509
<dd>X/Y/Z origin of the image, by default [0, 0, 0]</dd>
510
<dt><strong><code>dimensions</code></strong> :&ensp;<code>Optional[list]</code>, optional</dt>
511
<dd>Size of the image along each dimension, by default [20, 20, 20]</dd>
512
<dt><strong><code>spacing</code></strong> :&ensp;<code>Optional[float]</code>, optional</dt>
513
<dd>Image spacing along each dimension, by default [1., 1., 1.]</dd>
514
<dt><strong><code>scalar</code></strong> :&ensp;<code>Optional[float]</code>, optional</dt>
515
<dd>Scalar value to use for a uniform image, by default 20.</dd>
516
<dt><strong><code>data</code></strong> :&ensp;<code>Optional[np.ndarray]</code>, optional</dt>
517
<dd>Data for a non-uniform image, by default None</dd>
518
</dl></div>
519
<details class="source">
520
<summary>
521
<span>Expand source code</span>
522
</summary>
523
<pre><code class="python">def create_vtk_image(
524
    origin: Optional[int] = [0, 0, 0],
525
    dimensions: Optional[list] = [20, 20, 20],
526
    spacing: Optional[float] = [1., 1., 1.],
527
    scalar: Optional[float] = 20.,
528
    data: Optional[np.ndarray] = None
529
):
530
    &#34;&#34;&#34;
531
    Function to create a 3D vtkimage from a numpy array
532
    OR to create a uniform image (all same value)
533
534
    Parameters
535
    ----------
536
    origin : Optional[int], optional
537
        X/Y/Z origin of the image, by default [0, 0, 0]
538
    dimensions : Optional[list], optional
539
        Size of the image along each dimension, by default [20, 20, 20]
540
    spacing : Optional[float], optional
541
        Image spacing along each dimension, by default [1., 1., 1.]
542
    scalar : Optional[float], optional
543
        Scalar value to use for a uniform image, by default 20.
544
    data : Optional[np.ndarray], optional
545
        Data for a non-uniform image, by default None
546
    &#34;&#34;&#34;    
547
    
548
    if data is None:
549
        data = np.ones(dimensions) * scalar
550
    else:
551
        if len(data.shape) == 3:
552
            dimensions = data.shape
553
        else:
554
            dimensions = [1, 1, 1]
555
            for idx, dim_size in enumerate(data.shape):
556
                dimensions[idx] = dim_size
557
    vtk_array = numpy_to_vtk(data.flatten(order=&#39;F&#39;))
558
    vtk_array.SetName(&#39;test&#39;)
559
560
    # points = vtk.vtkDoubleArray()
561
    # points.SetName(&#39;test&#39;)
562
    # points.SetNumberOfComponents(1)
563
    # points.SetNumberOfTuples(np.product(dimensions))
564
    # for x in range(dimensions[0]):
565
    #   for y in range(dimensions[1]):
566
    #      for z in range(dimensions[2]):
567
    #         points.SetValue(
568
    #            (z * dimensions[0] * dimensions[1]) + (x * dimensions[1]) + y,
569
    #            array[x, y, z]
570
    #         )
571
572
    vtk_image = vtk.vtkImageData()
573
    vtk_image.SetOrigin(*origin)
574
    vtk_image.SetDimensions(*dimensions)
575
    vtk_image.SetSpacing(*spacing)
576
    vtk_image.GetPointData().SetScalars(vtk_array)            
577
578
# 
579
    return vtk_image</code></pre>
580
</details>
581
</dd>
582
<dt id="pymskt.image.main.crop_bone_based_on_width"><code class="name flex">
583
<span>def <span class="ident">crop_bone_based_on_width</span></span>(<span>seg_image, bone_idx, np_med_lat_axis=0, np_inf_sup_axis=1, bone_crop_distal=True, value_to_reassign=0, percent_width_to_crop_height=1.0)</span>
584
</code></dt>
585
<dd>
586
<div class="desc"><p>Crop the bone labelmap of a SimpleITK.Image so that it is proportional to the
587
bones medial/lateral width. </p>
588
<h2 id="parameters">Parameters</h2>
589
<dl>
590
<dt><strong><code>seg_image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
591
<dd>Image to be cropped.</dd>
592
<dt><strong><code>bone_idx</code></strong> :&ensp;<code>int</code></dt>
593
<dd>Label_index of the bone to be cropped.</dd>
594
<dt><strong><code>np_med_lat_axis</code></strong> :&ensp;<code>int</code>, optional</dt>
595
<dd>Medial/lateral axis, by default 0</dd>
596
<dt><strong><code>np_inf_sup_axis</code></strong> :&ensp;<code>int</code>, optional</dt>
597
<dd>Inferior/superir axis, by default 1</dd>
598
<dt><strong><code>bone_crop_distal</code></strong> :&ensp;<code>bool</code>, optional</dt>
599
<dd>Boolean of cropping should occur distal or proximally, by default True</dd>
600
<dt><strong><code>value_to_reassign</code></strong> :&ensp;<code>int</code>, optional</dt>
601
<dd>Value to replace bone label with, by default 0</dd>
602
<dt><strong><code>percent_width_to_crop_height</code></strong> :&ensp;<code>float</code>, optional</dt>
603
<dd>Bone length as a proportion of width, by default 1.0</dd>
604
</dl>
605
<h2 id="returns">Returns</h2>
606
<dl>
607
<dt><code>SimpleITK.Image</code></dt>
608
<dd>Image after bone is cropped as a proportion of the bone's width.</dd>
609
</dl></div>
610
<details class="source">
611
<summary>
612
<span>Expand source code</span>
613
</summary>
614
<pre><code class="python">def crop_bone_based_on_width(seg_image,
615
                             bone_idx,
616
                             np_med_lat_axis=0,
617
                             np_inf_sup_axis=1,
618
                             bone_crop_distal=True,
619
                             value_to_reassign=0,
620
                             percent_width_to_crop_height=1.0):
621
    &#34;&#34;&#34;
622
    Crop the bone labelmap of a SimpleITK.Image so that it is proportional to the
623
    bones medial/lateral width. 
624
625
    Parameters
626
    ----------
627
    seg_image : SimpleITK.Image
628
        Image to be cropped. 
629
    bone_idx : int
630
        Label_index of the bone to be cropped. 
631
    np_med_lat_axis : int, optional
632
        Medial/lateral axis, by default 0
633
    np_inf_sup_axis : int, optional
634
        Inferior/superir axis, by default 1
635
    bone_crop_distal : bool, optional
636
        Boolean of cropping should occur distal or proximally, by default True
637
    value_to_reassign : int, optional
638
        Value to replace bone label with, by default 0
639
    percent_width_to_crop_height : float, optional
640
        Bone length as a proportion of width, by default 1.0
641
642
    Returns
643
    -------
644
    SimpleITK.Image
645
        Image after bone is cropped as a proportion of the bone&#39;s width. 
646
    &#34;&#34;&#34;    
647
    seg_array = sitk.GetArrayFromImage(seg_image)
648
    loc_bone = np.where(seg_array == bone_idx)
649
    med_lat_width_bone_mm = (np.max(loc_bone[np_med_lat_axis]) - np.min(loc_bone[np_med_lat_axis])) * \
650
                            seg_image.GetSpacing()[::-1][np_med_lat_axis]
651
    inf_sup_crop_in_pixels = (med_lat_width_bone_mm / seg_image.GetSpacing()[::-1][
652
        np_inf_sup_axis]) * percent_width_to_crop_height
653
    if bone_crop_distal is True:
654
        bone_distal_idx = np.max(loc_bone[np_inf_sup_axis])
655
        bone_proximal_idx = bone_distal_idx - inf_sup_crop_in_pixels
656
        if bone_proximal_idx &lt; 1:
657
            bone_proximal_idx = 1
658
659
    elif bone_crop_distal is False:
660
        bone_proximal_idx = np.min(loc_bone[np_inf_sup_axis])
661
        bone_distal_idx = bone_proximal_idx + inf_sup_crop_in_pixels
662
        if bone_distal_idx &gt; seg_array.shape[np_inf_sup_axis]:
663
            bone_distal_idx = seg_array.shape[np_inf_sup_axis] - 1
664
665
    max_inf_sup_idx = max(bone_distal_idx, bone_proximal_idx)
666
    min_inf_sup_idx = min(bone_distal_idx, bone_proximal_idx)
667
668
    idx_bone_to_keep = np.where(
669
        (loc_bone[np_inf_sup_axis] &gt; min_inf_sup_idx) &amp; (loc_bone[np_inf_sup_axis] &lt; max_inf_sup_idx))
670
    loc_bone_to_remove = tuple([np.delete(x, idx_bone_to_keep) for x in loc_bone])
671
672
    seg_array[loc_bone_to_remove] = value_to_reassign
673
674
    new_seg_image = sitk.GetImageFromArray(seg_array)
675
    new_seg_image.CopyInformation(seg_image)
676
677
    return new_seg_image</code></pre>
678
</details>
679
</dd>
680
<dt id="pymskt.image.main.read_nrrd"><code class="name flex">
681
<span>def <span class="ident">read_nrrd</span></span>(<span>path, set_origin_zero=False)</span>
682
</code></dt>
683
<dd>
684
<div class="desc"><p>Read NRRD image file into vtk. Enables usage of marching cubes
685
and other functions that work on image data.</p>
686
<h2 id="parameters">Parameters</h2>
687
<dl>
688
<dt><strong><code>path</code></strong> :&ensp;<code>str</code></dt>
689
<dd>Path to <code>.nrrd</code> medical image to read in.</dd>
690
<dt><strong><code>set_origin_zero</code></strong> :&ensp;<code>bool</code>, optional</dt>
691
<dd>Bool to determine if origin should be set to zeros, by default False</dd>
692
</dl>
693
<h2 id="returns">Returns</h2>
694
<dl>
695
<dt><code>vtk.Filter</code></dt>
696
<dd>End of VTK filter pipeline.</dd>
697
</dl></div>
698
<details class="source">
699
<summary>
700
<span>Expand source code</span>
701
</summary>
702
<pre><code class="python">def read_nrrd(path, set_origin_zero=False):
703
    &#34;&#34;&#34;
704
    Read NRRD image file into vtk. Enables usage of marching cubes
705
    and other functions that work on image data.
706
707
    Parameters
708
    ----------
709
    path : str
710
        Path to `.nrrd` medical image to read in. 
711
    set_origin_zero : bool, optional
712
        Bool to determine if origin should be set to zeros, by default False
713
714
    Returns
715
    -------
716
    vtk.Filter
717
        End of VTK filter pipeline. 
718
    &#34;&#34;&#34;    
719
720
    image_reader = vtk.vtkNrrdReader()
721
    image_reader.SetFileName(path)
722
    image_reader.Update()
723
    if set_origin_zero is True:
724
        change_origin = set_vtk_image_origin(image_reader, new_origin=(0, 0, 0))
725
        return change_origin
726
    elif set_origin_zero is False:
727
        return image_reader</code></pre>
728
</details>
729
</dd>
730
<dt id="pymskt.image.main.set_seg_border_to_zeros"><code class="name flex">
731
<span>def <span class="ident">set_seg_border_to_zeros</span></span>(<span>seg_image, border_size=1)</span>
732
</code></dt>
733
<dd>
734
<div class="desc"><p>Utility function to ensure that all segmentations are "closed" after marching cubes.
735
If the segmentation extends to the edges of the image then the surface wont be closed
736
at the places it touches the edges. </p>
737
<h2 id="parameters">Parameters</h2>
738
<dl>
739
<dt><strong><code>seg_image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
740
<dd>Image of a segmentation.</dd>
741
<dt><strong><code>border_size</code></strong> :&ensp;<code>int</code>, optional</dt>
742
<dd>The size of the border to set around the edges of the 3D image, by default 1</dd>
743
</dl>
744
<h2 id="returns">Returns</h2>
745
<dl>
746
<dt><code>SimpleITK.Image</code></dt>
747
<dd>The image with border set to 0 (background).</dd>
748
</dl></div>
749
<details class="source">
750
<summary>
751
<span>Expand source code</span>
752
</summary>
753
<pre><code class="python">def set_seg_border_to_zeros(seg_image,
754
                            border_size=1):
755
    &#34;&#34;&#34;
756
    Utility function to ensure that all segmentations are &#34;closed&#34; after marching cubes. 
757
    If the segmentation extends to the edges of the image then the surface wont be closed 
758
    at the places it touches the edges. 
759
760
    Parameters
761
    ----------
762
    seg_image : SimpleITK.Image
763
        Image of a segmentation. 
764
    border_size : int, optional
765
        The size of the border to set around the edges of the 3D image, by default 1
766
767
    Returns
768
    -------
769
    SimpleITK.Image
770
        The image with border set to 0 (background). 
771
    &#34;&#34;&#34;    
772
773
    seg_array = sitk.GetArrayFromImage(seg_image)
774
    new_seg_array = np.zeros_like(seg_array)
775
    new_seg_array[border_size:-border_size, border_size:-border_size, border_size:-border_size] = seg_array[border_size:-border_size, border_size:-border_size, border_size:-border_size]
776
    new_seg_image = sitk.GetImageFromArray(new_seg_array)
777
    new_seg_image.CopyInformation(seg_image)
778
    return new_seg_image</code></pre>
779
</details>
780
</dd>
781
<dt id="pymskt.image.main.set_vtk_image_origin"><code class="name flex">
782
<span>def <span class="ident">set_vtk_image_origin</span></span>(<span>vtk_image, new_origin=(0, 0, 0))</span>
783
</code></dt>
784
<dd>
785
<div class="desc"><p>Reset the origin of a <code>vtk_image</code></p>
786
<h2 id="parameters">Parameters</h2>
787
<dl>
788
<dt><strong><code>vtk_image</code></strong> :&ensp;<code>vtk.image</code></dt>
789
<dd>VTK image that we want to change the origin of.</dd>
790
<dt><strong><code>new_origin</code></strong> :&ensp;<code>tuple</code>, optional</dt>
791
<dd>New origin to asign to <code>vtk_image</code>, by default (0, 0, 0)</dd>
792
</dl>
793
<h2 id="returns">Returns</h2>
794
<dl>
795
<dt><code>vtk.Filter</code></dt>
796
<dd>End of VTK filter pipeline after applying origin change.</dd>
797
</dl></div>
798
<details class="source">
799
<summary>
800
<span>Expand source code</span>
801
</summary>
802
<pre><code class="python">def set_vtk_image_origin(vtk_image, new_origin=(0, 0, 0)):
803
    &#34;&#34;&#34;
804
    Reset the origin of a `vtk_image`
805
806
    Parameters
807
    ----------
808
    vtk_image : vtk.image
809
        VTK image that we want to change the origin of. 
810
    new_origin : tuple, optional
811
        New origin to asign to `vtk_image`, by default (0, 0, 0)
812
813
    Returns
814
    -------
815
    vtk.Filter
816
        End of VTK filter pipeline after applying origin change. 
817
    &#34;&#34;&#34;    
818
819
    change_origin = vtk.vtkImageChangeInformation()
820
    change_origin.SetInputConnection(vtk_image.GetOutputPort())
821
    change_origin.SetOutputOrigin(new_origin)
822
    change_origin.Update()
823
    return change_origin</code></pre>
824
</details>
825
</dd>
826
<dt id="pymskt.image.main.smooth_image"><code class="name flex">
827
<span>def <span class="ident">smooth_image</span></span>(<span>image, label_idx, variance=1.0)</span>
828
</code></dt>
829
<dd>
830
<div class="desc"><p>Smooth a single label in a SimpleITK image. Used as pre-processing for
831
bones/cartilage before applying marching cubes. Helps obtain smooth surfaces. </p>
832
<h2 id="parameters">Parameters</h2>
833
<dl>
834
<dt><strong><code>image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
835
<dd>Image to be smoothed.</dd>
836
<dt><strong><code>label_idx</code></strong> :&ensp;<code>int</code></dt>
837
<dd>Integer of the tissue of interest to be smoothed in the image.</dd>
838
<dt><strong><code>variance</code></strong> :&ensp;<code>float</code>, optional</dt>
839
<dd>The size of the smoothing, by default 1.0</dd>
840
</dl>
841
<h2 id="returns">Returns</h2>
842
<dl>
843
<dt><code>SimpleITK.Image</code></dt>
844
<dd>Image of only the label (tissue) of interest after being smoothed.</dd>
845
</dl></div>
846
<details class="source">
847
<summary>
848
<span>Expand source code</span>
849
</summary>
850
<pre><code class="python">def smooth_image(image, label_idx, variance=1.0):
851
    &#34;&#34;&#34;
852
    Smooth a single label in a SimpleITK image. Used as pre-processing for 
853
    bones/cartilage before applying marching cubes. Helps obtain smooth surfaces. 
854
855
    Parameters
856
    ----------
857
    image : SimpleITK.Image
858
        Image to be smoothed. 
859
    label_idx : int
860
        Integer of the tissue of interest to be smoothed in the image. 
861
    variance : float, optional
862
        The size of the smoothing, by default 1.0
863
864
    Returns
865
    -------
866
    SimpleITK.Image
867
        Image of only the label (tissue) of interest after being smoothed. 
868
    &#34;&#34;&#34;    
869
    new_image = binarize_segmentation_image(image, label_idx)
870
871
    new_image = sitk.Cast(new_image, sitk.sitkFloat32)
872
873
    gauss_filter = sitk.DiscreteGaussianImageFilter()
874
    gauss_filter.SetVariance(variance)
875
    #     gauss_filter.SetUseImageSpacingOn
876
    gauss_filter.SetUseImageSpacing(True)
877
    filtered_new_image = gauss_filter.Execute(new_image)
878
879
    return filtered_new_image</code></pre>
880
</details>
881
</dd>
882
</dl>
883
</section>
884
<section>
885
</section>
886
</article>
887
<nav id="sidebar">
888
<h1>Index</h1>
889
<div class="toc">
890
<ul></ul>
891
</div>
892
<ul id="index">
893
<li><h3>Super-module</h3>
894
<ul>
895
<li><code><a title="pymskt.image" href="index.html">pymskt.image</a></code></li>
896
</ul>
897
</li>
898
<li><h3><a href="#header-functions">Functions</a></h3>
899
<ul class="">
900
<li><code><a title="pymskt.image.main.apply_transform_retain_array" href="#pymskt.image.main.apply_transform_retain_array">apply_transform_retain_array</a></code></li>
901
<li><code><a title="pymskt.image.main.binarize_segmentation_image" href="#pymskt.image.main.binarize_segmentation_image">binarize_segmentation_image</a></code></li>
902
<li><code><a title="pymskt.image.main.create_vtk_image" href="#pymskt.image.main.create_vtk_image">create_vtk_image</a></code></li>
903
<li><code><a title="pymskt.image.main.crop_bone_based_on_width" href="#pymskt.image.main.crop_bone_based_on_width">crop_bone_based_on_width</a></code></li>
904
<li><code><a title="pymskt.image.main.read_nrrd" href="#pymskt.image.main.read_nrrd">read_nrrd</a></code></li>
905
<li><code><a title="pymskt.image.main.set_seg_border_to_zeros" href="#pymskt.image.main.set_seg_border_to_zeros">set_seg_border_to_zeros</a></code></li>
906
<li><code><a title="pymskt.image.main.set_vtk_image_origin" href="#pymskt.image.main.set_vtk_image_origin">set_vtk_image_origin</a></code></li>
907
<li><code><a title="pymskt.image.main.smooth_image" href="#pymskt.image.main.smooth_image">smooth_image</a></code></li>
908
</ul>
909
</li>
910
</ul>
911
</nav>
912
</main>
913
<footer id="footer">
914
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
915
</footer>
916
</body>
917
</html>