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

Switch to side-by-side view

--- a
+++ b/docs/image/main.html
@@ -0,0 +1,917 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>pymskt.image.main API documentation</title>
+<meta name="description" content="" />
+<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>
+<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>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<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>
+<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>
+<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>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>pymskt.image.main</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">from typing import Optional
+import os
+import vtk
+import SimpleITK as sitk
+import numpy as np
+from vtk.util.numpy_support import numpy_to_vtk
+
+
+def set_vtk_image_origin(vtk_image, new_origin=(0, 0, 0)):
+    &#34;&#34;&#34;
+    Reset the origin of a `vtk_image`
+
+    Parameters
+    ----------
+    vtk_image : vtk.image
+        VTK image that we want to change the origin of. 
+    new_origin : tuple, optional
+        New origin to asign to `vtk_image`, by default (0, 0, 0)
+
+    Returns
+    -------
+    vtk.Filter
+        End of VTK filter pipeline after applying origin change. 
+    &#34;&#34;&#34;    
+
+    change_origin = vtk.vtkImageChangeInformation()
+    change_origin.SetInputConnection(vtk_image.GetOutputPort())
+    change_origin.SetOutputOrigin(new_origin)
+    change_origin.Update()
+    return change_origin
+
+def read_nrrd(path, set_origin_zero=False):
+    &#34;&#34;&#34;
+    Read NRRD image file into vtk. Enables usage of marching cubes
+    and other functions that work on image data.
+
+    Parameters
+    ----------
+    path : str
+        Path to `.nrrd` medical image to read in. 
+    set_origin_zero : bool, optional
+        Bool to determine if origin should be set to zeros, by default False
+
+    Returns
+    -------
+    vtk.Filter
+        End of VTK filter pipeline. 
+    &#34;&#34;&#34;    
+
+    image_reader = vtk.vtkNrrdReader()
+    image_reader.SetFileName(path)
+    image_reader.Update()
+    if set_origin_zero is True:
+        change_origin = set_vtk_image_origin(image_reader, new_origin=(0, 0, 0))
+        return change_origin
+    elif set_origin_zero is False:
+        return image_reader
+
+
+def set_seg_border_to_zeros(seg_image,
+                            border_size=1):
+    &#34;&#34;&#34;
+    Utility function to ensure that all segmentations are &#34;closed&#34; after marching cubes. 
+    If the segmentation extends to the edges of the image then the surface wont be closed 
+    at the places it touches the edges. 
+
+    Parameters
+    ----------
+    seg_image : SimpleITK.Image
+        Image of a segmentation. 
+    border_size : int, optional
+        The size of the border to set around the edges of the 3D image, by default 1
+
+    Returns
+    -------
+    SimpleITK.Image
+        The image with border set to 0 (background). 
+    &#34;&#34;&#34;    
+
+    seg_array = sitk.GetArrayFromImage(seg_image)
+    new_seg_array = np.zeros_like(seg_array)
+    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]
+    new_seg_image = sitk.GetImageFromArray(new_seg_array)
+    new_seg_image.CopyInformation(seg_image)
+    return new_seg_image
+
+
+def smooth_image(image, label_idx, variance=1.0):
+    &#34;&#34;&#34;
+    Smooth a single label in a SimpleITK image. Used as pre-processing for 
+    bones/cartilage before applying marching cubes. Helps obtain smooth surfaces. 
+
+    Parameters
+    ----------
+    image : SimpleITK.Image
+        Image to be smoothed. 
+    label_idx : int
+        Integer of the tissue of interest to be smoothed in the image. 
+    variance : float, optional
+        The size of the smoothing, by default 1.0
+
+    Returns
+    -------
+    SimpleITK.Image
+        Image of only the label (tissue) of interest after being smoothed. 
+    &#34;&#34;&#34;    
+    new_image = binarize_segmentation_image(image, label_idx)
+
+    new_image = sitk.Cast(new_image, sitk.sitkFloat32)
+
+    gauss_filter = sitk.DiscreteGaussianImageFilter()
+    gauss_filter.SetVariance(variance)
+    #     gauss_filter.SetUseImageSpacingOn
+    gauss_filter.SetUseImageSpacing(True)
+    filtered_new_image = gauss_filter.Execute(new_image)
+
+    return filtered_new_image
+
+def binarize_segmentation_image(seg_image, label_idx):
+    &#34;&#34;&#34;
+    Return segmentation that is only 0s/1s, with 1s where label_idx is
+    located in the image. 
+
+    Parameters
+    ----------
+    seg_image : SimpleITK.Image
+        Segmentation image that contains data we want to binarize
+    label_idx : int
+        Integer/label that we want to extract (binarize) from the
+        `seg_image`.
+
+    Returns
+    -------
+    SimpleITK.Image
+        New segmentation image that is binarized. 
+    &#34;&#34;&#34;    
+    array = sitk.GetArrayFromImage(seg_image)
+    array_ = np.zeros_like(array)
+    array_[array == label_idx] = 1
+    new_seg_image = sitk.GetImageFromArray(array_)
+    new_seg_image.CopyInformation(seg_image)
+    return new_seg_image
+
+def crop_bone_based_on_width(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):
+    &#34;&#34;&#34;
+    Crop the bone labelmap of a SimpleITK.Image so that it is proportional to the
+    bones medial/lateral width. 
+
+    Parameters
+    ----------
+    seg_image : SimpleITK.Image
+        Image to be cropped. 
+    bone_idx : int
+        Label_index of the bone to be cropped. 
+    np_med_lat_axis : int, optional
+        Medial/lateral axis, by default 0
+    np_inf_sup_axis : int, optional
+        Inferior/superir axis, by default 1
+    bone_crop_distal : bool, optional
+        Boolean of cropping should occur distal or proximally, by default True
+    value_to_reassign : int, optional
+        Value to replace bone label with, by default 0
+    percent_width_to_crop_height : float, optional
+        Bone length as a proportion of width, by default 1.0
+
+    Returns
+    -------
+    SimpleITK.Image
+        Image after bone is cropped as a proportion of the bone&#39;s width. 
+    &#34;&#34;&#34;    
+    seg_array = sitk.GetArrayFromImage(seg_image)
+    loc_bone = np.where(seg_array == bone_idx)
+    med_lat_width_bone_mm = (np.max(loc_bone[np_med_lat_axis]) - np.min(loc_bone[np_med_lat_axis])) * \
+                            seg_image.GetSpacing()[::-1][np_med_lat_axis]
+    inf_sup_crop_in_pixels = (med_lat_width_bone_mm / seg_image.GetSpacing()[::-1][
+        np_inf_sup_axis]) * percent_width_to_crop_height
+    if bone_crop_distal is True:
+        bone_distal_idx = np.max(loc_bone[np_inf_sup_axis])
+        bone_proximal_idx = bone_distal_idx - inf_sup_crop_in_pixels
+        if bone_proximal_idx &lt; 1:
+            bone_proximal_idx = 1
+
+    elif bone_crop_distal is False:
+        bone_proximal_idx = np.min(loc_bone[np_inf_sup_axis])
+        bone_distal_idx = bone_proximal_idx + inf_sup_crop_in_pixels
+        if bone_distal_idx &gt; seg_array.shape[np_inf_sup_axis]:
+            bone_distal_idx = seg_array.shape[np_inf_sup_axis] - 1
+
+    max_inf_sup_idx = max(bone_distal_idx, bone_proximal_idx)
+    min_inf_sup_idx = min(bone_distal_idx, bone_proximal_idx)
+
+    idx_bone_to_keep = np.where(
+        (loc_bone[np_inf_sup_axis] &gt; min_inf_sup_idx) &amp; (loc_bone[np_inf_sup_axis] &lt; max_inf_sup_idx))
+    loc_bone_to_remove = tuple([np.delete(x, idx_bone_to_keep) for x in loc_bone])
+
+    seg_array[loc_bone_to_remove] = value_to_reassign
+
+    new_seg_image = sitk.GetImageFromArray(seg_array)
+    new_seg_image.CopyInformation(seg_image)
+
+    return new_seg_image
+
+def apply_transform_retain_array(image, transform, interpolator=sitk.sitkNearestNeighbor):
+    &#34;&#34;&#34;
+    This function will move the actual image in space but keep the underlying array the same. 
+    So, in x/y/z land the pixels are in a new location, but the actual underlying data array 
+    is the same. 
+
+    Parameters
+    ----------
+    image : SimpleITK.Image
+        Image to be transformed.
+    transform : SimpleITK.Transform
+        Transform to apply
+    interpolator : SimpleITK.Interpolator, optional
+        Interpolator type to use, by default sitk.sitkNearestNeighbor
+
+    Returns
+    -------
+    SimpleITK.Image
+        New image after applying the appropriate transform.
+    
+    Notes
+    -----
+    I have a feeling that this is overkill.
+    &#34;&#34;&#34;    
+
+    inverse_transform = transform.GetInverse()
+    new_origin = inverse_transform.TransformPoint(image.GetOrigin())
+
+    new_x = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((image.GetSize()[0], 0, 0)))
+    new_y = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, image.GetSize()[1], 0)))
+    new_z = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, 0, image.GetSize()[2])))
+
+    # Create x-axis vector
+    new_x_vector = np.asarray(new_x) - np.asarray(new_origin)
+    new_x_vector /= np.sqrt(np.sum(np.square(new_x_vector)))
+    # Create y-axis vector
+    new_y_vector = np.asarray(new_y) - np.asarray(new_origin)
+    new_y_vector /= np.sqrt(np.sum(np.square(new_y_vector)))
+    # Create z-axis vector
+    new_z_vector = np.asarray(new_z) - np.asarray(new_origin)
+    new_z_vector /= np.sqrt(np.sum(np.square(new_z_vector)))
+    # New image size (shape)
+    new_size = image.GetSize()
+    # New image spacing 
+    new_spacing = image.GetSpacing()
+    # Create 3x3 transformation matrix from the x/y/z unit vectors. 
+    new_three_by_three = np.zeros((3,3))
+    new_three_by_three[:,0] = new_x_vector
+    new_three_by_three[:,1] = new_y_vector
+    new_three_by_three[:,2] = new_z_vector
+
+    new_image = sitk.Resample(image, 
+                              new_size,
+                              transform,
+                              interpolator,
+                              new_origin, 
+                              new_spacing,
+                              new_three_by_three.flatten().tolist())
+    return new_image
+
+def create_vtk_image(
+    origin: Optional[int] = [0, 0, 0],
+    dimensions: Optional[list] = [20, 20, 20],
+    spacing: Optional[float] = [1., 1., 1.],
+    scalar: Optional[float] = 20.,
+    data: Optional[np.ndarray] = None
+):
+    &#34;&#34;&#34;
+    Function to create a 3D vtkimage from a numpy array
+    OR to create a uniform image (all same value)
+
+    Parameters
+    ----------
+    origin : Optional[int], optional
+        X/Y/Z origin of the image, by default [0, 0, 0]
+    dimensions : Optional[list], optional
+        Size of the image along each dimension, by default [20, 20, 20]
+    spacing : Optional[float], optional
+        Image spacing along each dimension, by default [1., 1., 1.]
+    scalar : Optional[float], optional
+        Scalar value to use for a uniform image, by default 20.
+    data : Optional[np.ndarray], optional
+        Data for a non-uniform image, by default None
+    &#34;&#34;&#34;    
+    
+    if data is None:
+        data = np.ones(dimensions) * scalar
+    else:
+        if len(data.shape) == 3:
+            dimensions = data.shape
+        else:
+            dimensions = [1, 1, 1]
+            for idx, dim_size in enumerate(data.shape):
+                dimensions[idx] = dim_size
+    vtk_array = numpy_to_vtk(data.flatten(order=&#39;F&#39;))
+    vtk_array.SetName(&#39;test&#39;)
+
+    # points = vtk.vtkDoubleArray()
+    # points.SetName(&#39;test&#39;)
+    # points.SetNumberOfComponents(1)
+    # points.SetNumberOfTuples(np.product(dimensions))
+    # for x in range(dimensions[0]):
+    #   for y in range(dimensions[1]):
+    #      for z in range(dimensions[2]):
+    #         points.SetValue(
+    #            (z * dimensions[0] * dimensions[1]) + (x * dimensions[1]) + y,
+    #            array[x, y, z]
+    #         )
+
+    vtk_image = vtk.vtkImageData()
+    vtk_image.SetOrigin(*origin)
+    vtk_image.SetDimensions(*dimensions)
+    vtk_image.SetSpacing(*spacing)
+    vtk_image.GetPointData().SetScalars(vtk_array)            
+
+# 
+    return vtk_image</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-functions">Functions</h2>
+<dl>
+<dt id="pymskt.image.main.apply_transform_retain_array"><code class="name flex">
+<span>def <span class="ident">apply_transform_retain_array</span></span>(<span>image, transform, interpolator=1)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>This function will move the actual image in space but keep the underlying array the same.
+So, in x/y/z land the pixels are in a new location, but the actual underlying data array
+is the same. </p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
+<dd>Image to be transformed.</dd>
+<dt><strong><code>transform</code></strong> :&ensp;<code>SimpleITK.Transform</code></dt>
+<dd>Transform to apply</dd>
+<dt><strong><code>interpolator</code></strong> :&ensp;<code>SimpleITK.Interpolator</code>, optional</dt>
+<dd>Interpolator type to use, by default sitk.sitkNearestNeighbor</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>SimpleITK.Image</code></dt>
+<dd>New image after applying the appropriate transform.</dd>
+</dl>
+<h2 id="notes">Notes</h2>
+<p>I have a feeling that this is overkill.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def apply_transform_retain_array(image, transform, interpolator=sitk.sitkNearestNeighbor):
+    &#34;&#34;&#34;
+    This function will move the actual image in space but keep the underlying array the same. 
+    So, in x/y/z land the pixels are in a new location, but the actual underlying data array 
+    is the same. 
+
+    Parameters
+    ----------
+    image : SimpleITK.Image
+        Image to be transformed.
+    transform : SimpleITK.Transform
+        Transform to apply
+    interpolator : SimpleITK.Interpolator, optional
+        Interpolator type to use, by default sitk.sitkNearestNeighbor
+
+    Returns
+    -------
+    SimpleITK.Image
+        New image after applying the appropriate transform.
+    
+    Notes
+    -----
+    I have a feeling that this is overkill.
+    &#34;&#34;&#34;    
+
+    inverse_transform = transform.GetInverse()
+    new_origin = inverse_transform.TransformPoint(image.GetOrigin())
+
+    new_x = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((image.GetSize()[0], 0, 0)))
+    new_y = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, image.GetSize()[1], 0)))
+    new_z = inverse_transform.TransformPoint(image.TransformIndexToPhysicalPoint((0, 0, image.GetSize()[2])))
+
+    # Create x-axis vector
+    new_x_vector = np.asarray(new_x) - np.asarray(new_origin)
+    new_x_vector /= np.sqrt(np.sum(np.square(new_x_vector)))
+    # Create y-axis vector
+    new_y_vector = np.asarray(new_y) - np.asarray(new_origin)
+    new_y_vector /= np.sqrt(np.sum(np.square(new_y_vector)))
+    # Create z-axis vector
+    new_z_vector = np.asarray(new_z) - np.asarray(new_origin)
+    new_z_vector /= np.sqrt(np.sum(np.square(new_z_vector)))
+    # New image size (shape)
+    new_size = image.GetSize()
+    # New image spacing 
+    new_spacing = image.GetSpacing()
+    # Create 3x3 transformation matrix from the x/y/z unit vectors. 
+    new_three_by_three = np.zeros((3,3))
+    new_three_by_three[:,0] = new_x_vector
+    new_three_by_three[:,1] = new_y_vector
+    new_three_by_three[:,2] = new_z_vector
+
+    new_image = sitk.Resample(image, 
+                              new_size,
+                              transform,
+                              interpolator,
+                              new_origin, 
+                              new_spacing,
+                              new_three_by_three.flatten().tolist())
+    return new_image</code></pre>
+</details>
+</dd>
+<dt id="pymskt.image.main.binarize_segmentation_image"><code class="name flex">
+<span>def <span class="ident">binarize_segmentation_image</span></span>(<span>seg_image, label_idx)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>Return segmentation that is only 0s/1s, with 1s where label_idx is
+located in the image. </p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>seg_image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
+<dd>Segmentation image that contains data we want to binarize</dd>
+<dt><strong><code>label_idx</code></strong> :&ensp;<code>int</code></dt>
+<dd>Integer/label that we want to extract (binarize) from the
+<code>seg_image</code>.</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>SimpleITK.Image</code></dt>
+<dd>New segmentation image that is binarized.</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def binarize_segmentation_image(seg_image, label_idx):
+    &#34;&#34;&#34;
+    Return segmentation that is only 0s/1s, with 1s where label_idx is
+    located in the image. 
+
+    Parameters
+    ----------
+    seg_image : SimpleITK.Image
+        Segmentation image that contains data we want to binarize
+    label_idx : int
+        Integer/label that we want to extract (binarize) from the
+        `seg_image`.
+
+    Returns
+    -------
+    SimpleITK.Image
+        New segmentation image that is binarized. 
+    &#34;&#34;&#34;    
+    array = sitk.GetArrayFromImage(seg_image)
+    array_ = np.zeros_like(array)
+    array_[array == label_idx] = 1
+    new_seg_image = sitk.GetImageFromArray(array_)
+    new_seg_image.CopyInformation(seg_image)
+    return new_seg_image</code></pre>
+</details>
+</dd>
+<dt id="pymskt.image.main.create_vtk_image"><code class="name flex">
+<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>
+</code></dt>
+<dd>
+<div class="desc"><p>Function to create a 3D vtkimage from a numpy array
+OR to create a uniform image (all same value)</p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>origin</code></strong> :&ensp;<code>Optional[int]</code>, optional</dt>
+<dd>X/Y/Z origin of the image, by default [0, 0, 0]</dd>
+<dt><strong><code>dimensions</code></strong> :&ensp;<code>Optional[list]</code>, optional</dt>
+<dd>Size of the image along each dimension, by default [20, 20, 20]</dd>
+<dt><strong><code>spacing</code></strong> :&ensp;<code>Optional[float]</code>, optional</dt>
+<dd>Image spacing along each dimension, by default [1., 1., 1.]</dd>
+<dt><strong><code>scalar</code></strong> :&ensp;<code>Optional[float]</code>, optional</dt>
+<dd>Scalar value to use for a uniform image, by default 20.</dd>
+<dt><strong><code>data</code></strong> :&ensp;<code>Optional[np.ndarray]</code>, optional</dt>
+<dd>Data for a non-uniform image, by default None</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def create_vtk_image(
+    origin: Optional[int] = [0, 0, 0],
+    dimensions: Optional[list] = [20, 20, 20],
+    spacing: Optional[float] = [1., 1., 1.],
+    scalar: Optional[float] = 20.,
+    data: Optional[np.ndarray] = None
+):
+    &#34;&#34;&#34;
+    Function to create a 3D vtkimage from a numpy array
+    OR to create a uniform image (all same value)
+
+    Parameters
+    ----------
+    origin : Optional[int], optional
+        X/Y/Z origin of the image, by default [0, 0, 0]
+    dimensions : Optional[list], optional
+        Size of the image along each dimension, by default [20, 20, 20]
+    spacing : Optional[float], optional
+        Image spacing along each dimension, by default [1., 1., 1.]
+    scalar : Optional[float], optional
+        Scalar value to use for a uniform image, by default 20.
+    data : Optional[np.ndarray], optional
+        Data for a non-uniform image, by default None
+    &#34;&#34;&#34;    
+    
+    if data is None:
+        data = np.ones(dimensions) * scalar
+    else:
+        if len(data.shape) == 3:
+            dimensions = data.shape
+        else:
+            dimensions = [1, 1, 1]
+            for idx, dim_size in enumerate(data.shape):
+                dimensions[idx] = dim_size
+    vtk_array = numpy_to_vtk(data.flatten(order=&#39;F&#39;))
+    vtk_array.SetName(&#39;test&#39;)
+
+    # points = vtk.vtkDoubleArray()
+    # points.SetName(&#39;test&#39;)
+    # points.SetNumberOfComponents(1)
+    # points.SetNumberOfTuples(np.product(dimensions))
+    # for x in range(dimensions[0]):
+    #   for y in range(dimensions[1]):
+    #      for z in range(dimensions[2]):
+    #         points.SetValue(
+    #            (z * dimensions[0] * dimensions[1]) + (x * dimensions[1]) + y,
+    #            array[x, y, z]
+    #         )
+
+    vtk_image = vtk.vtkImageData()
+    vtk_image.SetOrigin(*origin)
+    vtk_image.SetDimensions(*dimensions)
+    vtk_image.SetSpacing(*spacing)
+    vtk_image.GetPointData().SetScalars(vtk_array)            
+
+# 
+    return vtk_image</code></pre>
+</details>
+</dd>
+<dt id="pymskt.image.main.crop_bone_based_on_width"><code class="name flex">
+<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>
+</code></dt>
+<dd>
+<div class="desc"><p>Crop the bone labelmap of a SimpleITK.Image so that it is proportional to the
+bones medial/lateral width. </p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>seg_image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
+<dd>Image to be cropped.</dd>
+<dt><strong><code>bone_idx</code></strong> :&ensp;<code>int</code></dt>
+<dd>Label_index of the bone to be cropped.</dd>
+<dt><strong><code>np_med_lat_axis</code></strong> :&ensp;<code>int</code>, optional</dt>
+<dd>Medial/lateral axis, by default 0</dd>
+<dt><strong><code>np_inf_sup_axis</code></strong> :&ensp;<code>int</code>, optional</dt>
+<dd>Inferior/superir axis, by default 1</dd>
+<dt><strong><code>bone_crop_distal</code></strong> :&ensp;<code>bool</code>, optional</dt>
+<dd>Boolean of cropping should occur distal or proximally, by default True</dd>
+<dt><strong><code>value_to_reassign</code></strong> :&ensp;<code>int</code>, optional</dt>
+<dd>Value to replace bone label with, by default 0</dd>
+<dt><strong><code>percent_width_to_crop_height</code></strong> :&ensp;<code>float</code>, optional</dt>
+<dd>Bone length as a proportion of width, by default 1.0</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>SimpleITK.Image</code></dt>
+<dd>Image after bone is cropped as a proportion of the bone's width.</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def crop_bone_based_on_width(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):
+    &#34;&#34;&#34;
+    Crop the bone labelmap of a SimpleITK.Image so that it is proportional to the
+    bones medial/lateral width. 
+
+    Parameters
+    ----------
+    seg_image : SimpleITK.Image
+        Image to be cropped. 
+    bone_idx : int
+        Label_index of the bone to be cropped. 
+    np_med_lat_axis : int, optional
+        Medial/lateral axis, by default 0
+    np_inf_sup_axis : int, optional
+        Inferior/superir axis, by default 1
+    bone_crop_distal : bool, optional
+        Boolean of cropping should occur distal or proximally, by default True
+    value_to_reassign : int, optional
+        Value to replace bone label with, by default 0
+    percent_width_to_crop_height : float, optional
+        Bone length as a proportion of width, by default 1.0
+
+    Returns
+    -------
+    SimpleITK.Image
+        Image after bone is cropped as a proportion of the bone&#39;s width. 
+    &#34;&#34;&#34;    
+    seg_array = sitk.GetArrayFromImage(seg_image)
+    loc_bone = np.where(seg_array == bone_idx)
+    med_lat_width_bone_mm = (np.max(loc_bone[np_med_lat_axis]) - np.min(loc_bone[np_med_lat_axis])) * \
+                            seg_image.GetSpacing()[::-1][np_med_lat_axis]
+    inf_sup_crop_in_pixels = (med_lat_width_bone_mm / seg_image.GetSpacing()[::-1][
+        np_inf_sup_axis]) * percent_width_to_crop_height
+    if bone_crop_distal is True:
+        bone_distal_idx = np.max(loc_bone[np_inf_sup_axis])
+        bone_proximal_idx = bone_distal_idx - inf_sup_crop_in_pixels
+        if bone_proximal_idx &lt; 1:
+            bone_proximal_idx = 1
+
+    elif bone_crop_distal is False:
+        bone_proximal_idx = np.min(loc_bone[np_inf_sup_axis])
+        bone_distal_idx = bone_proximal_idx + inf_sup_crop_in_pixels
+        if bone_distal_idx &gt; seg_array.shape[np_inf_sup_axis]:
+            bone_distal_idx = seg_array.shape[np_inf_sup_axis] - 1
+
+    max_inf_sup_idx = max(bone_distal_idx, bone_proximal_idx)
+    min_inf_sup_idx = min(bone_distal_idx, bone_proximal_idx)
+
+    idx_bone_to_keep = np.where(
+        (loc_bone[np_inf_sup_axis] &gt; min_inf_sup_idx) &amp; (loc_bone[np_inf_sup_axis] &lt; max_inf_sup_idx))
+    loc_bone_to_remove = tuple([np.delete(x, idx_bone_to_keep) for x in loc_bone])
+
+    seg_array[loc_bone_to_remove] = value_to_reassign
+
+    new_seg_image = sitk.GetImageFromArray(seg_array)
+    new_seg_image.CopyInformation(seg_image)
+
+    return new_seg_image</code></pre>
+</details>
+</dd>
+<dt id="pymskt.image.main.read_nrrd"><code class="name flex">
+<span>def <span class="ident">read_nrrd</span></span>(<span>path, set_origin_zero=False)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>Read NRRD image file into vtk. Enables usage of marching cubes
+and other functions that work on image data.</p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>path</code></strong> :&ensp;<code>str</code></dt>
+<dd>Path to <code>.nrrd</code> medical image to read in.</dd>
+<dt><strong><code>set_origin_zero</code></strong> :&ensp;<code>bool</code>, optional</dt>
+<dd>Bool to determine if origin should be set to zeros, by default False</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>vtk.Filter</code></dt>
+<dd>End of VTK filter pipeline.</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_nrrd(path, set_origin_zero=False):
+    &#34;&#34;&#34;
+    Read NRRD image file into vtk. Enables usage of marching cubes
+    and other functions that work on image data.
+
+    Parameters
+    ----------
+    path : str
+        Path to `.nrrd` medical image to read in. 
+    set_origin_zero : bool, optional
+        Bool to determine if origin should be set to zeros, by default False
+
+    Returns
+    -------
+    vtk.Filter
+        End of VTK filter pipeline. 
+    &#34;&#34;&#34;    
+
+    image_reader = vtk.vtkNrrdReader()
+    image_reader.SetFileName(path)
+    image_reader.Update()
+    if set_origin_zero is True:
+        change_origin = set_vtk_image_origin(image_reader, new_origin=(0, 0, 0))
+        return change_origin
+    elif set_origin_zero is False:
+        return image_reader</code></pre>
+</details>
+</dd>
+<dt id="pymskt.image.main.set_seg_border_to_zeros"><code class="name flex">
+<span>def <span class="ident">set_seg_border_to_zeros</span></span>(<span>seg_image, border_size=1)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>Utility function to ensure that all segmentations are "closed" after marching cubes.
+If the segmentation extends to the edges of the image then the surface wont be closed
+at the places it touches the edges. </p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>seg_image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
+<dd>Image of a segmentation.</dd>
+<dt><strong><code>border_size</code></strong> :&ensp;<code>int</code>, optional</dt>
+<dd>The size of the border to set around the edges of the 3D image, by default 1</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>SimpleITK.Image</code></dt>
+<dd>The image with border set to 0 (background).</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def set_seg_border_to_zeros(seg_image,
+                            border_size=1):
+    &#34;&#34;&#34;
+    Utility function to ensure that all segmentations are &#34;closed&#34; after marching cubes. 
+    If the segmentation extends to the edges of the image then the surface wont be closed 
+    at the places it touches the edges. 
+
+    Parameters
+    ----------
+    seg_image : SimpleITK.Image
+        Image of a segmentation. 
+    border_size : int, optional
+        The size of the border to set around the edges of the 3D image, by default 1
+
+    Returns
+    -------
+    SimpleITK.Image
+        The image with border set to 0 (background). 
+    &#34;&#34;&#34;    
+
+    seg_array = sitk.GetArrayFromImage(seg_image)
+    new_seg_array = np.zeros_like(seg_array)
+    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]
+    new_seg_image = sitk.GetImageFromArray(new_seg_array)
+    new_seg_image.CopyInformation(seg_image)
+    return new_seg_image</code></pre>
+</details>
+</dd>
+<dt id="pymskt.image.main.set_vtk_image_origin"><code class="name flex">
+<span>def <span class="ident">set_vtk_image_origin</span></span>(<span>vtk_image, new_origin=(0, 0, 0))</span>
+</code></dt>
+<dd>
+<div class="desc"><p>Reset the origin of a <code>vtk_image</code></p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>vtk_image</code></strong> :&ensp;<code>vtk.image</code></dt>
+<dd>VTK image that we want to change the origin of.</dd>
+<dt><strong><code>new_origin</code></strong> :&ensp;<code>tuple</code>, optional</dt>
+<dd>New origin to asign to <code>vtk_image</code>, by default (0, 0, 0)</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>vtk.Filter</code></dt>
+<dd>End of VTK filter pipeline after applying origin change.</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def set_vtk_image_origin(vtk_image, new_origin=(0, 0, 0)):
+    &#34;&#34;&#34;
+    Reset the origin of a `vtk_image`
+
+    Parameters
+    ----------
+    vtk_image : vtk.image
+        VTK image that we want to change the origin of. 
+    new_origin : tuple, optional
+        New origin to asign to `vtk_image`, by default (0, 0, 0)
+
+    Returns
+    -------
+    vtk.Filter
+        End of VTK filter pipeline after applying origin change. 
+    &#34;&#34;&#34;    
+
+    change_origin = vtk.vtkImageChangeInformation()
+    change_origin.SetInputConnection(vtk_image.GetOutputPort())
+    change_origin.SetOutputOrigin(new_origin)
+    change_origin.Update()
+    return change_origin</code></pre>
+</details>
+</dd>
+<dt id="pymskt.image.main.smooth_image"><code class="name flex">
+<span>def <span class="ident">smooth_image</span></span>(<span>image, label_idx, variance=1.0)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>Smooth a single label in a SimpleITK image. Used as pre-processing for
+bones/cartilage before applying marching cubes. Helps obtain smooth surfaces. </p>
+<h2 id="parameters">Parameters</h2>
+<dl>
+<dt><strong><code>image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
+<dd>Image to be smoothed.</dd>
+<dt><strong><code>label_idx</code></strong> :&ensp;<code>int</code></dt>
+<dd>Integer of the tissue of interest to be smoothed in the image.</dd>
+<dt><strong><code>variance</code></strong> :&ensp;<code>float</code>, optional</dt>
+<dd>The size of the smoothing, by default 1.0</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>SimpleITK.Image</code></dt>
+<dd>Image of only the label (tissue) of interest after being smoothed.</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def smooth_image(image, label_idx, variance=1.0):
+    &#34;&#34;&#34;
+    Smooth a single label in a SimpleITK image. Used as pre-processing for 
+    bones/cartilage before applying marching cubes. Helps obtain smooth surfaces. 
+
+    Parameters
+    ----------
+    image : SimpleITK.Image
+        Image to be smoothed. 
+    label_idx : int
+        Integer of the tissue of interest to be smoothed in the image. 
+    variance : float, optional
+        The size of the smoothing, by default 1.0
+
+    Returns
+    -------
+    SimpleITK.Image
+        Image of only the label (tissue) of interest after being smoothed. 
+    &#34;&#34;&#34;    
+    new_image = binarize_segmentation_image(image, label_idx)
+
+    new_image = sitk.Cast(new_image, sitk.sitkFloat32)
+
+    gauss_filter = sitk.DiscreteGaussianImageFilter()
+    gauss_filter.SetVariance(variance)
+    #     gauss_filter.SetUseImageSpacingOn
+    gauss_filter.SetUseImageSpacing(True)
+    filtered_new_image = gauss_filter.Execute(new_image)
+
+    return filtered_new_image</code></pre>
+</details>
+</dd>
+</dl>
+</section>
+<section>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="pymskt.image" href="index.html">pymskt.image</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-functions">Functions</a></h3>
+<ul class="">
+<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>
+<li><code><a title="pymskt.image.main.binarize_segmentation_image" href="#pymskt.image.main.binarize_segmentation_image">binarize_segmentation_image</a></code></li>
+<li><code><a title="pymskt.image.main.create_vtk_image" href="#pymskt.image.main.create_vtk_image">create_vtk_image</a></code></li>
+<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>
+<li><code><a title="pymskt.image.main.read_nrrd" href="#pymskt.image.main.read_nrrd">read_nrrd</a></code></li>
+<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>
+<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>
+<li><code><a title="pymskt.image.main.smooth_image" href="#pymskt.image.main.smooth_image">smooth_image</a></code></li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
\ No newline at end of file