We build on the BRATS 2013 challenge to segment areas of the brain that have been damaged by stroke. We also refer to a more recent publication that implements a more complex version of what we do here.
We define a function that will help us simulate large, lateralized lesions on the fly.
library(ANTsR)
simLesion<-function( img, s , w, thresh=0.01, mask=NA, myseed )
{
set.seed(myseed)
img<-iMath(img,"Normalize")
if ( is.na(mask) ) mask<-getMask(img)
i<-makeImage( dim(img) , rnorm( length(as.array(img)) ) )
i[ mask==0 ]<-0
ni<-smoothImage(i,s)
ni[mask==0]<-0
i<-thresholdImage(ni,thresh,Inf)
i<-iMath(i,"GetLargestComponent")
ti<-antsImageClone(i)
i[i>0]<-ti[i>0]
i<-smoothImage(i,w)
i[ mask != 1 ] <- 0
i[ 1:(dim(img)[1]/2), 1:(dim(img)[2]-1) ]<-0
limg<-( antsImageClone(img) * (-i) %>% iMath("Normalize") )
return( list(limg=limg, lesion=i ) )
}
Now let’s apply this function to generate a test dataset.
Now let’s apply this function to generate a test dataset.
Create training data and map to the test subject. Note that a “real” application of this type would use cost function masking.
But let’s ignore that aspect of the problem here.
This gives us a subject with a “ground truth” segmentation.
Now we get a new subject and map to the space of the arbitrarily chosen reference space.
Now use these to train a model.
rad<-c(1,1) # fast setting
mr<-c(1,2,4,2,1) # multi-res schedule, U-style schedule
masks=list( getMask(seg), getMask(seg1) )
rfm<-mrvnrfs( list(seg,seg1) , list(list(ll$limg), list(ll1$limg) ),
masks, rad=rad, nsamples = 500, ntrees=1000, multiResSchedule=mr,
voxchunk=500, do.trace = 100)
## randomForest 4.6-14
## Type rfNews() to see new features/changes/bug fixes.
## ntree OOB 1 2 3 4
## 100: 12.30% 29.81% 11.07% 12.98% 5.08%
## 200: 12.60% 30.77% 12.08% 12.71% 5.08%
## 300: 12.90% 29.81% 12.42% 13.54% 5.08%
## 400: 12.70% 28.85% 12.08% 13.54% 5.08%
## 500: 12.80% 31.73% 12.08% 13.26% 4.66%
## 600: 12.90% 31.73% 12.42% 13.26% 4.66%
## 700: 12.70% 31.73% 12.08% 12.98% 4.66%
## 800: 13.00% 31.73% 12.08% 13.54% 5.08%
## 900: 13.00% 31.73% 11.74% 13.81% 5.08%
## 1000: 13.00% 32.69% 12.08% 13.26% 5.08%
## ntree OOB 1 2 3 4
## 100: 10.60% 14.29% 11.80% 13.22% 1.99%
## 200: 10.60% 12.50% 12.68% 12.93% 1.99%
## 300: 10.80% 13.39% 12.68% 13.22% 1.99%
## 400: 10.80% 13.39% 12.98% 12.93% 1.99%
## 500: 10.80% 13.39% 12.98% 12.93% 1.99%
## 600: 10.90% 13.39% 12.98% 13.22% 1.99%
## 700: 10.90% 13.39% 12.98% 13.22% 1.99%
## 800: 10.90% 13.39% 12.98% 13.22% 1.99%
## 900: 10.90% 13.39% 12.98% 13.22% 1.99%
## 1000: 11.00% 13.39% 12.98% 13.22% 2.49%
## ntree OOB 1 2 3 4
## 100: 7.30% 11.93% 9.87% 8.00% 1.53%
## 200: 7.50% 12.84% 10.53% 7.69% 1.53%
## 300: 7.40% 12.84% 10.53% 7.69% 1.15%
## 400: 7.40% 12.84% 10.53% 7.69% 1.15%
## 500: 7.40% 14.68% 9.87% 7.69% 1.15%
## 600: 7.50% 14.68% 10.20% 8.00% 0.76%
## 700: 7.60% 14.68% 9.87% 8.00% 1.53%
## 800: 7.40% 14.68% 9.54% 8.00% 1.15%
## 900: 7.40% 14.68% 9.54% 8.00% 1.15%
## 1000: 7.40% 14.68% 9.54% 8.00% 1.15%
## ntree OOB 1 2 3 4
## 100: 7.60% 8.70% 10.03% 9.57% 1.24%
## 200: 6.80% 9.57% 8.78% 8.33% 0.83%
## 300: 6.60% 9.57% 8.15% 8.33% 0.83%
## 400: 6.30% 8.70% 7.84% 8.02% 0.83%
## 500: 6.40% 8.70% 7.52% 8.64% 0.83%
## 600: 6.80% 8.70% 8.46% 8.95% 0.83%
## 700: 6.60% 8.70% 8.15% 8.64% 0.83%
## 800: 6.50% 8.70% 7.84% 8.64% 0.83%
## 900: 6.50% 8.70% 8.15% 8.33% 0.83%
## 1000: 6.60% 8.70% 8.15% 8.64% 0.83%
## ntree OOB 1 2 3 4
## 100: 7.20% 12.63% 7.94% 9.15% 1.61%
## 200: 7.10% 13.68% 7.65% 8.83% 1.61%
## 300: 6.70% 11.58% 7.65% 8.20% 1.61%
## 400: 6.50% 12.63% 7.06% 7.89% 1.61%
## 500: 6.60% 11.58% 7.65% 7.89% 1.61%
## 600: 6.40% 12.63% 7.35% 7.26% 1.61%
## 700: 6.40% 12.63% 7.06% 7.57% 1.61%
## 800: 6.50% 12.63% 7.35% 7.57% 1.61%
## 900: 6.40% 12.63% 7.06% 7.57% 1.61%
## 1000: 6.30% 12.63% 6.76% 7.57% 1.61%
newrflist<-list()
temp<-mrvnrfs( list(seg,seg1) , list(list(ll$limg), list(ll1$limg) ),
masks, rad=rad, nsamples = 500, ntrees=1000, multiResSchedule=mr,
voxchunk=500 )
for ( k in 1:length( mr ) )
if ( length( rfm$rflist[[k]]$classes ) ==
length( temp$rflist[[k]]$classes ) )
newrflist[[k]]<-combine( rfm$rflist[[k]], temp$rflist[[k]] )
rfm$rflist<-newrflist
We apply the learned model to segment the new data.
Here is the ground truth.
Take a quick look at the lesion probability.
Now we compute the overlap.
The Dice overlap is 0.9180068. We might consider model selection as well where we do a quick estimate of lesion size based on the volume of left hemisphere csf. Then build the model from subjects that “match” with respect to the coarse amount of lesion.