Especially for MRI, the pixel values can vary between scanner types. This will lead to a very differnt range of pixel intensities across images in the same batch and the algorithms will have a hard time converging. Various techniques for rescaling exist, of which some are implemented here.
@patch
def show_L(l:L, **kwargs):
"shows all Tensors in L"
show_images_3d(torch.stack(tuple(l)), **kwargs)
@patch
def apply(l:L, fun):
"applies a function to each element of L"
return L(fun(item) for item in l)
fns = Path('../data/series').ls()
images = L(TensorDicom3D.create(fn) for fn in fns)
images.show_L(nrow = 15)
Size correction
If working with data from different scanners and even different sequences, pixel spacing can differ. E.g. T2w images are usually in a higher resolution as DWI images, thus the size of each individual pixel is larger in DWI images than in T2W. Normalizing pixel size to a standartized value can help achiving better performance. However, only the H x W dimension is rescaled, not the D dimension.
from faimed3d.basics import TensorDicom3D, TensorMask3D # for compatibility with show_docs
[im.get_spacing() for im in images]
from faimed3d.basics import TensorDicom3D # for compatibility with show_docs
im = images[0]
print(im.mean())
# the example MRI images have no rescale slope or intercept
im.set_metadata('0028|1052', 5.)
im.set_metadata('0028|1053', 0.5)
im = im.rescale_pixeldata()
im.mean()
images.apply(MeanScale()).show_L(nrow = 15)
However, just scaling with one mean (or median) and std (or IQR) might not be the optimal solution. Histogram scaling can be used for a more even distribution of pixel values. Different functions are provided for histogram scaling:
Method adapted from Jeremy Howard
See the excellent Kaggle kernel from Jeremy Howard for an explanation.
from torch import Tensor # for compatibility with show_docs
The sample data from radiopaedia is already windowed and scaled, so the results presented here are not very impressive. However, if applied to MRI data, changes will be stronger.
def f(x): return x.hist_scaled()
images.apply(f).show_L(nrow = 15)
im1 = TensorDicom3D(images[0][10:20])
image = sitk.Cast(im1.as_sitk(), sitk.sitkFloat32)
output = sitk.AdaptiveHistogramEqualization(image, radius=[20]*3, alpha=0.3, beta=0.3) # ~ 30-60 seconds
TensorDicom3D(sitk.GetArrayFromImage(output)).show()
im1.hist_scaled().show()
N4 bias field correction
from official SimpleITK docs
The N4 bias field correction algorithm is a popular method for correcting low frequency intensity non-uniformity present in MRI image data known as a bias or gain field. The method has also been successfully applied as flat-field correction in microscopy data. This method assumes a simple parametric model and does not require tissue classification.
corrector = sitk.N4BiasFieldCorrectionImageFilter()
corrector.SetMaximumNumberOfIterations([3]*3)
output = corrector.Execute(sitk.Cast(im1.as_sitk(), sitk.sitkFloat32)) # needs float
TensorDicom3D(sitk.GetArrayFromImage(output)).show() #
faimed3d
provides a wrapper class to apply both N4 bias field correction and adaptive histogram equalization, which basically just simplifies reading the data.
Piecewise linear histogram matching
[1] N. Laszlo G and J. K. Udupa, “On Standardizing the MR Image Intensity Scale,” Magn. Reson. Med., vol. 42, pp. 1072–1081, 1999.
[2] M. Shah, Y. Xiao, N. Subbanna, S. Francis, D. L. Arnold, D. L. Collins, and T. Arbel, “Evaluating intensity normalization on MRIs of human brain with multiple sclerosis,” Med. Image Anal., vol. 15, no. 2, pp. 267–282, 2011.
Implementation adapted from: https://github.com/jcreinhold/intensity-normalization, ported to pytorch (no use of numpy works in cuda).
In contrast to hist_scaled
, the piecewise linear histogram matching need pre-specified values for new scale and landmarks. It should be used to normalize a whole dataset.
standard_scale, percs = find_standard_scale(images)
standard_scale, percs
images.apply(PiecewiseHistScaling(landmark_percs=percs,
standard_scale=standard_scale)).show_L(nrow = 15)
from fastai.data.core import DataLoaders # for compatibility with show_docs