Switch to unified view

a b/docs/image/cartilage_processing.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.cartilage_processing 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.cartilage_processing</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">import SimpleITK as sitk
30
import numpy as np
31
from scipy import ndimage as ndi
32
33
34
def CofM(array):
35
    &#39;&#39;&#39;
36
    Get center of mass for a row of a binary 2D image. 
37
    Parameters
38
    ----------
39
    array : 1D array
40
        Individual row of a 2D image.  
41
    Returns
42
    -------
43
    centerPixels : 
44
        Average location of 1s in the row
45
    Notes
46
    -----
47
    Calculates the average location of cartilage for the row of image being analyzed. 
48
    Returns 0 if there are no pixels
49
    
50
    &#39;&#39;&#39;
51
    pixels = np.where(array==1)
52
    centerPixels = np.mean(pixels)
53
    nans = np.isnan(centerPixels)
54
    if nans == True:
55
        centerPixels = 0
56
    return(centerPixels)
57
58
def get_y_CofM(flattenedSeg):
59
    &#39;&#39;&#39;
60
    Get CofM of femoral cartilage for each row of the flattened segmentation. 
61
    Parameters
62
    ----------
63
    flattenedSeg : 2D array
64
        Axial flattened, and filled in femoral cartilage segmentation.  
65
    Returns
66
    -------
67
    yCofM : 
68
        Find the CofM for each row of the image. 
69
    Notes
70
    -----
71
    Get the x/y coordinates for the CofM for each row of the flattened segmentation. 
72
    
73
    &#39;&#39;&#39;
74
    locationFemur = np.where(flattenedSeg==1)
75
    yCofM = np.zeros((flattenedSeg.shape[0], 2), dtype=int)
76
    
77
    # only calculate for rows with cartilage. 
78
    minRow = np.min(locationFemur[0])
79
    maxRow = np.max(locationFemur[0])
80
    
81
    # iterate over rows of image, get CofM, store CofM for row. 
82
    for x in range(minRow, maxRow):
83
        yCofM[x, 0] = x #store the x-coordinate (row) we calcualted CofM for. 
84
        yCofM[x, 1] = int(CofM(flattenedSeg[x, :])) # store the CofM value (make it an integer for indexing)
85
    yCofM = yCofM[minRow+10:maxRow-10,:] # remove 10 most medial and most lateral pixels of femoral cartilage. 
86
    return(yCofM) 
87
88
def absolute_CofM(flattenedSeg):
89
    &#39;&#39;&#39;
90
    Get absolute CofM of all the femoral cartilage pixels
91
    Parameters
92
    ----------
93
    flattenedSeg : 2D array
94
        Axial flattened, and filled in femoral cartilage segmentation.  
95
    Returns
96
    -------
97
    centerX : 
98
        The CofM in the X direction for the segmentation  
99
    centerY : 
100
        The CofM in the Y direction for the segmentation
101
    Notes
102
    -----
103
    Get the x/y coordinates for the CofM for the whole flattened segmentation
104
    
105
    &#39;&#39;&#39;
106
    femurPoints = np.where(flattenedSeg==1)
107
    centerX = np.mean(femurPoints[0])
108
    centerY = np.mean(femurPoints[1])
109
    return(centerX, centerY)
110
111
def findNotch(flattenedSeg, trochleaPositionX=1000):
112
    &#39;&#39;&#39;
113
    Get the X Y position of the trochlear notch - where medial/lateral sides of the femur meet. 
114
    Parameters
115
    ----------
116
    flattenedSeg : 2D array
117
        Axial flattened, and filled in femoral cartilage segmentation.  
118
    Returns
119
    -------
120
    trochleaPositionY : 
121
        Y position of trochlear notch  
122
    trochleaPositionX : 
123
        X position of trochlear notch
124
    Notes
125
    -----
126
    Get the x/y coordinates for the trochlear notch. This is an iterative method that assumes things about the shape the
127
    femoral cartilage.
128
    
129
    &#39;&#39;&#39;
130
    # Goal is to find the most anterior point that is between the medial/lateral condyles
131
132
    # First guess at the troch notch in the 1st axis (med/lat axis) is the location with the smallest value for
133
    # the 2nd axis CofM. This is because in axis 1, negative is anterior and we expect the most anterior CofM should 
134
    # roughly align with the trochlear notch.
135
    y_CofM = get_y_CofM(flattenedSeg)
136
    first_guess = y_CofM[np.argmin(y_CofM[:,1]), 0]
137
    # the second guess is just the CofM of the whole cartilage. 
138
    centerX, centerY = absolute_CofM(flattenedSeg)
139
    second_guess = centerX
140
141
    # We use the 2 guesses to help define a search space for the trochlear notch.
142
    min_search = int(np.min((first_guess,second_guess))-20)
143
    max_search = int(np.max((first_guess,second_guess))+20)
144
145
    # now, we iterate over all of the rows (axis 1) of the search space (moving in the medial/lateral direction)
146
    # we are looking for the row where the most posterior point (back of femur) is furthest anterior (notch). 
147
    for y in range(min_search, max_search):
148
        # At each row, we find most posterior pixel labeled as cartilage. 
149
        try:
150
            trochleaPosition_test = np.max(np.where(flattenedSeg[y,:]==1))
151
        except ValueError:
152
            # if there is no cartilage we&#39;ll get a ValueError exception. 
153
            # in that case, set this value to be the max it can be (the size of the first axis)
154
            trochleaPosition_test = flattenedSeg.shape[1]
155
        # if the most posterior point for this row is more anterior than the current trochleaPositionX,
156
        # then update this to be the new trochlear notch.
157
        if trochleaPosition_test &lt; trochleaPositionX:
158
            trochleaPositionX = trochleaPosition_test
159
            trochleaPositionY = y
160
161
    return(trochleaPositionY, trochleaPositionX+1)
162
163
def getAnteriorOfWeightBearing(segArray, femurIndex=1):
164
    &#39;&#39;&#39;
165
    Prepare full segmentation and extract the trochlear notch location. 
166
    Parameters
167
    ----------
168
    flattenedSeg : 2D array
169
        Axial flattened, and filled in femoral cartilage segmentation.  
170
    femurIndex : int
171
        Index of the label used to localize the femur in the array. 
172
    Returns
173
    -------
174
    trochleaPositionY : 
175
        Y position of trochlear notch  
176
    trochleaPositionX : 
177
        X position of trochlear notch
178
    Notes
179
    -----
180
    Get the x/y coordinates for the trochlear notch. This is an iterative method that assumes things about the shape the femoral cartilage. 
181
    First flatten and fill any holes in the segmentation. 
182
    
183
    &#39;&#39;&#39;
184
185
    femurSegmentation = np.zeros_like(segArray)
186
    femurSegmentation[segArray == femurIndex] = 1
187
    flattenedSegmentation = np.amax(femurSegmentation, axis=1)
188
    flattened_seg_filled = ndi.binary_fill_holes(flattenedSegmentation)
189
    trochY, trochX = findNotch(flattened_seg_filled)
190
    return(trochY, trochX)
191
    
192
def getCartilageSubRegions(segArray, anteriorWBslice, posteriorWBslice, trochY,
193
                           femurLabel=1, medTibiaLabel=2, latTibiaLabel=3, antFemurMask=5, 
194
                           medWbFemurMask=6, latWbFemurMask=7, medPostFemurMask=8, latPostFemurMask=9):
195
    &#39;&#39;&#39;
196
    Take cartilage segmentation, and decompose femoral cartilage into subregions of interest.  
197
    Parameters
198
    ----------
199
    segArray : array
200
        3D array with segmentation for the cartialge regions. 
201
    anteriorWBslice : int
202
        Slice that seperates the anterior and weight bearing femoral cartilage.  
203
    posteriorWBslice : int
204
        Slice that seperates the weight bearing and posterior femoral cartilage. 
205
    trochY : int
206
        Slice that differentiates medial / lateral femur - trochlear notch Y component. 
207
    femurLabel : int
208
        Label that femur is in the segArray
209
    medTibiaLabel : int
210
        Label that medial tibia is in the segArray
211
    latTibiaLabel : int
212
        Label that lateral tibia is in the segArray
213
    antFemurMask : int
214
        Label anterior femur should be labeled in final segmentation. 
215
    medWbFemurMask : int
216
        Label medial weight bearing femur should be labeled in final segmentation.
217
    latWbFemurMask : int
218
        Label lateral weight bearing femur should be labeled in final segmentation. 
219
    medPostFemurMask : int
220
        Label medial posterior femur should be labeled in final segmentation. 
221
    latPostFemurMask : int
222
        Label lateral posterior femur should be labeled in final segmentation.
223
    Returns
224
    -------
225
    final_segmentation : array
226
        3D array with the updated segmentations - including weightbearing, medial/latera, anterior, and posterior. 
227
    Notes
228
    -----
229
    
230
    &#39;&#39;&#39;
231
    
232
    #array to store final segmentation
233
    final_segmentation = np.zeros_like(segArray)
234
    
235
    #create masks for ant/wb/posterior femur
236
    anterior_femur_mask = np.zeros_like(segArray)
237
    anterior_femur_mask[:,:,:anteriorWBslice] = 1
238
239
    wb_femur_mask = np.zeros_like(segArray)
240
    wb_femur_mask[:,:,anteriorWBslice:posteriorWBslice] = 1
241
242
    posterior_femur_mask = np.zeros_like(segArray)
243
    posterior_femur_mask[:,:,posteriorWBslice:] = 1
244
    
245
    #create seg of just femur - and then break it into the sub-regions
246
    femurSegArray = np.zeros_like(segArray)
247
    femurSegArray[segArray==femurLabel] = 1
248
    
249
    #find the center of the medial/lateral tibia - use to distinguish M/L femur ROIs
250
    locationMedialTibia = np.asarray(np.where(segArray==medTibiaLabel))
251
    locationLateralTibia = np.asarray(np.where(segArray==latTibiaLabel))
252
    
253
    centerMedialTibia = locationMedialTibia.mean(axis=1)
254
    centerLateralTibia = locationLateralTibia.mean(axis=1)
255
256
    med_femur_mask = np.zeros_like(segArray)
257
    lat_femur_mask = np.zeros_like(segArray)
258
    if centerMedialTibia[0] &gt; trochY:
259
        med_femur_mask[trochY:,:,:] = 1
260
        lat_femur_mask[:trochY,:,:] = 1
261
    else:
262
        med_femur_mask[:trochY,:,:] = 1
263
        lat_femur_mask[trochY:,:,:] = 1
264
265
    final_segmentation[segArray!=femurLabel] = segArray[segArray!=femurLabel] 
266
    final_segmentation += (femurSegArray * anterior_femur_mask) * antFemurMask
267
    final_segmentation += (femurSegArray * wb_femur_mask * med_femur_mask) * medWbFemurMask
268
    final_segmentation += (femurSegArray * wb_femur_mask * lat_femur_mask) * latWbFemurMask
269
    final_segmentation += (femurSegArray * posterior_femur_mask * med_femur_mask) * medPostFemurMask
270
    final_segmentation += (femurSegArray * posterior_femur_mask * lat_femur_mask) * latPostFemurMask
271
    
272
    return(final_segmentation)
273
274
def verify_and_correct_med_lat_tib_cart(
275
    seg_array,  #sitk.GetArrayViewFromImage(seg)
276
    tib_label=6,
277
    med_tib_cart_label=2, 
278
    lat_tib_cart_label=3,
279
    ml_axis=0
280
):
281
    &#39;&#39;&#39;
282
    Verify that the medial and lateral tibial cartilage are correctly labeled.
283
    Parameters
284
    ----------
285
    seg_array : array
286
        3D array with segmentation for the cartilage/bone regions.
287
    tib_label : int
288
        Label that tibial cartilage is in the seg_array
289
    med_tib_cart_label : int
290
        Label that medial tibial cartilage is in the seg_array
291
    lat_tib_cart_label : int
292
        Label that lateral tibial cartilage is in the seg_array
293
    ml_axis : int
294
        Medial/lateral axis of the acquired knee MRI.
295
    
296
    Returns
297
    -------
298
    seg_array : array
299
        3D array with segmentation for the cartilage/bone regions.
300
        The tibial cartilage regions will have been updated to ensure
301
        all tib cart on med/lat sides are correctly classified.
302
        
303
    &#39;&#39;&#39;
304
    #get binary array for tibia
305
    array_tib = np.zeros_like(seg_array)
306
    array_tib[seg_array == tib_label] = 1
307
    #get binary array for tib cart
308
    array_tib_cart = np.zeros_like(seg_array)
309
    array_tib_cart[(seg_array == lat_tib_cart_label) + (seg_array == med_tib_cart_label)] = 1
310
311
    #get the locatons of med/lat cartilage &amp; get their centroids
312
    med_cart_locs = np.asarray(np.where(seg_array == med_tib_cart_label))
313
    lat_cart_locs = np.asarray(np.where(seg_array == lat_tib_cart_label))
314
    middle_med_cart = med_cart_locs[ml_axis,:].mean()
315
    middle_lat_cart = lat_cart_locs[ml_axis,:].mean()
316
317
    #get location of tibia to get centroid of tibial plateau
318
    tib_locs = np.asarray(np.where(seg_array == tib_label))
319
    middle_tib = tib_locs[ml_axis, :].mean()
320
    center_tibia_slice = int(middle_tib)
321
322
    # infer the direction(s) for medial/lateral
323
    med_direction = np.sign(middle_med_cart - middle_tib)
324
    lat_direction = np.sign(middle_lat_cart - middle_tib)
325
    if med_direction == lat_direction:
326
        raise Exception(&#39;Middle of med and lat tibial cartilage on same side of centerline!&#39;)
327
328
    #create med/lat cartilage masks - binary for updating seg masks
329
    med_tib_cart_mask = np.zeros_like(seg_array)
330
    lat_tib_cart_mask = np.zeros_like(seg_array)
331
332
    if med_direction &gt; 0:
333
        med_tib_cart_mask[center_tibia_slice:,...] = 1
334
        lat_tib_cart_mask[:center_tibia_slice,...] = 1
335
    elif med_direction &lt; 0:
336
        med_tib_cart_mask[:center_tibia_slice,...] = 1
337
        lat_tib_cart_mask[center_tibia_slice:,...] = 1
338
339
    # create new med/lat cartilage arrays 
340
    new_med_cart_array = array_tib_cart * med_tib_cart_mask
341
    new_lat_cart_array = array_tib_cart * lat_tib_cart_mask
342
343
    #make copy of original segmentation array &amp; update
344
    # med/lat tibial cartilage labels
345
    new_seg_array = seg_array.copy()
346
    new_seg_array[new_med_cart_array == 1] = med_tib_cart_label
347
    new_seg_array[new_lat_cart_array == 1] = lat_tib_cart_label
348
    
349
    return new_seg_array
350
351
def get_knee_segmentation_with_femur_subregions(seg_image,
352
                                                fem_cart_label_idx=1,
353
                                                wb_region_percent_dist=0.6,
354
                                                # femur_label=1,
355
                                                med_tibia_label=2,
356
                                                lat_tibia_label=3,
357
                                                ant_femur_mask=11,
358
                                                med_wb_femur_mask=12,
359
                                                lat_wb_femur_mask=13,
360
                                                med_post_femur_mask=14,
361
                                                lat_post_femur_mask=15,
362
                                                verify_med_lat_tib_cart=True,
363
                                                tibia_label=6,
364
                                                ml_axis=0
365
                                                ):
366
    &#34;&#34;&#34;
367
    Give seg image of knee. Return seg image with all sub-regions of femur included. 
368
369
    Parameters
370
    ----------
371
    seg_image : SimpleITK.Image
372
        SimpleITK image of the segmentation to be processed. 
373
    fem_cart_label_idx : int, optional
374
        Label of femoral cartilage, by default 1
375
    wb_region_percent_dist : float, optional
376
        How large weightbearing region is (from not to posterior of condyles), by default 0.6
377
    femur_label : int, optional
378
        Seg label for the femur cartilage, by default 1
379
    med_tibia_label : int, optional
380
        Seg label for the medial tibia cartilage, by default 2
381
    lat_tibia_label : int, optional
382
        Seg label for the lateral tibia cartilage, by default 3
383
    ant_femur_mask : int, optional
384
        Seg label for the anterior femur region, by default 11
385
    med_wb_femur_mask : int, optional
386
        Seg label for medial weight-bearing femur, by default 12
387
    lat_wb_femur_mask : int, optional
388
        Seg label for lateral weight-bearing femur, by default 13
389
    med_post_femur_mask : int, optional
390
        Seg label for medial posterior femur, by default 14
391
    lat_post_femur_mask : int, optional
392
        Seg label for lateral posterior femur, by default 15
393
    verify_med_lat_tib_cart : bool, optional
394
        Whether to verify that medial and lateral tibial cartilage is on same side of centerline, by default True
395
    tibia_label : int, optional
396
        Seg label for the tibia, by default 6
397
    ml_axis : int, optional
398
        Medial/lateral axis of the acquired knee MRI, by default 0
399
400
    Returns
401
    -------
402
    SimpleITK.Image
403
        Image of the new/updated segmentation
404
    &#34;&#34;&#34;
405
    troch_notch_y, troch_notch_x = getAnteriorOfWeightBearing(sitk.GetArrayViewFromImage(seg_image),
406
                                                              femurIndex=fem_cart_label_idx)
407
    loc_fem_z, loc_fem_y, loc_fem_x = np.where(sitk.GetArrayViewFromImage(seg_image) == fem_cart_label_idx)
408
    post_femur_slice = np.max(loc_fem_x)
409
    posterior_wb_slice = np.round((post_femur_slice - troch_notch_x) * wb_region_percent_dist + troch_notch_x).astype(int)
410
    new_seg_array = getCartilageSubRegions(sitk.GetArrayViewFromImage(seg_image),
411
                                           anteriorWBslice=troch_notch_x,
412
                                           posteriorWBslice=posterior_wb_slice,
413
                                           trochY=troch_notch_y,
414
                                           femurLabel=fem_cart_label_idx,
415
                                           medTibiaLabel=med_tibia_label,
416
                                           latTibiaLabel=lat_tibia_label,
417
                                           antFemurMask=ant_femur_mask,
418
                                           medWbFemurMask=med_wb_femur_mask,
419
                                           latWbFemurMask=lat_wb_femur_mask,
420
                                           medPostFemurMask=med_post_femur_mask,
421
                                           latPostFemurMask=lat_post_femur_mask
422
                                           )
423
424
    if verify_med_lat_tib_cart:
425
        new_seg_array = verify_and_correct_med_lat_tib_cart(new_seg_array,
426
                                                            tib_label=tibia_label,
427
                                                            med_tib_cart_label=med_tibia_label, 
428
                                                            lat_tib_cart_label=lat_tibia_label,
429
                                                            ml_axis=ml_axis) 
430
    seg_label_image = sitk.GetImageFromArray(new_seg_array)
431
    seg_label_image.CopyInformation(seg_image)
432
    return seg_label_image</code></pre>
433
</details>
434
</section>
435
<section>
436
</section>
437
<section>
438
</section>
439
<section>
440
<h2 class="section-title" id="header-functions">Functions</h2>
441
<dl>
442
<dt id="pymskt.image.cartilage_processing.CofM"><code class="name flex">
443
<span>def <span class="ident">CofM</span></span>(<span>array)</span>
444
</code></dt>
445
<dd>
446
<div class="desc"><p>Get center of mass for a row of a binary 2D image.
447
Parameters</p>
448
<hr>
449
<dl>
450
<dt><strong><code>array</code></strong> :&ensp;<code>1D array</code></dt>
451
<dd>Individual row of a 2D image.</dd>
452
</dl>
453
<h2 id="returns">Returns</h2>
454
<dl>
455
<dt><strong><code>centerPixels</code></strong></dt>
456
<dd>Average location of 1s in the row</dd>
457
</dl>
458
<h2 id="notes">Notes</h2>
459
<p>Calculates the average location of cartilage for the row of image being analyzed.
460
Returns 0 if there are no pixels</p></div>
461
<details class="source">
462
<summary>
463
<span>Expand source code</span>
464
</summary>
465
<pre><code class="python">def CofM(array):
466
    &#39;&#39;&#39;
467
    Get center of mass for a row of a binary 2D image. 
468
    Parameters
469
    ----------
470
    array : 1D array
471
        Individual row of a 2D image.  
472
    Returns
473
    -------
474
    centerPixels : 
475
        Average location of 1s in the row
476
    Notes
477
    -----
478
    Calculates the average location of cartilage for the row of image being analyzed. 
479
    Returns 0 if there are no pixels
480
    
481
    &#39;&#39;&#39;
482
    pixels = np.where(array==1)
483
    centerPixels = np.mean(pixels)
484
    nans = np.isnan(centerPixels)
485
    if nans == True:
486
        centerPixels = 0
487
    return(centerPixels)</code></pre>
488
</details>
489
</dd>
490
<dt id="pymskt.image.cartilage_processing.absolute_CofM"><code class="name flex">
491
<span>def <span class="ident">absolute_CofM</span></span>(<span>flattenedSeg)</span>
492
</code></dt>
493
<dd>
494
<div class="desc"><p>Get absolute CofM of all the femoral cartilage pixels
495
Parameters</p>
496
<hr>
497
<dl>
498
<dt><strong><code>flattenedSeg</code></strong> :&ensp;<code>2D array</code></dt>
499
<dd>Axial flattened, and filled in femoral cartilage segmentation.</dd>
500
</dl>
501
<h2 id="returns">Returns</h2>
502
<dl>
503
<dt><strong><code>centerX</code></strong></dt>
504
<dd>The CofM in the X direction for the segmentation</dd>
505
<dt><strong><code>centerY</code></strong></dt>
506
<dd>The CofM in the Y direction for the segmentation</dd>
507
</dl>
508
<h2 id="notes">Notes</h2>
509
<p>Get the x/y coordinates for the CofM for the whole flattened segmentation</p></div>
510
<details class="source">
511
<summary>
512
<span>Expand source code</span>
513
</summary>
514
<pre><code class="python">def absolute_CofM(flattenedSeg):
515
    &#39;&#39;&#39;
516
    Get absolute CofM of all the femoral cartilage pixels
517
    Parameters
518
    ----------
519
    flattenedSeg : 2D array
520
        Axial flattened, and filled in femoral cartilage segmentation.  
521
    Returns
522
    -------
523
    centerX : 
524
        The CofM in the X direction for the segmentation  
525
    centerY : 
526
        The CofM in the Y direction for the segmentation
527
    Notes
528
    -----
529
    Get the x/y coordinates for the CofM for the whole flattened segmentation
530
    
531
    &#39;&#39;&#39;
532
    femurPoints = np.where(flattenedSeg==1)
533
    centerX = np.mean(femurPoints[0])
534
    centerY = np.mean(femurPoints[1])
535
    return(centerX, centerY)</code></pre>
536
</details>
537
</dd>
538
<dt id="pymskt.image.cartilage_processing.findNotch"><code class="name flex">
539
<span>def <span class="ident">findNotch</span></span>(<span>flattenedSeg, trochleaPositionX=1000)</span>
540
</code></dt>
541
<dd>
542
<div class="desc"><p>Get the X Y position of the trochlear notch - where medial/lateral sides of the femur meet.
543
Parameters</p>
544
<hr>
545
<dl>
546
<dt><strong><code>flattenedSeg</code></strong> :&ensp;<code>2D array</code></dt>
547
<dd>Axial flattened, and filled in femoral cartilage segmentation.</dd>
548
</dl>
549
<h2 id="returns">Returns</h2>
550
<dl>
551
<dt><strong><code>trochleaPositionY</code></strong></dt>
552
<dd>Y position of trochlear notch</dd>
553
<dt><strong><code>trochleaPositionX</code></strong></dt>
554
<dd>X position of trochlear notch</dd>
555
</dl>
556
<h2 id="notes">Notes</h2>
557
<p>Get the x/y coordinates for the trochlear notch. This is an iterative method that assumes things about the shape the
558
femoral cartilage.</p></div>
559
<details class="source">
560
<summary>
561
<span>Expand source code</span>
562
</summary>
563
<pre><code class="python">def findNotch(flattenedSeg, trochleaPositionX=1000):
564
    &#39;&#39;&#39;
565
    Get the X Y position of the trochlear notch - where medial/lateral sides of the femur meet. 
566
    Parameters
567
    ----------
568
    flattenedSeg : 2D array
569
        Axial flattened, and filled in femoral cartilage segmentation.  
570
    Returns
571
    -------
572
    trochleaPositionY : 
573
        Y position of trochlear notch  
574
    trochleaPositionX : 
575
        X position of trochlear notch
576
    Notes
577
    -----
578
    Get the x/y coordinates for the trochlear notch. This is an iterative method that assumes things about the shape the
579
    femoral cartilage.
580
    
581
    &#39;&#39;&#39;
582
    # Goal is to find the most anterior point that is between the medial/lateral condyles
583
584
    # First guess at the troch notch in the 1st axis (med/lat axis) is the location with the smallest value for
585
    # the 2nd axis CofM. This is because in axis 1, negative is anterior and we expect the most anterior CofM should 
586
    # roughly align with the trochlear notch.
587
    y_CofM = get_y_CofM(flattenedSeg)
588
    first_guess = y_CofM[np.argmin(y_CofM[:,1]), 0]
589
    # the second guess is just the CofM of the whole cartilage. 
590
    centerX, centerY = absolute_CofM(flattenedSeg)
591
    second_guess = centerX
592
593
    # We use the 2 guesses to help define a search space for the trochlear notch.
594
    min_search = int(np.min((first_guess,second_guess))-20)
595
    max_search = int(np.max((first_guess,second_guess))+20)
596
597
    # now, we iterate over all of the rows (axis 1) of the search space (moving in the medial/lateral direction)
598
    # we are looking for the row where the most posterior point (back of femur) is furthest anterior (notch). 
599
    for y in range(min_search, max_search):
600
        # At each row, we find most posterior pixel labeled as cartilage. 
601
        try:
602
            trochleaPosition_test = np.max(np.where(flattenedSeg[y,:]==1))
603
        except ValueError:
604
            # if there is no cartilage we&#39;ll get a ValueError exception. 
605
            # in that case, set this value to be the max it can be (the size of the first axis)
606
            trochleaPosition_test = flattenedSeg.shape[1]
607
        # if the most posterior point for this row is more anterior than the current trochleaPositionX,
608
        # then update this to be the new trochlear notch.
609
        if trochleaPosition_test &lt; trochleaPositionX:
610
            trochleaPositionX = trochleaPosition_test
611
            trochleaPositionY = y
612
613
    return(trochleaPositionY, trochleaPositionX+1)</code></pre>
614
</details>
615
</dd>
616
<dt id="pymskt.image.cartilage_processing.getAnteriorOfWeightBearing"><code class="name flex">
617
<span>def <span class="ident">getAnteriorOfWeightBearing</span></span>(<span>segArray, femurIndex=1)</span>
618
</code></dt>
619
<dd>
620
<div class="desc"><p>Prepare full segmentation and extract the trochlear notch location.
621
Parameters</p>
622
<hr>
623
<dl>
624
<dt><strong><code>flattenedSeg</code></strong> :&ensp;<code>2D array</code></dt>
625
<dd>Axial flattened, and filled in femoral cartilage segmentation.</dd>
626
<dt><strong><code>femurIndex</code></strong> :&ensp;<code>int</code></dt>
627
<dd>Index of the label used to localize the femur in the array.</dd>
628
</dl>
629
<h2 id="returns">Returns</h2>
630
<dl>
631
<dt><strong><code>trochleaPositionY</code></strong></dt>
632
<dd>Y position of trochlear notch</dd>
633
<dt><strong><code>trochleaPositionX</code></strong></dt>
634
<dd>X position of trochlear notch</dd>
635
</dl>
636
<h2 id="notes">Notes</h2>
637
<p>Get the x/y coordinates for the trochlear notch. This is an iterative method that assumes things about the shape the femoral cartilage.
638
First flatten and fill any holes in the segmentation.</p></div>
639
<details class="source">
640
<summary>
641
<span>Expand source code</span>
642
</summary>
643
<pre><code class="python">def getAnteriorOfWeightBearing(segArray, femurIndex=1):
644
    &#39;&#39;&#39;
645
    Prepare full segmentation and extract the trochlear notch location. 
646
    Parameters
647
    ----------
648
    flattenedSeg : 2D array
649
        Axial flattened, and filled in femoral cartilage segmentation.  
650
    femurIndex : int
651
        Index of the label used to localize the femur in the array. 
652
    Returns
653
    -------
654
    trochleaPositionY : 
655
        Y position of trochlear notch  
656
    trochleaPositionX : 
657
        X position of trochlear notch
658
    Notes
659
    -----
660
    Get the x/y coordinates for the trochlear notch. This is an iterative method that assumes things about the shape the femoral cartilage. 
661
    First flatten and fill any holes in the segmentation. 
662
    
663
    &#39;&#39;&#39;
664
665
    femurSegmentation = np.zeros_like(segArray)
666
    femurSegmentation[segArray == femurIndex] = 1
667
    flattenedSegmentation = np.amax(femurSegmentation, axis=1)
668
    flattened_seg_filled = ndi.binary_fill_holes(flattenedSegmentation)
669
    trochY, trochX = findNotch(flattened_seg_filled)
670
    return(trochY, trochX)</code></pre>
671
</details>
672
</dd>
673
<dt id="pymskt.image.cartilage_processing.getCartilageSubRegions"><code class="name flex">
674
<span>def <span class="ident">getCartilageSubRegions</span></span>(<span>segArray, anteriorWBslice, posteriorWBslice, trochY, femurLabel=1, medTibiaLabel=2, latTibiaLabel=3, antFemurMask=5, medWbFemurMask=6, latWbFemurMask=7, medPostFemurMask=8, latPostFemurMask=9)</span>
675
</code></dt>
676
<dd>
677
<div class="desc"><p>Take cartilage segmentation, and decompose femoral cartilage into subregions of interest.<br>
678
Parameters</p>
679
<hr>
680
<dl>
681
<dt><strong><code>segArray</code></strong> :&ensp;<code>array</code></dt>
682
<dd>3D array with segmentation for the cartialge regions.</dd>
683
<dt><strong><code>anteriorWBslice</code></strong> :&ensp;<code>int</code></dt>
684
<dd>Slice that seperates the anterior and weight bearing femoral cartilage.</dd>
685
<dt><strong><code>posteriorWBslice</code></strong> :&ensp;<code>int</code></dt>
686
<dd>Slice that seperates the weight bearing and posterior femoral cartilage.</dd>
687
<dt><strong><code>trochY</code></strong> :&ensp;<code>int</code></dt>
688
<dd>Slice that differentiates medial / lateral femur - trochlear notch Y component.</dd>
689
<dt><strong><code>femurLabel</code></strong> :&ensp;<code>int</code></dt>
690
<dd>Label that femur is in the segArray</dd>
691
<dt><strong><code>medTibiaLabel</code></strong> :&ensp;<code>int</code></dt>
692
<dd>Label that medial tibia is in the segArray</dd>
693
<dt><strong><code>latTibiaLabel</code></strong> :&ensp;<code>int</code></dt>
694
<dd>Label that lateral tibia is in the segArray</dd>
695
<dt><strong><code>antFemurMask</code></strong> :&ensp;<code>int</code></dt>
696
<dd>Label anterior femur should be labeled in final segmentation.</dd>
697
<dt><strong><code>medWbFemurMask</code></strong> :&ensp;<code>int</code></dt>
698
<dd>Label medial weight bearing femur should be labeled in final segmentation.</dd>
699
<dt><strong><code>latWbFemurMask</code></strong> :&ensp;<code>int</code></dt>
700
<dd>Label lateral weight bearing femur should be labeled in final segmentation.</dd>
701
<dt><strong><code>medPostFemurMask</code></strong> :&ensp;<code>int</code></dt>
702
<dd>Label medial posterior femur should be labeled in final segmentation.</dd>
703
<dt><strong><code>latPostFemurMask</code></strong> :&ensp;<code>int</code></dt>
704
<dd>Label lateral posterior femur should be labeled in final segmentation.</dd>
705
</dl>
706
<h2 id="returns">Returns</h2>
707
<dl>
708
<dt><strong><code>final_segmentation</code></strong> :&ensp;<code>array</code></dt>
709
<dd>3D array with the updated segmentations - including weightbearing, medial/latera, anterior, and posterior.</dd>
710
</dl>
711
<h2 id="notes">Notes</h2></div>
712
<details class="source">
713
<summary>
714
<span>Expand source code</span>
715
</summary>
716
<pre><code class="python">def getCartilageSubRegions(segArray, anteriorWBslice, posteriorWBslice, trochY,
717
                           femurLabel=1, medTibiaLabel=2, latTibiaLabel=3, antFemurMask=5, 
718
                           medWbFemurMask=6, latWbFemurMask=7, medPostFemurMask=8, latPostFemurMask=9):
719
    &#39;&#39;&#39;
720
    Take cartilage segmentation, and decompose femoral cartilage into subregions of interest.  
721
    Parameters
722
    ----------
723
    segArray : array
724
        3D array with segmentation for the cartialge regions. 
725
    anteriorWBslice : int
726
        Slice that seperates the anterior and weight bearing femoral cartilage.  
727
    posteriorWBslice : int
728
        Slice that seperates the weight bearing and posterior femoral cartilage. 
729
    trochY : int
730
        Slice that differentiates medial / lateral femur - trochlear notch Y component. 
731
    femurLabel : int
732
        Label that femur is in the segArray
733
    medTibiaLabel : int
734
        Label that medial tibia is in the segArray
735
    latTibiaLabel : int
736
        Label that lateral tibia is in the segArray
737
    antFemurMask : int
738
        Label anterior femur should be labeled in final segmentation. 
739
    medWbFemurMask : int
740
        Label medial weight bearing femur should be labeled in final segmentation.
741
    latWbFemurMask : int
742
        Label lateral weight bearing femur should be labeled in final segmentation. 
743
    medPostFemurMask : int
744
        Label medial posterior femur should be labeled in final segmentation. 
745
    latPostFemurMask : int
746
        Label lateral posterior femur should be labeled in final segmentation.
747
    Returns
748
    -------
749
    final_segmentation : array
750
        3D array with the updated segmentations - including weightbearing, medial/latera, anterior, and posterior. 
751
    Notes
752
    -----
753
    
754
    &#39;&#39;&#39;
755
    
756
    #array to store final segmentation
757
    final_segmentation = np.zeros_like(segArray)
758
    
759
    #create masks for ant/wb/posterior femur
760
    anterior_femur_mask = np.zeros_like(segArray)
761
    anterior_femur_mask[:,:,:anteriorWBslice] = 1
762
763
    wb_femur_mask = np.zeros_like(segArray)
764
    wb_femur_mask[:,:,anteriorWBslice:posteriorWBslice] = 1
765
766
    posterior_femur_mask = np.zeros_like(segArray)
767
    posterior_femur_mask[:,:,posteriorWBslice:] = 1
768
    
769
    #create seg of just femur - and then break it into the sub-regions
770
    femurSegArray = np.zeros_like(segArray)
771
    femurSegArray[segArray==femurLabel] = 1
772
    
773
    #find the center of the medial/lateral tibia - use to distinguish M/L femur ROIs
774
    locationMedialTibia = np.asarray(np.where(segArray==medTibiaLabel))
775
    locationLateralTibia = np.asarray(np.where(segArray==latTibiaLabel))
776
    
777
    centerMedialTibia = locationMedialTibia.mean(axis=1)
778
    centerLateralTibia = locationLateralTibia.mean(axis=1)
779
780
    med_femur_mask = np.zeros_like(segArray)
781
    lat_femur_mask = np.zeros_like(segArray)
782
    if centerMedialTibia[0] &gt; trochY:
783
        med_femur_mask[trochY:,:,:] = 1
784
        lat_femur_mask[:trochY,:,:] = 1
785
    else:
786
        med_femur_mask[:trochY,:,:] = 1
787
        lat_femur_mask[trochY:,:,:] = 1
788
789
    final_segmentation[segArray!=femurLabel] = segArray[segArray!=femurLabel] 
790
    final_segmentation += (femurSegArray * anterior_femur_mask) * antFemurMask
791
    final_segmentation += (femurSegArray * wb_femur_mask * med_femur_mask) * medWbFemurMask
792
    final_segmentation += (femurSegArray * wb_femur_mask * lat_femur_mask) * latWbFemurMask
793
    final_segmentation += (femurSegArray * posterior_femur_mask * med_femur_mask) * medPostFemurMask
794
    final_segmentation += (femurSegArray * posterior_femur_mask * lat_femur_mask) * latPostFemurMask
795
    
796
    return(final_segmentation)</code></pre>
797
</details>
798
</dd>
799
<dt id="pymskt.image.cartilage_processing.get_knee_segmentation_with_femur_subregions"><code class="name flex">
800
<span>def <span class="ident">get_knee_segmentation_with_femur_subregions</span></span>(<span>seg_image, fem_cart_label_idx=1, wb_region_percent_dist=0.6, med_tibia_label=2, lat_tibia_label=3, ant_femur_mask=11, med_wb_femur_mask=12, lat_wb_femur_mask=13, med_post_femur_mask=14, lat_post_femur_mask=15, verify_med_lat_tib_cart=True, tibia_label=6, ml_axis=0)</span>
801
</code></dt>
802
<dd>
803
<div class="desc"><p>Give seg image of knee. Return seg image with all sub-regions of femur included. </p>
804
<h2 id="parameters">Parameters</h2>
805
<dl>
806
<dt><strong><code>seg_image</code></strong> :&ensp;<code>SimpleITK.Image</code></dt>
807
<dd>SimpleITK image of the segmentation to be processed.</dd>
808
<dt><strong><code>fem_cart_label_idx</code></strong> :&ensp;<code>int</code>, optional</dt>
809
<dd>Label of femoral cartilage, by default 1</dd>
810
<dt><strong><code>wb_region_percent_dist</code></strong> :&ensp;<code>float</code>, optional</dt>
811
<dd>How large weightbearing region is (from not to posterior of condyles), by default 0.6</dd>
812
<dt><strong><code>femur_label</code></strong> :&ensp;<code>int</code>, optional</dt>
813
<dd>Seg label for the femur cartilage, by default 1</dd>
814
<dt><strong><code>med_tibia_label</code></strong> :&ensp;<code>int</code>, optional</dt>
815
<dd>Seg label for the medial tibia cartilage, by default 2</dd>
816
<dt><strong><code>lat_tibia_label</code></strong> :&ensp;<code>int</code>, optional</dt>
817
<dd>Seg label for the lateral tibia cartilage, by default 3</dd>
818
<dt><strong><code>ant_femur_mask</code></strong> :&ensp;<code>int</code>, optional</dt>
819
<dd>Seg label for the anterior femur region, by default 11</dd>
820
<dt><strong><code>med_wb_femur_mask</code></strong> :&ensp;<code>int</code>, optional</dt>
821
<dd>Seg label for medial weight-bearing femur, by default 12</dd>
822
<dt><strong><code>lat_wb_femur_mask</code></strong> :&ensp;<code>int</code>, optional</dt>
823
<dd>Seg label for lateral weight-bearing femur, by default 13</dd>
824
<dt><strong><code>med_post_femur_mask</code></strong> :&ensp;<code>int</code>, optional</dt>
825
<dd>Seg label for medial posterior femur, by default 14</dd>
826
<dt><strong><code>lat_post_femur_mask</code></strong> :&ensp;<code>int</code>, optional</dt>
827
<dd>Seg label for lateral posterior femur, by default 15</dd>
828
<dt><strong><code>verify_med_lat_tib_cart</code></strong> :&ensp;<code>bool</code>, optional</dt>
829
<dd>Whether to verify that medial and lateral tibial cartilage is on same side of centerline, by default True</dd>
830
<dt><strong><code>tibia_label</code></strong> :&ensp;<code>int</code>, optional</dt>
831
<dd>Seg label for the tibia, by default 6</dd>
832
<dt><strong><code>ml_axis</code></strong> :&ensp;<code>int</code>, optional</dt>
833
<dd>Medial/lateral axis of the acquired knee MRI, by default 0</dd>
834
</dl>
835
<h2 id="returns">Returns</h2>
836
<dl>
837
<dt><code>SimpleITK.Image</code></dt>
838
<dd>Image of the new/updated segmentation</dd>
839
</dl></div>
840
<details class="source">
841
<summary>
842
<span>Expand source code</span>
843
</summary>
844
<pre><code class="python">def get_knee_segmentation_with_femur_subregions(seg_image,
845
                                                fem_cart_label_idx=1,
846
                                                wb_region_percent_dist=0.6,
847
                                                # femur_label=1,
848
                                                med_tibia_label=2,
849
                                                lat_tibia_label=3,
850
                                                ant_femur_mask=11,
851
                                                med_wb_femur_mask=12,
852
                                                lat_wb_femur_mask=13,
853
                                                med_post_femur_mask=14,
854
                                                lat_post_femur_mask=15,
855
                                                verify_med_lat_tib_cart=True,
856
                                                tibia_label=6,
857
                                                ml_axis=0
858
                                                ):
859
    &#34;&#34;&#34;
860
    Give seg image of knee. Return seg image with all sub-regions of femur included. 
861
862
    Parameters
863
    ----------
864
    seg_image : SimpleITK.Image
865
        SimpleITK image of the segmentation to be processed. 
866
    fem_cart_label_idx : int, optional
867
        Label of femoral cartilage, by default 1
868
    wb_region_percent_dist : float, optional
869
        How large weightbearing region is (from not to posterior of condyles), by default 0.6
870
    femur_label : int, optional
871
        Seg label for the femur cartilage, by default 1
872
    med_tibia_label : int, optional
873
        Seg label for the medial tibia cartilage, by default 2
874
    lat_tibia_label : int, optional
875
        Seg label for the lateral tibia cartilage, by default 3
876
    ant_femur_mask : int, optional
877
        Seg label for the anterior femur region, by default 11
878
    med_wb_femur_mask : int, optional
879
        Seg label for medial weight-bearing femur, by default 12
880
    lat_wb_femur_mask : int, optional
881
        Seg label for lateral weight-bearing femur, by default 13
882
    med_post_femur_mask : int, optional
883
        Seg label for medial posterior femur, by default 14
884
    lat_post_femur_mask : int, optional
885
        Seg label for lateral posterior femur, by default 15
886
    verify_med_lat_tib_cart : bool, optional
887
        Whether to verify that medial and lateral tibial cartilage is on same side of centerline, by default True
888
    tibia_label : int, optional
889
        Seg label for the tibia, by default 6
890
    ml_axis : int, optional
891
        Medial/lateral axis of the acquired knee MRI, by default 0
892
893
    Returns
894
    -------
895
    SimpleITK.Image
896
        Image of the new/updated segmentation
897
    &#34;&#34;&#34;
898
    troch_notch_y, troch_notch_x = getAnteriorOfWeightBearing(sitk.GetArrayViewFromImage(seg_image),
899
                                                              femurIndex=fem_cart_label_idx)
900
    loc_fem_z, loc_fem_y, loc_fem_x = np.where(sitk.GetArrayViewFromImage(seg_image) == fem_cart_label_idx)
901
    post_femur_slice = np.max(loc_fem_x)
902
    posterior_wb_slice = np.round((post_femur_slice - troch_notch_x) * wb_region_percent_dist + troch_notch_x).astype(int)
903
    new_seg_array = getCartilageSubRegions(sitk.GetArrayViewFromImage(seg_image),
904
                                           anteriorWBslice=troch_notch_x,
905
                                           posteriorWBslice=posterior_wb_slice,
906
                                           trochY=troch_notch_y,
907
                                           femurLabel=fem_cart_label_idx,
908
                                           medTibiaLabel=med_tibia_label,
909
                                           latTibiaLabel=lat_tibia_label,
910
                                           antFemurMask=ant_femur_mask,
911
                                           medWbFemurMask=med_wb_femur_mask,
912
                                           latWbFemurMask=lat_wb_femur_mask,
913
                                           medPostFemurMask=med_post_femur_mask,
914
                                           latPostFemurMask=lat_post_femur_mask
915
                                           )
916
917
    if verify_med_lat_tib_cart:
918
        new_seg_array = verify_and_correct_med_lat_tib_cart(new_seg_array,
919
                                                            tib_label=tibia_label,
920
                                                            med_tib_cart_label=med_tibia_label, 
921
                                                            lat_tib_cart_label=lat_tibia_label,
922
                                                            ml_axis=ml_axis) 
923
    seg_label_image = sitk.GetImageFromArray(new_seg_array)
924
    seg_label_image.CopyInformation(seg_image)
925
    return seg_label_image</code></pre>
926
</details>
927
</dd>
928
<dt id="pymskt.image.cartilage_processing.get_y_CofM"><code class="name flex">
929
<span>def <span class="ident">get_y_CofM</span></span>(<span>flattenedSeg)</span>
930
</code></dt>
931
<dd>
932
<div class="desc"><p>Get CofM of femoral cartilage for each row of the flattened segmentation.
933
Parameters</p>
934
<hr>
935
<dl>
936
<dt><strong><code>flattenedSeg</code></strong> :&ensp;<code>2D array</code></dt>
937
<dd>Axial flattened, and filled in femoral cartilage segmentation.</dd>
938
</dl>
939
<h2 id="returns">Returns</h2>
940
<dl>
941
<dt><strong><code>yCofM</code></strong></dt>
942
<dd>Find the CofM for each row of the image.</dd>
943
</dl>
944
<h2 id="notes">Notes</h2>
945
<p>Get the x/y coordinates for the CofM for each row of the flattened segmentation.</p></div>
946
<details class="source">
947
<summary>
948
<span>Expand source code</span>
949
</summary>
950
<pre><code class="python">def get_y_CofM(flattenedSeg):
951
    &#39;&#39;&#39;
952
    Get CofM of femoral cartilage for each row of the flattened segmentation. 
953
    Parameters
954
    ----------
955
    flattenedSeg : 2D array
956
        Axial flattened, and filled in femoral cartilage segmentation.  
957
    Returns
958
    -------
959
    yCofM : 
960
        Find the CofM for each row of the image. 
961
    Notes
962
    -----
963
    Get the x/y coordinates for the CofM for each row of the flattened segmentation. 
964
    
965
    &#39;&#39;&#39;
966
    locationFemur = np.where(flattenedSeg==1)
967
    yCofM = np.zeros((flattenedSeg.shape[0], 2), dtype=int)
968
    
969
    # only calculate for rows with cartilage. 
970
    minRow = np.min(locationFemur[0])
971
    maxRow = np.max(locationFemur[0])
972
    
973
    # iterate over rows of image, get CofM, store CofM for row. 
974
    for x in range(minRow, maxRow):
975
        yCofM[x, 0] = x #store the x-coordinate (row) we calcualted CofM for. 
976
        yCofM[x, 1] = int(CofM(flattenedSeg[x, :])) # store the CofM value (make it an integer for indexing)
977
    yCofM = yCofM[minRow+10:maxRow-10,:] # remove 10 most medial and most lateral pixels of femoral cartilage. 
978
    return(yCofM) </code></pre>
979
</details>
980
</dd>
981
<dt id="pymskt.image.cartilage_processing.verify_and_correct_med_lat_tib_cart"><code class="name flex">
982
<span>def <span class="ident">verify_and_correct_med_lat_tib_cart</span></span>(<span>seg_array, tib_label=6, med_tib_cart_label=2, lat_tib_cart_label=3, ml_axis=0)</span>
983
</code></dt>
984
<dd>
985
<div class="desc"><p>Verify that the medial and lateral tibial cartilage are correctly labeled.
986
Parameters</p>
987
<hr>
988
<dl>
989
<dt><strong><code>seg_array</code></strong> :&ensp;<code>array</code></dt>
990
<dd>3D array with segmentation for the cartilage/bone regions.</dd>
991
<dt><strong><code>tib_label</code></strong> :&ensp;<code>int</code></dt>
992
<dd>Label that tibial cartilage is in the seg_array</dd>
993
<dt><strong><code>med_tib_cart_label</code></strong> :&ensp;<code>int</code></dt>
994
<dd>Label that medial tibial cartilage is in the seg_array</dd>
995
<dt><strong><code>lat_tib_cart_label</code></strong> :&ensp;<code>int</code></dt>
996
<dd>Label that lateral tibial cartilage is in the seg_array</dd>
997
<dt><strong><code>ml_axis</code></strong> :&ensp;<code>int</code></dt>
998
<dd>Medial/lateral axis of the acquired knee MRI.</dd>
999
</dl>
1000
<h2 id="returns">Returns</h2>
1001
<dl>
1002
<dt><strong><code>seg_array</code></strong> :&ensp;<code>array</code></dt>
1003
<dd>3D array with segmentation for the cartilage/bone regions.
1004
The tibial cartilage regions will have been updated to ensure
1005
all tib cart on med/lat sides are correctly classified.</dd>
1006
</dl></div>
1007
<details class="source">
1008
<summary>
1009
<span>Expand source code</span>
1010
</summary>
1011
<pre><code class="python">def verify_and_correct_med_lat_tib_cart(
1012
    seg_array,  #sitk.GetArrayViewFromImage(seg)
1013
    tib_label=6,
1014
    med_tib_cart_label=2, 
1015
    lat_tib_cart_label=3,
1016
    ml_axis=0
1017
):
1018
    &#39;&#39;&#39;
1019
    Verify that the medial and lateral tibial cartilage are correctly labeled.
1020
    Parameters
1021
    ----------
1022
    seg_array : array
1023
        3D array with segmentation for the cartilage/bone regions.
1024
    tib_label : int
1025
        Label that tibial cartilage is in the seg_array
1026
    med_tib_cart_label : int
1027
        Label that medial tibial cartilage is in the seg_array
1028
    lat_tib_cart_label : int
1029
        Label that lateral tibial cartilage is in the seg_array
1030
    ml_axis : int
1031
        Medial/lateral axis of the acquired knee MRI.
1032
    
1033
    Returns
1034
    -------
1035
    seg_array : array
1036
        3D array with segmentation for the cartilage/bone regions.
1037
        The tibial cartilage regions will have been updated to ensure
1038
        all tib cart on med/lat sides are correctly classified.
1039
        
1040
    &#39;&#39;&#39;
1041
    #get binary array for tibia
1042
    array_tib = np.zeros_like(seg_array)
1043
    array_tib[seg_array == tib_label] = 1
1044
    #get binary array for tib cart
1045
    array_tib_cart = np.zeros_like(seg_array)
1046
    array_tib_cart[(seg_array == lat_tib_cart_label) + (seg_array == med_tib_cart_label)] = 1
1047
1048
    #get the locatons of med/lat cartilage &amp; get their centroids
1049
    med_cart_locs = np.asarray(np.where(seg_array == med_tib_cart_label))
1050
    lat_cart_locs = np.asarray(np.where(seg_array == lat_tib_cart_label))
1051
    middle_med_cart = med_cart_locs[ml_axis,:].mean()
1052
    middle_lat_cart = lat_cart_locs[ml_axis,:].mean()
1053
1054
    #get location of tibia to get centroid of tibial plateau
1055
    tib_locs = np.asarray(np.where(seg_array == tib_label))
1056
    middle_tib = tib_locs[ml_axis, :].mean()
1057
    center_tibia_slice = int(middle_tib)
1058
1059
    # infer the direction(s) for medial/lateral
1060
    med_direction = np.sign(middle_med_cart - middle_tib)
1061
    lat_direction = np.sign(middle_lat_cart - middle_tib)
1062
    if med_direction == lat_direction:
1063
        raise Exception(&#39;Middle of med and lat tibial cartilage on same side of centerline!&#39;)
1064
1065
    #create med/lat cartilage masks - binary for updating seg masks
1066
    med_tib_cart_mask = np.zeros_like(seg_array)
1067
    lat_tib_cart_mask = np.zeros_like(seg_array)
1068
1069
    if med_direction &gt; 0:
1070
        med_tib_cart_mask[center_tibia_slice:,...] = 1
1071
        lat_tib_cart_mask[:center_tibia_slice,...] = 1
1072
    elif med_direction &lt; 0:
1073
        med_tib_cart_mask[:center_tibia_slice,...] = 1
1074
        lat_tib_cart_mask[center_tibia_slice:,...] = 1
1075
1076
    # create new med/lat cartilage arrays 
1077
    new_med_cart_array = array_tib_cart * med_tib_cart_mask
1078
    new_lat_cart_array = array_tib_cart * lat_tib_cart_mask
1079
1080
    #make copy of original segmentation array &amp; update
1081
    # med/lat tibial cartilage labels
1082
    new_seg_array = seg_array.copy()
1083
    new_seg_array[new_med_cart_array == 1] = med_tib_cart_label
1084
    new_seg_array[new_lat_cart_array == 1] = lat_tib_cart_label
1085
    
1086
    return new_seg_array</code></pre>
1087
</details>
1088
</dd>
1089
</dl>
1090
</section>
1091
<section>
1092
</section>
1093
</article>
1094
<nav id="sidebar">
1095
<h1>Index</h1>
1096
<div class="toc">
1097
<ul></ul>
1098
</div>
1099
<ul id="index">
1100
<li><h3>Super-module</h3>
1101
<ul>
1102
<li><code><a title="pymskt.image" href="index.html">pymskt.image</a></code></li>
1103
</ul>
1104
</li>
1105
<li><h3><a href="#header-functions">Functions</a></h3>
1106
<ul class="">
1107
<li><code><a title="pymskt.image.cartilage_processing.CofM" href="#pymskt.image.cartilage_processing.CofM">CofM</a></code></li>
1108
<li><code><a title="pymskt.image.cartilage_processing.absolute_CofM" href="#pymskt.image.cartilage_processing.absolute_CofM">absolute_CofM</a></code></li>
1109
<li><code><a title="pymskt.image.cartilage_processing.findNotch" href="#pymskt.image.cartilage_processing.findNotch">findNotch</a></code></li>
1110
<li><code><a title="pymskt.image.cartilage_processing.getAnteriorOfWeightBearing" href="#pymskt.image.cartilage_processing.getAnteriorOfWeightBearing">getAnteriorOfWeightBearing</a></code></li>
1111
<li><code><a title="pymskt.image.cartilage_processing.getCartilageSubRegions" href="#pymskt.image.cartilage_processing.getCartilageSubRegions">getCartilageSubRegions</a></code></li>
1112
<li><code><a title="pymskt.image.cartilage_processing.get_knee_segmentation_with_femur_subregions" href="#pymskt.image.cartilage_processing.get_knee_segmentation_with_femur_subregions">get_knee_segmentation_with_femur_subregions</a></code></li>
1113
<li><code><a title="pymskt.image.cartilage_processing.get_y_CofM" href="#pymskt.image.cartilage_processing.get_y_CofM">get_y_CofM</a></code></li>
1114
<li><code><a title="pymskt.image.cartilage_processing.verify_and_correct_med_lat_tib_cart" href="#pymskt.image.cartilage_processing.verify_and_correct_med_lat_tib_cart">verify_and_correct_med_lat_tib_cart</a></code></li>
1115
</ul>
1116
</li>
1117
</ul>
1118
</nav>
1119
</main>
1120
<footer id="footer">
1121
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
1122
</footer>
1123
</body>
1124
</html>