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

Switch to unified view

a b/R/radiomics_partition.R
1
#' Radiomic Calculation on Partitioned Lung
2
#'
3
#' Calculate radiomic features on the partitioned 3D lung
4
#'
5
#' @param img CT scan in ANTs image file format
6
#' @param mask Mask of CT scan in ANTs image file format
7
#' @param sides Choose to calculate radiomic features on the right and/or left lungs. Note: Right lung = 1, left lung = 2, non-lung = 0
8
#' @param featuresFirst First level radiomic features to calculate
9
#' @param featuresSpatial Spatial radiomic features to calculate
10
#' @param partition Matrix of x, y, and z coordinates for each partition from partition_lung. If null, partition_lung is called.
11
#' @param kernel_size (If partition is null) Size of the kernel, in voxel units of width, depth, and height. Must be c(3,3,3) or greater. Default: c(30,30,30)
12
#' @param kernel_stride (If partition is null) Stride (or spacing) between kernels, in voxel units, for width, depth, and height. If kernel_stride = kernel_size, the partitions are non-overlapping. If stride = c(1,1,1), then each voxel is returned.
13
#' @param threshold Number of non-missing voxels needed to calculate radiomic features in each partition.
14
#' @param tidy Logical. If true, outputs a tidy dataframe with results. If false, outputs nested loop.
15
#'
16
#' @return Values from selected features for both left and right lungs
17
#' @importFrom ANTsR maskImage
18
#' @export
19
radiomics_partition <- function(img,
20
                                mask,
21
                                sides = c("right", "left"),
22
                                featuresFirst = c('mean', 'sd', 'skew', 'kurtosis', 'min', 'q1', 'median', 'q3', 'max','energy', 'rms', 'uniformity', 'entropy'),
23
                                featuresSpatial = c('mi', 'gc', 'fd'),
24
                                partition = NULL,
25
                                kernel_size = c(30, 30, 30),
26
                                kernel_stride = c(30, 30, 30),
27
                                threshold = 1000,
28
                                tidy = TRUE) {
29
30
  # Get partition, if necessary
31
  if(is.null(partition)){
32
    partition = partition_lung(img,
33
                               kernel_size = kernel_size,
34
                               kernel_stride = kernel_stride,
35
                               centroid = TRUE)
36
  }
37
38
39
  # Calculate radiomic features on partitions within each mask value
40
  featuresMask <- lapply(sides, function(side){
41
42
    if(side == "right"){mv = 1}
43
    if(side == "left"){mv = 2}
44
45
    # Put image in array format and remove non-mask values
46
    img2 <- as.array(img)
47
    mask2 <- as.array(mask)
48
    mask2 <- mask2 == mv
49
    img2[mask2 != 1] <- NA
50
51
    # Calculate n each partition
52
    features <- lapply(1:dim(partition)[1], function(i){
53
54
      # Grab partition
55
      x <- img2[partition$x1[i]:partition$xend[i],
56
                partition$y1[i]:partition$yend[i],
57
                partition$z1[i]:partition$zend[i]]
58
59
      # Find dimension of partition and number of non-null pixels
60
      dim_p <- dim(x)
61
      if(is.null(dim_p)){dim_p <- c(0,0,0)}
62
      npixels <- length(x[!is.na(x)])
63
64
65
      # Only calculate radiomic features if partition fits criteria
66
      if(dim_p[1] > 2 & dim_p[2] > 2 & dim_p[3] > 2 & npixels >= threshold){
67
68
        # Calculate features
69
        if(length(featuresFirst)>0){
70
          features1 <- radiomics_first(x, featuresFirst)
71
        }else(features1 <- NULL)
72
        if(length(featuresSpatial)>0){
73
          features2 <- radiomics_spatial(x, featuresSpatial)
74
        }else(features2 <- NULL)
75
76
77
        # Put features together and only keep specified features
78
        features <- c(features1, features2)
79
        features <- features[c(featuresFirst, featuresSpatial)]
80
        features <- c(npixels = npixels, features)
81
82
      }else(features <- NULL)
83
84
      return(features)
85
    })
86
87
    # Name partitions and remove NULL partitions
88
    names(features) <- paste0('partition', 1:dim(partition)[1])
89
    features[sapply(features, is.null)] <- NULL
90
    return(features)
91
  })
92
  names(featuresMask) <- sides
93
94
95
  if(tidy == TRUE){
96
    # Make a nice little data frame to output
97
    test2 = NULL
98
    for(i in 1:length(featuresMask)){
99
100
      # Reduce list to data frame
101
      test <- do.call('rbind', featuresMask[[i]])
102
      test <- cbind.data.frame(lung = names(featuresMask)[i],
103
                               partition = names(featuresMask[[i]]),
104
                               test)
105
106
      # Reformatting
107
      test$partition <- gsub("partition", "", test$partition)
108
      test <- as.data.frame(sapply(test, as.numeric))
109
110
      # Add in partition centroids
111
      partition2 <- partition[partition$partition %in% test$partition, 8:10]
112
      test <- cbind(partition2, test)
113
      test2 <- rbind(test2, test)
114
    }
115
    featuresMask <- test2
116
    rm(test,test2,partition2)
117
    gc()
118
    rownames(featuresMask) <- c()
119
  }
120
121
  return(featuresMask)
122
}
123