Diff of /R/segment_lung_lr.R [000000] .. [3b2327]

Switch to unified view

a b/R/segment_lung_lr.R
1
#' Lung Segmentation
2
#'
3
#' This function segments the right and left lungs from a CT scan.
4
#'
5
#' @param img CT scan in ANTs or NIfTI file format
6
#' @param lthresh Threshold used to find the lung and airways,
7
#' from the CT. Default: -300 HU.
8
#' @param verbose Print diagnostic messages.
9
#'
10
#' @return Lung mask in ANTs file format. Right lung = 1, left lung = 2, non-lung = 0
11
#' @importFrom ANTsR maskImage
12
#' @importFrom ANTsRCore iMath labelClusters makeImage
13
#' @export
14
segment_lung_lr = function(img, lthresh = -300, verbose = TRUE){
15
16
    orig_img = check_ants(img)
17
    img = antsImageClone(orig_img)
18
    if (verbose) {
19
      message("# Resampling Image to 1x1x1")
20
    }
21
    img = resampleImage(img, c(1,1,1))
22
23
24
    # Make all values positive, so 0s are 0s
25
    img = img + 1025
26
    orig_lthresh = lthresh
27
    lthresh = lthresh + 1025
28
29
30
    # Segmenting Lung and Airways (using code from segment_lung)
31
    if (verbose) {
32
      message("# Segmenting Lung and Airways: Thresholding")
33
    }
34
    body_img = img <= lthresh
35
36
37
    # Find the lungs and trachea from the image
38
    if (verbose) {
39
      message("# Segmenting Lung and Airways: Largest Component")
40
    }
41
    first_img = iMath(img = body_img, operation = "GetLargestComponent")
42
43
    # Check to see if we grabbed the background instead of the lung/trachea
44
    # The back 10 slice and/or front 10 slices should have mean ~ 1, if selected
45
    n_max = dim(first_img)[2]
46
    mean_back = mean(apply(as.array(first_img)[,1:10,],2,mean))
47
    mean_front = mean(apply(as.array(first_img)[,(n_max-9):n_max,],2,mean))
48
49
    # Remove background, as necessary
50
    if(mean_back > .5 | mean_front > .5)
51
    {
52
      first_img_hold = antsImageClone(first_img)
53
54
      # Remove background from rest of image
55
      first_img = (1-first_img_hold) * body_img
56
      first_img = iMath(img = first_img, operation = "GetLargestComponent")
57
58
      # Check to see if that fixed the problem
59
      mean_back = mean(apply(as.array(first_img)[,1:10,],2,mean))
60
      mean_front = mean(apply(as.array(first_img)[,(n_max-9):n_max,],2,mean))
61
62
      # Keep fixing, as necessary
63
      if(mean_back > .5 | mean_front > .5) # Still background
64
      {
65
        first_img_hold[first_img==1] = 1
66
        first_img = (1-first_img_hold) * body_img
67
        first_img = iMath(img = first_img, operation = "GetLargestComponent")
68
69
        # Check to see if that fixed the problem
70
        mean_back = mean(apply(as.array(first_img)[,1:10,],2,mean))
71
        mean_front = mean(apply(as.array(first_img)[,(n_max-9):n_max,],2,mean))
72
        if(mean_back > .5 | mean_front > .5){
73
          first_img = segment_lung(orig_img, lthresh = orig_lthresh)
74
          first_img <- first_img$lung_mask
75
          #stop("Can't find lungs beneath background noise. More coding needed")
76
          }
77
78
      }
79
    }
80
    lung_air_mask = iMath(first_img, "MC", 2)
81
82
83
84
    # Segmenting Airways
85
    if (verbose) {
86
      message("# Segmenting Airways: Thresholding")
87
    }
88
    air_mask = antsImageClone(lung_air_mask)
89
    air = maskImage(img,lung_air_mask)
90
    air_thres = quantile(air[air>0],.04)
91
    air_mask[img > air_thres] = 0
92
93
    if (verbose) {
94
      message("# Segmenting Airways: Identifying Airway Location")
95
    }
96
    fimg <- air_mask > 2
97
    mydim = dim(fimg)
98
    fimg<-as.array(fimg,dim=mydim)
99
    fimg[round(mydim[1]/4):(round(mydim[1]/4)*3),round(mydim[2]/4):(round(mydim[2]/4)*3),round(mydim[3]/2):mydim[3]] <- 1
100
    fimg<-makeImage(mydim,fimg)
101
    air_mask <- maskImage(air_mask,fimg)
102
103
    if (verbose) {
104
      message("# Segmenting Airways: Smoothing")
105
    }
106
    air_mask = iMath(air_mask, "MC", 1)
107
    air_mask = iMath(air_mask, "ME", 1)
108
    air_mask = iMath(air_mask, "MD", 2)
109
110
111
    # Segmenting Lung
112
    if (verbose) {
113
      message("# Segmenting Lung: Removing Airways from Lung")
114
    }
115
    lung_mask = maskImage(lung_air_mask, 1-air_mask)
116
    img_masked = maskImage(img, lung_mask)
117
118
    if (verbose) {
119
      message("# Segmenting Lung: Finding Left and Right Lungs")
120
    }
121
    left_right_mask = labelClusters(lung_mask, minClusterSize = 50000)
122
    n_clus = length(unique(left_right_mask))
123
124
    if (n_clus == 1) {
125
      message("# Error: Can't find lungs, returning current mask")
126
      return(lung_mask)
127
    }
128
129
    # Left and right lung are still connected
130
    i = 0
131
    j = 0
132
    lung_mask2 = antsImageClone(lung_mask)
133
    while(n_clus == 2){
134
      if(i == 0) {
135
        lung_mask2 = iMath(lung_mask2, "ME", 1)
136
        j = j + 1
137
        left_right_mask = labelClusters(lung_mask2, minClusterSize = 50000)
138
        n_clus = length(unique(left_right_mask))
139
      }
140
      i = i + 1
141
      new_lthresh = lthresh - 50*i
142
      if(new_lthresh < 0){
143
        message("# Error: Can't distinguish left/right lungs, returning left/right combined mask")
144
        return(lung_mask)
145
      }
146
      if(new_lthresh <= 200) {
147
        lung_mask2 = iMath(lung_mask2, "ME", 1)
148
        j = j + 1
149
      }
150
      img_mask = img_masked < new_lthresh
151
      lung_mask2[img_mask == 0] = 0
152
      left_right_mask = labelClusters(lung_mask2, minClusterSize = 50000)
153
      num = unique(left_right_mask)
154
      n_clus = length(num)
155
    }
156
157
    # Correct number of clusters
158
    if (n_clus == 3) {
159
160
      # Find which value is the background (Note: this was added because sometimes the background is non-zero)
161
      left_right_mask = left_right_mask + 1
162
      fimg <- as.array(left_right_mask)
163
      last <- dim(fimg)[1]
164
      left <- unique(as.vector(fimg[1,,]))
165
      right <- unique(as.vector(fimg[last,,]))
166
      both <- c(left,right)
167
      # Logic: only the background value will be on both the left and right sides
168
      value <- both[duplicated(both)]
169
170
      # Make background value 0, and the other two values 1 and 2
171
      left_right_mask[left_right_mask == value] <- 0
172
      num = unique(left_right_mask)
173
      if(1 %in% num & 3 %in% num){
174
        left_right_mask[left_right_mask==3] <- 2
175
      }
176
      if(2 %in% num & 3 %in% num){
177
        left_right_mask[left_right_mask==2] <- 1
178
        left_right_mask[left_right_mask==3] <- 2
179
      }
180
181
182
      # Find coordinates of left and right clusters
183
      coord = sapply(1:2, function(i){
184
        img = left_right_mask == i
185
        loc = which(as.array(img) == 1, arr.ind = T)
186
        x = median(loc[,1])
187
        return(x)
188
      })
189
      if (coord[1] < coord[2]){
190
        right_mask = left_right_mask == 1
191
        left_mask = left_right_mask == 2
192
      } else {
193
        right_mask = left_right_mask == 2
194
        left_mask = left_right_mask == 1
195
      }
196
197
198
      if (verbose) {
199
        message("# Segmenting Lung: Finishing Touches")
200
      }
201
      left_mask = iMath(left_mask, "MC", 8+2*j)
202
      left_mask = iMath(img = left_mask, operation = "GetLargestComponent")
203
      right_mask = iMath(right_mask, "MC", 8+2*j)
204
      right_mask = iMath(img = right_mask, operation = "GetLargestComponent")
205
      left_right_mask = right_mask + left_mask * 2
206
      left_right_mask[left_right_mask == 3] = 0
207
      left_right_mask[lung_air_mask == 0] = 0
208
209
    } else{message("# Error: Too many clusters")}
210
211
212
    if (verbose) {
213
      message("# Resampling Back to Original Image Size")
214
    }
215
    left_right_mask = resampleImage(left_right_mask,
216
                                    resampleParams = dim(orig_img),
217
                                    useVoxels = TRUE,
218
                                    interpType = 1)
219
    return(left_right_mask)
220
221
222
}
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247