From f9f2bc05d0768dacd9edd9ccd6af3a50db03540e Mon Sep 17 00:00:00 2001 From: mdesco Date: Mon, 23 Oct 2023 14:38:25 -0400 Subject: [PATCH 1/6] added dwi and utils --- scilpy/dwi/utils.py | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 scilpy/dwi/utils.py diff --git a/scilpy/dwi/utils.py b/scilpy/dwi/utils.py new file mode 100644 index 000000000..fbc15372e --- /dev/null +++ b/scilpy/dwi/utils.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + + + From ae4523d40f3795106206ff2fbcd38f9492daa211 Mon Sep 17 00:00:00 2001 From: mdesco Date: Mon, 23 Oct 2023 14:42:27 -0400 Subject: [PATCH 2/6] moving functions to module dwi --- scilpy/dwi/utils.py | 27 +++++++++++++++++++++++ scripts/scil_apply_bias_field_on_dwi.py | 29 +++---------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/scilpy/dwi/utils.py b/scilpy/dwi/utils.py index fbc15372e..84929334f 100644 --- a/scilpy/dwi/utils.py +++ b/scilpy/dwi/utils.py @@ -1,4 +1,31 @@ # -*- coding: utf-8 -*- +import numpy as np + + +def rescale_intensity(val, slope, in_max, bc_max): + return in_max - slope * (bc_max - val) + + +# https://github.com/stnava/ANTs/blob/master/Examples/N4BiasFieldCorrection.cxx +def rescale_dwi(in_data, bc_data): + in_min = np.amin(in_data) + in_max = np.amax(in_data) + bc_min = np.amin(bc_data) + bc_max = np.amax(bc_data) + + slope = (in_max - in_min) / (bc_max - bc_min) + + chunk = np.arange(0, len(in_data), 100000) + chunk = np.append(chunk, len(in_data)) + for i in range(len(chunk)-1): + nz_bc_data = bc_data[chunk[i]:chunk[i+1]] + rescale_func = np.vectorize(_rescale_intensity, otypes=[np.float32]) + + rescaled_data = rescale_func(nz_bc_data, slope, in_max, bc_max) + bc_data[chunk[i]:chunk[i+1]] = rescaled_data + + return bc_data + diff --git a/scripts/scil_apply_bias_field_on_dwi.py b/scripts/scil_apply_bias_field_on_dwi.py index 2d2712f27..dbead2f5a 100755 --- a/scripts/scil_apply_bias_field_on_dwi.py +++ b/scripts/scil_apply_bias_field_on_dwi.py @@ -16,6 +16,8 @@ from scilpy.io.utils import (add_overwrite_arg, assert_inputs_exist, assert_outputs_exist) +from scilpy.dwi.utils import (rescale_intensity, + rescale_dwi) def _build_arg_parser(): @@ -35,31 +37,6 @@ def _build_arg_parser(): return p -def _rescale_intensity(val, slope, in_max, bc_max): - return in_max - slope * (bc_max - val) - - -# https://github.com/stnava/ANTs/blob/master/Examples/N4BiasFieldCorrection.cxx -def _rescale_dwi(in_data, bc_data): - in_min = np.amin(in_data) - in_max = np.amax(in_data) - bc_min = np.amin(bc_data) - bc_max = np.amax(bc_data) - - slope = (in_max - in_min) / (bc_max - bc_min) - - chunk = np.arange(0, len(in_data), 100000) - chunk = np.append(chunk, len(in_data)) - for i in range(len(chunk)-1): - nz_bc_data = bc_data[chunk[i]:chunk[i+1]] - rescale_func = np.vectorize(_rescale_intensity, otypes=[np.float32]) - - rescaled_data = rescale_func(nz_bc_data, slope, in_max, bc_max) - bc_data[chunk[i]:chunk[i+1]] = rescaled_data - - return bc_data - - def main(): parser = _build_arg_parser() args = parser.parse_args() @@ -82,7 +59,7 @@ def main(): nuc_dwi_data = np.divide(dwi_data[nz_mask_data], bias_field_data[nz_mask_data].reshape((len(nz_mask_data[0]), 1))) - rescaled_nuc_data = _rescale_dwi(dwi_data[nz_mask_data], + rescaled_nuc_data = rescale_dwi(dwi_data[nz_mask_data], nuc_dwi_data) dwi_data[nz_mask_data] = rescaled_nuc_data From 9eee1f4ddc468ca2eae74f128d20286ff4c08a4e Mon Sep 17 00:00:00 2001 From: mdesco Date: Mon, 23 Oct 2023 14:45:25 -0400 Subject: [PATCH 3/6] making test pass --- scilpy/dwi/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scilpy/dwi/utils.py b/scilpy/dwi/utils.py index 84929334f..4ece78c21 100644 --- a/scilpy/dwi/utils.py +++ b/scilpy/dwi/utils.py @@ -3,7 +3,7 @@ import numpy as np -def rescale_intensity(val, slope, in_max, bc_max): +def _rescale_intensity(val, slope, in_max, bc_max): return in_max - slope * (bc_max - val) From 89c8057220557fefe17580d4e7a5b8efcf7af9be Mon Sep 17 00:00:00 2001 From: mdesco Date: Mon, 23 Oct 2023 14:46:24 -0400 Subject: [PATCH 4/6] wip --- scripts/scil_apply_bias_field_on_dwi.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/scil_apply_bias_field_on_dwi.py b/scripts/scil_apply_bias_field_on_dwi.py index dbead2f5a..b9cf0acb1 100755 --- a/scripts/scil_apply_bias_field_on_dwi.py +++ b/scripts/scil_apply_bias_field_on_dwi.py @@ -16,8 +16,7 @@ from scilpy.io.utils import (add_overwrite_arg, assert_inputs_exist, assert_outputs_exist) -from scilpy.dwi.utils import (rescale_intensity, - rescale_dwi) +from scilpy.dwi.utils import rescale_dwi def _build_arg_parser(): From d92b167fc4a5baec0c5ceea57cf8e09cab8b348c Mon Sep 17 00:00:00 2001 From: mdesco Date: Mon, 23 Oct 2023 14:49:39 -0400 Subject: [PATCH 5/6] pep8 de marde --- scilpy/dwi/utils.py | 3 --- scripts/scil_apply_bias_field_on_dwi.py | 7 ++++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/scilpy/dwi/utils.py b/scilpy/dwi/utils.py index 4ece78c21..51ffc40e1 100644 --- a/scilpy/dwi/utils.py +++ b/scilpy/dwi/utils.py @@ -26,6 +26,3 @@ def rescale_dwi(in_data, bc_data): bc_data[chunk[i]:chunk[i+1]] = rescaled_data return bc_data - - - diff --git a/scripts/scil_apply_bias_field_on_dwi.py b/scripts/scil_apply_bias_field_on_dwi.py index b9cf0acb1..5548b8e08 100755 --- a/scripts/scil_apply_bias_field_on_dwi.py +++ b/scripts/scil_apply_bias_field_on_dwi.py @@ -55,11 +55,12 @@ def main(): else: nz_mask_data = np.nonzero(np.average(dwi_data, axis=-1)) - nuc_dwi_data = np.divide(dwi_data[nz_mask_data], - bias_field_data[nz_mask_data].reshape((len(nz_mask_data[0]), 1))) + nuc_dwi_data = np.divide( + dwi_data[nz_mask_data], + bias_field_data[nz_mask_data].reshape((len(nz_mask_data[0]), 1))) rescaled_nuc_data = rescale_dwi(dwi_data[nz_mask_data], - nuc_dwi_data) + nuc_dwi_data) dwi_data[nz_mask_data] = rescaled_nuc_data nib.save(nib.Nifti1Image(dwi_data, dwi_img.affine, From c75d5bdff5bb82e58b46c85efb19fa824672f2ad Mon Sep 17 00:00:00 2001 From: mdesco Date: Mon, 23 Oct 2023 15:52:59 -0400 Subject: [PATCH 6/6] added docstring --- scilpy/dwi/utils.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/scilpy/dwi/utils.py b/scilpy/dwi/utils.py index 51ffc40e1..626caca14 100644 --- a/scilpy/dwi/utils.py +++ b/scilpy/dwi/utils.py @@ -4,11 +4,53 @@ def _rescale_intensity(val, slope, in_max, bc_max): + """ + Rescale an intensity value given a scaling factor. + This scaling factor ensures that the intensity + range before and after correction is the same. + + Parameters + ---------- + val: float + Value to be scaled + scale: float + Scaling factor to be applied + in_max: float + Max possible value + bc_max: float + Max value in the bias correction value range + + Returns + ------- + rescaled_value: float + Bias field corrected value scaled by the slope + of the data + """ + return in_max - slope * (bc_max - val) # https://github.com/stnava/ANTs/blob/master/Examples/N4BiasFieldCorrection.cxx def rescale_dwi(in_data, bc_data): + """ + Apply N4 Bias Field Correction to a DWI volume. + bc stands for bias correction. The code comes + from the C++ ANTS implmentation. + + Parameters + ---------- + in_data: ndarray (x, y, z, ndwi) + Input DWI volume 4-dimensional data. + bc_data: ndarray (x, y, z, ndwi) + Bias field correction volume estimated from ANTS + Copied for every dimension of the DWI 4-th dimension + + Returns + ------- + bc_data: ndarray (x, y, z, ndwi) + Bias field corrected DWI volume + """ + in_min = np.amin(in_data) in_max = np.amax(in_data) bc_min = np.amin(bc_data)