# Regions of Interest

#### 2025-04-09

# Regions of interest

## Creating a spherical ROI

In neuroim2 there is basic support for creating regions of interest (ROI). To create a spherical ROI around a central point, we need an existing object of type `NeuroVol` or `NeuroSpace`.

To create a spherical region of interest with a 5mm radius around a central voxel at i=20, j=20, k=20, we first read in an image.

          library(neuroim2)
          file_name <- system.file("extdata", "global_mask2.nii.gz", package="neuroim2")
          vol <- read_vol(file_name)

Next, we create a spherical ROI centered around voxel coordinates [20,20,20] with a 5mm radius, filling all values in the ROI with 100.

          sphere <- spherical_roi(vol, c(20,20,20), radius=5, fill=100, use_cpp=FALSE)

    #>
    #>  ROIVol Object
    #>
    #> Properties:
    #>   Dimensions: 11 x 3
    #>   ROI Points: 11
    #>   Value Range: [100.00, 100.00]

## Creating a Spherical ROI around a real-valued coordinate

To create a spherical ROI centered around a real coordinate in millimeters, we need to first convert the real-valued coordinates to a voxel-based coordinate. Suppose our real-world coordinate is at -50, -28, 10 in coordinate space.

        rpoint <- c(-34,-28,10)

Because the function `spherical_roi` takes a coordinate in voxel units, we need to convert the real-world coordinate (i.e. in millimeter units) to voxel coordinates.

        vox <- coord_to_grid(vol, rpoint)
        sphere <- spherical_roi(vol, vox, radius=10, fill=1)
        dim(coords(sphere))
    #> [1] 85  3

Now we convert back to real-world coordinates

        coords <- index_to_coord(vol, indices(sphere))
        center_of_mass <- colMeans(coords)
        center_of_mass
    #> [1] -36.75 -22.75  14.80

## Converting an ROI to a SparseNeuroVol

We may want to convert a region of interest to a NeuroVol instance. But we don’t want to store every value in a dense array. Here we can make use of the `SparseNeuroVol` class which only stores non-zero values my using a `Matrix::sparseVector` under the hood.

        sphere <- spherical_roi(vol, c(50,10,10), radius=10, fill=1)
        sphere
    #>
    #>  ROIVol Object
    #>
    #> Properties:
    #>   Dimensions: 85 x 3
    #>   ROI Points: 85
    #>   Value Range: [1.00, 1.00]

Now we construct a `SparseNeuroVol` and fill it with the values stored in the ROI:

        sparsevol <- SparseNeuroVol(sphere, space(vol),indices=indices(sphere))
        sum(sparsevol) == sum(sphere)
    #> [1] TRUE
        all(dim(sparsevol) == dim(vol))
    #> [1] TRUE

## Carrying out simple “searchlight” ROI analyses

The so-called roving “searchlight” is often used to perform multivariate statistical analyses in a local neighborhood of each voxel of an image. Several functions in `neuroim2` can be used to carry out searchlight analyses. These functions produces `list`s of the `ROIVol` instances that encapsulate the local neighborhood around each voxel.

Here, we compute the mean value in an exhaustive set of spherical searchlights in an image volume.

    library(purrr)

    ## generate a list of searchlight ROIs
    slist <- searchlight(vol, eager=TRUE, radius=8)

    ## compute the mean value in each searchlight ROI.
    ret <- slist %>% purrr::map(~ mean(vol[coords(.)]))

We can also use a “randomized searchlight”, which samples voxels without replacement until all voxels have been included in at least one searchlight.

    ret <- vol %>% random_searchlight(radius=8) %>% purrr::map(~ mean(vol[coords(.)]))

Another related method involves using a “parcellation” or clustering to define successive regions of interest for an analysis. Here we show how to do this in a similar way as above. First we must define a ‘clustering’ over the voxel space:

    grid <- index_to_coord(vol, which(vol > 0))
    kres <- kmeans(grid, centers=50, iter.max=500)

Now we create a `ClusteredNeuroVol` and map the `mean` function over all clusters:

    kvol <- ClusteredNeuroVol(vol, kres$cluster)
    ret <- vol %>% clustered_searchlight(cvol=kvol) %>% purrr::map(~ mean(vol[coords(.)]))

## Working with image patches

Another type of ROI analysis, similar to the ‘searchlight’, involves working with sets of square or cuboid image “patches”. The `patch_set` function can be used to generate a set of equally-sized patches that span the image space (or some mask covering the space). The patches are guaranteed to be of equal size. This means that at edges, ‘patches’ will be padded out with the value at the image extremes.

Here we create a patch set consistting of 3 by 3 by 1 square patches that span the image.

    pset <- patch_set(vol, dims=c(3,3,1))
    length(pset)
    #> [1] 102400
    ret <- pset %>% purrr::map(~ mean(.))

Now we limit patches so that the set of patch centers are within a mask.

    pset <- patch_set(vol, dims=c(3,3,1), mask=as.logical(vol))
    length(pset)
    #> [1] 29532
    ret <- pset %>% purrr::map(~ mean(.))