Chapter 6 Stitching
Stitching is the task of aligning adjacent overlapping FOVs, to obtain a coherent coordinate system across all FOVs. It can be done on DAPI images, or on the reference bit in MERFISH (i.e. the image that registration is performed with respect to – typically the first bit). It can thus be done in parallel with the previous two tasks.
Alternatively, recall that as part of spotcalling (Chapter 3.4.2) and cell segmentation (Chapter 5.4), reference images are returned as REGIM_{ FOV Name }.png
. Users may wish to use these instead; and so stitching will have to be performed after the previous two tasks.
library(masmr)
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.2
6.1 Pre-processing
Parameters established as before.
= 'C:/Users/kwaje/Downloads/JIN_SIM/20190718_WK_T2_a_B2_R8_12_d50/'
data_dir establishParams(
imageDirs = paste0(data_dir, 'S10/'),
imageFormat = '.ome.tif',
codebookFileName = list.files(paste0(data_dir, 'codebook/'), pattern='codebook', full.names = TRUE),
codebookColumnNames = paste0(rep(c(0:3), 4), '_', rep(c('cy3', 'alexa594', 'cy5', 'cy7'), each=4) ),
outDir = 'C:/Users/kwaje/Downloads/JYOUT/',
dapiDir = paste0(data_dir, 'DAPI_1/'),
pythonLocation = 'C:/Users/kwaje/AppData/Local/miniforge3/envs/scipyenv/',
fpkmFileName = paste0(data_dir, "FPKM_data/Jin_FPKMData_B.tsv"),
nProbesFileName = paste0(data_dir, "ProbesPerGene.csv"),
verbose = FALSE
)
## Assuming .ome.tif is extension for meta files...
At this stage, relevant metadata files (META_RESOLUTION.txt
and GLOBALCOORD.csv
) should have been created for both DAPI and MERFISH data using the readImageMetaData
function (see previous Chapters). This is the minimum requirement for stitching with masmr
. [Both are generated early in their respective pipelines.]
There should thus be two subdirectories as this stage, one for MERFISH data and one for DAPI data. Both should have the metadata files.
list.files( params$parent_out_dir, pattern = 'GLOBALCOORD.csv', recursive = T, full.names = T )
## [1] "C:/Users/kwaje/Downloads/JYOUT/DAPI/GLOBALCOORD.csv"
## [2] "C:/Users/kwaje/Downloads/JYOUT/IM/GLOBALCOORD.csv"
list.files( params$parent_out_dir, pattern = 'META_RESOLUTION.txt', recursive = T, full.names = T )
## [1] "C:/Users/kwaje/Downloads/JYOUT/DAPI/META_RESOLUTION.txt"
## [2] "C:/Users/kwaje/Downloads/JYOUT/IM/META_RESOLUTION.txt"
6.2 Loading images for stitching
For stitching, we will need to load a reference FOV, and the FOVs immediately surrounding it. For instance, let’s select the same FOV processed in previous Chapters. From one of the GLOBALCOORD.csv
files, we expect to load the four FOVs in blue below, alongside our reference FOV (red).
$current_fov <- 'MMStack_1-Pos_002_003'
params<- data.table::fread(
gcx list.files( params$parent_out_dir, pattern = 'GLOBALCOORD.csv', recursive = T, full.names = T )[1],
data.table = F
)<- gcx[!duplicated(gcx$fov),]
gcx $X <- as.integer( factor(gcx$x_microns) )
gcx$Y <- as.integer( factor(gcx$y_microns) )
gcx$CX <- gcx$X + 1i * gcx$Y
gcx$fov_type <- ifelse(
gcx$fov==params$current_fov, 'Reference',
gcxifelse(
Mod( gcx$CX - gcx$CX[gcx$fov==params$current_fov] ) == 1,
'Neighbour', 'Other'))
$short_name <- gsub('MMStack_1-Pos_|00', '', gcx$fov)
gcxggplot( gcx ) +
geom_text( aes(x=x_microns, y=y_microns, label=short_name, colour = fov_type),
size = 5 ) +
scale_colour_manual( name='', values = c('Reference' = 'red', 'Neighbour' = 'blue', 'Other' = 'black')) +
scale_y_reverse() + xlab('X (microns)') + ylab('Y (microns)') +
theme_minimal(base_size=14)
The actual loading is accomplished with the readImagesForStitch
function. The default is to load MERFISH images.
## params$current_fov specifies which image to load
<- readImagesForStitch()
imList par(mfrow=c(2,3))
for(i in 1:length(imList)){
plot(imager::as.cimg(imList[[i]]), main=names(imList)[i])
}
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
par(mfrow = c(1,1))
The subDirectory
parameter allows for easy swapping between DAPI and MERFISH images.
<- readImagesForStitch( subDirectory = 'DAPI' )
imList par(mfrow=c(2,3))
for(i in 1:length(imList)){
plot(imager::as.cimg(imList[[i]]), main=names(imList)[i])
}
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
par(mfrow = c(1,1))
<- imList dapiList
Every time readImagesForStitch
is run, a stitchParams
environment object is generated. This functions similarly to params
: it houses parameters for image handling and file saving. It also copies params$current_fov
[It is separate from params
owing to users possibly wishing to handle both MERFISH and DAPI images.]
ls( envir = stitchParams )
## [1] "current_fov" "fov_names"
## [3] "fovs_loaded" "global_coords"
## [5] "im_format" "out_dir"
## [7] "processed_images_loaded" "resolutions"
## [9] "sub_directory" "verbose"
From above, it is apparent that raw MERFISH images may require some image processing prior to stitching (e.g. brightening of image). We recommend the same image processing as done during image registration (Chapter 3.4.2).
If stitching is done after spotcalling is complete for all FOVs, processed images for the reference bit are accessible by setting loadProcessedImages
to TRUE
. As default, the loadProcessedImages
parameter is FALSE
. If TRUE
, the function will first attempt to search for REGIM_{ FOV Name }.png
images and load those instead. If unable to, loadProcessedImages
is switched back to FALSE
, and raw images loaded instead (failure to find processed images returned as a warning).
Otherwise, we can reprocess the raw images by specifying the imageFunction
parameter. [The minimum and maximum brightness below come from outputs of getAnchorParams
; this done early during the spotcalling pipeline (see Chapter 3.2.2).]
<- function( im ){
imFunction
= 0.0370383157674109 #First bit floor
minBrightness = 0.288414576071673 #First bit cap
maxBrightness
<-
norm imLowPass(im, floorVal = minBrightness, ceilVal = maxBrightness) +
imForDecode(im, floorVal = minBrightness, ceilVal = maxBrightness)
<- imNormalise(norm)
norm
return( norm )
}
<- readImagesForStitch( subDirectory = 'IM', imageFunction = imFunction)
imList par(mfrow=c(2,3))
for(i in 1:length(imList)){
plot(imager::as.cimg(imList[[i]]), main=names(imList)[i])
}
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
## Warning in as.cimg.array(imList[[i]]): Assuming third dimension corresponds to
## time/depth
par(mfrow = c(1,1))
<- imList merList
6.3 Performing stitching
The task of stitching is similar to image registration and our stitching algorithm stitchImages
similarly relies on cross-correlation to a reference image. As default, the first image in the list – which should also be the current FOV being processed – is used.
<- stitchImages(merList) stitchResults
## Warning in stitchImages(merList): Z stack detected...Defaulting to MIP...
::kable(stitchResults, format = 'html', booktabs = T) knitr
fov | shift_pixel |
---|---|
MMStack_1-Pos_001_003 | -2673+27i |
MMStack_1-Pos_002_002 | -28-2651i |
MMStack_1-Pos_002_004 | 26+2660i |
MMStack_1-Pos_003_003 | 2657-27i |
Users may wish to stitch both DAPI and MERFISH images to compare.
## Keep the old stitch vector
<- stitchResults
df colnames(df)[2] <- paste0('merfish_', colnames(stitchResults)[2])
## Re-run stitching but with DAPI images
<- stitchImages(dapiList, returnTroubleShootPlots = TRUE) stitchResults
## Warning in stitchImages(dapiList, returnTroubleShootPlots = TRUE): Z stack
## detected...Defaulting to MIP...
colnames(stitchResults)[2] <- paste0('dapi_', colnames(stitchResults)[2])
colnames(df)[2]] <- df[match(stitchResults[,1], df[,1]),2]
stitchResults[,::kable(stitchResults, format = 'html', booktabs = T) knitr
fov | dapi_shift_pixel | merfish_shift_pixel |
---|---|---|
MMStack_1-Pos_001_003 | -2664+25i | -2673+27i |
MMStack_1-Pos_002_002 | -25-2664i | -28-2651i |
MMStack_1-Pos_002_004 | 27+2664i | 26+2660i |
MMStack_1-Pos_003_003 | 2664-27i | 2657-27i |
Stitching can be evaluated visually. These can be obtained by setting returnTroubleShootPlots
in stitchImages
to TRUE
, or through manual use of the stitch_troubleshootPlots
function (see documentation). The reference FOV is shown in red, while the neighbour is in blue.
## Plots are returned for each neihgbour, will show just one below
<- troubleshootPlots[['STITCH_EVAL']][[4]][['UNSTITCHED']]
p_unstitched <- troubleshootPlots[['STITCH_EVAL']][[4]][['STITCHED']]
p_stitched
## Re-scale alpha so that low brightness is more solid
## We find this makes the stitch visually clearer for DAPI images
::plot_grid( plotlist = list(
cowplot+ ggtitle('Unstitched') + scale_alpha(range=c(0.75, 0)),
p_unstitched + ggtitle('Stitched') + scale_alpha(range=c(0.75, 0))
p_stitched nrow=1) ),
6.4 Saving stitch vectors
Finally, users may save the dataframe output using the saveStitch
function. This is strictly not necessary, but is recommended, as it would ensure standardised file names and compatability with the rest of masmr
.
saveStitch( stitchResults )
file.exists( paste0(stitchParams$out_dir, 'STITCH_', stitchParams$current_fov, '.csv') )
## [1] TRUE