Permalink
Browse files

Added the reporting of quality metric values.

1) The distance between the images after registration is reported.
2) The metric of optiaml parameters is reported during the workflow.
3) The quality assurance metric can be saved optionally by the user.

4) Tested the workflows on simulated (coronal slice dataset) and real datasets (stanford hardi).
  • Loading branch information...
Parichit Sharma
Parichit Sharma committed Jul 1, 2018
1 parent c3b4786 commit 94c8b8fbf0b84d48ce46b31eae58a6457239b1b6
Showing with 123 additions and 48 deletions.
  1. +14 −1 dipy/align/imaffine.py
  2. +24 −1 dipy/io/image.py
  3. +66 −35 dipy/workflows/align.py
  4. +1 −1 dipy/workflows/flow_runner.py
  5. +18 −10 dipy/workflows/tests/test_align.py
@@ -954,7 +954,7 @@ def _init_optimizer(self, static, moving, transform, params0,

def optimize(self, static, moving, transform, params0,
static_grid2world=None, moving_grid2world=None,
starting_affine=None):
starting_affine=None, ret_metric=False):
r''' Starts the optimization process
Parameters
@@ -993,11 +993,22 @@ def optimize(self, static, moving, transform, params0,
If None:
Start from identity.
The default is None.
ret_metric : boolean, optional
if True, it returns the parameters for measuring the
similarity between the images (default 'False').
The metric containing optimal parameters and
the distance between the images.
Returns
-------
affine_map : instance of AffineMap
the affine resulting affine transformation
xopt : similarity metric
the metric of optimal parameters
fopt : distance
the distance between the images
'''
self._init_optimizer(static, moving, transform, params0,
static_grid2world, moving_grid2world,
@@ -1074,6 +1085,8 @@ def optimize(self, static, moving, transform, params0,
self.params0 = self.transform.get_identity_parameters()

affine_map.set_affine(self.starting_affine)
if ret_metric:
return affine_map, opt.xopt, opt.fopt
return affine_map


@@ -31,9 +31,32 @@ def save_affine_matrix(fname, affine):
"""
Parameters
---------
fname : str
fname : string
File name to save the affine matrix.
affine : numpy array
The object containing the affine matrix.
"""
np.savetxt(fname, affine)


def save_quality_assur_metric(fname, xopt, fopt):
"""
Parameters
__________
fname: string
File name to save the metric values.
xopt: numpy array
The metric containing the
optimal parameters for
image registration.
fopt: int
The distance between the registered images.
"""
np.savetxt(fname, xopt, header="Optimal Parameter metric")
with open(fname,'a') as f:
f.write('# Distance after registration\n')
f.write(str(fopt))




@@ -10,7 +10,7 @@
MutualInformationMetric, AffineRegistration)
from dipy.align.transforms import (TranslationTransform3D, RigidTransform3D,
AffineTransform3D)
from dipy.io.image import save_nifti, save_affine_matrix
from dipy.io.image import save_nifti, save_affine_matrix, save_quality_assur_metric


class ResliceFlow(Workflow):
@@ -163,13 +163,16 @@ def translate(self, static, static_grid2world, moving,
transform = TranslationTransform3D()
starting_affine = affine

img_registration = affreg.optimize(static, moving, transform,
params0, static_grid2world,
moving_grid2world,
starting_affine=starting_affine)
img_registration, xopt, fopt = affreg.optimize(static, moving,
transform, params0,
static_grid2world,
moving_grid2world,
starting_affine=
starting_affine,
ret_metric=True)

transformed = img_registration.transform(moving)
return transformed, img_registration.affine
return transformed, img_registration.affine, xopt, fopt

def rigid(self, static, static_grid2world, moving, moving_grid2world,
affreg, params0, progressive):
@@ -213,31 +216,32 @@ def rigid(self, static, static_grid2world, moving, moving_grid2world,
"""

if progressive:
moved, affine = self.translate(static,
static_grid2world,
moving, moving_grid2world,
affreg, params0)
moved, affine, xopt, fopt = self.translate(static,
static_grid2world,
moving,
moving_grid2world,
affreg, params0)

else:
moved, affine = self.center_of_mass(static,
static_grid2world,
moving,
moving_grid2world)
moved, affine = self.center_of_mass(static, static_grid2world,
moving, moving_grid2world)

transform = RigidTransform3D()
starting_affine = affine

img_registration = affreg.optimize(static, moving, transform,
params0, static_grid2world,
moving_grid2world,
starting_affine=starting_affine)
img_registration, xopt, fopt = affreg.optimize(static, moving,
transform, params0,
static_grid2world,
moving_grid2world,
starting_affine=
starting_affine,
ret_metric=True)

transformed = img_registration.transform(moving)
return transformed, img_registration.affine
return transformed, img_registration.affine, xopt, fopt

def affine(self, static, static_grid2world, moving, moving_grid2world,
affreg, params0,
progressive):
affreg, params0, progressive):

""" Function for full affine registration.
@@ -277,7 +281,7 @@ def affine(self, static, static_grid2world, moving, moving_grid2world,
"""
if progressive:
moved, affine = self.rigid(static, static_grid2world,
moved, affine, xopt, fopt = self.rigid(static, static_grid2world,
moving, moving_grid2world,
affreg, params0, progressive)

@@ -288,13 +292,16 @@ def affine(self, static, static_grid2world, moving, moving_grid2world,
transform = AffineTransform3D()
starting_affine = affine

img_registration = affreg.optimize(static, moving, transform,
params0, static_grid2world,
moving_grid2world,
starting_affine=starting_affine)
img_registration, xopt, fopt = affreg.optimize(static, moving,
transform, params0,
static_grid2world,
moving_grid2world,
starting_affine=
starting_affine,
ret_metric=True)

transformed = img_registration.transform(moving)
return transformed, img_registration.affine
return transformed, img_registration.affine, xopt, fopt

@staticmethod
def check_dimensions(static, moving):
@@ -338,8 +345,9 @@ def check_metric(metric):
def run(self, static_img_file, moving_img_file, transform='affine',
nbins=32, sampling_prop=None, metric='mi',
level_iters=[10000, 1000, 100], sigmas=[3.0, 1.0, 0.0],
factors=[4, 2, 1], progressive=True, out_dir='',
out_moved='moved.nii.gz', out_affine='affine.txt'):
factors=[4, 2, 1], progressive=True, save_metric=True,
out_dir='', out_moved='moved.nii.gz', out_affine='affine.txt',
out_quality='quality_metric.txt'):

"""
Parameters
@@ -392,6 +400,17 @@ def run(self, static_img_file, moving_img_file, transform='affine',
Flag for enabling/disabling the progressive registration.
(default 'True')
save_metric : boolean, optional
If true, the metric values are
saved in a file called 'quality_metric.txt'
(default 'False')
By default, the similarity measure
values such as the distance and the
metric of optimal parameters is only
displayed but not saved.
out_dir : string, optional
Directory to save the transformed image and the affine matrix.
(default '')
@@ -404,14 +423,19 @@ def run(self, static_img_file, moving_img_file, transform='affine',
Name for the saved affine matrix.
(default 'affine.txt')
out_quality : string, optional
Name of the file containing the saved quality
metrices (default 'quality_metric.txt')
"""

"""
setting up the io iterator to gobble the input and output paths
"""
io_it = self.get_io_iterator()

for static_img, mov_img, moved_file, affine_matrix_file in io_it:

for static_img, mov_img, moved_file, affine_matrix_file, qual_val_file in io_it:

"""
Load the data from the input files and store into objects.
@@ -447,22 +471,22 @@ def run(self, static_img_file, moving_img_file, transform='affine',
factors=factors)

if transform.lower() == 'trans':
moved_image, affine = self.translate(static,
moved_image, affine, xopt, fopt = self.translate(static,
static_grid2world,
moving,
moving_grid2world,
affreg, params0)

elif transform.lower() == 'rigid':
moved_image, affine = self.rigid(static,
moved_image, affine, xopt, fopt = self.rigid(static,
static_grid2world,
moving,
moving_grid2world,
affreg, params0,
progressive)

elif transform.lower() == 'affine':
moved_image, affine = self.affine(static,
moved_image, affine, xopt, fopt = self.affine(static,
static_grid2world,
moving,
moving_grid2world,
@@ -478,5 +502,12 @@ def run(self, static_img_file, moving_img_file, transform='affine',
Saving the moved image file and the affine matrix.
"""

save_nifti(moved_file, moved_image, static_grid2world)
save_affine_matrix(affine_matrix_file, affine)
logging.info("Similarity metric:"+str(xopt))
logging.info("Distance measure:"+str(fopt))

if save_metric:
save_quality_assur_metric(qual_val_file, xopt, fopt)

#save_nifti(moved_file, moved_image, static_grid2world)
#save_affine_matrix(affine_matrix_file, affine)

@@ -31,7 +31,7 @@ def run_flow(flow):
help='Force overwriting output files.')

parser.add_argument('--out_strat', action='store', dest='out_strat',
metavar='string', required=False, default='append',
metavar='string', required=False, default='absolute',
help='Strategy to manage output creation.')

parser.add_argument('--mix_names', dest='mix_names',
@@ -39,7 +39,7 @@ def test_reslice():


def test_image_registration():
folder_path = '/Users/schmuck/Documents/register_workflow_test/test'

with TemporaryDirectory() as temp_out_dir:
static, moving, static_g2w, moving_g2w, smask, mmask, M = setup_random_transform(
transform=regtransforms[('AFFINE', 3)], rfactor=0.1)
@@ -62,7 +62,8 @@ def test_image_registration():
transform='com',
out_dir=temp_out_dir
, out_moved=out_moved,
out_affine=out_affine)
out_affine=out_affine,
level_iters="100 10 1")

npt.assert_equal(os.path.exists(out_moved), True)
npt.assert_equal(os.path.exists(out_affine), True)
@@ -75,7 +76,8 @@ def test_image_registration():
transform='trans',
out_dir=temp_out_dir
, out_moved=out_moved,
out_affine=out_affine)
out_affine=out_affine,
level_iters="100 10 1")

npt.assert_equal(os.path.exists(out_moved), True)
npt.assert_equal(os.path.exists(out_affine), True)
@@ -88,7 +90,8 @@ def test_image_registration():
transform='rigid',
out_dir=temp_out_dir
, out_moved=out_moved,
out_affine=out_affine)
out_affine=out_affine,
level_iters="100 10 1")

npt.assert_equal(os.path.exists(out_moved), True)
npt.assert_equal(os.path.exists(out_affine), True)
@@ -101,7 +104,8 @@ def test_image_registration():
transform='affine',
out_dir=temp_out_dir
, out_moved=out_moved,
out_affine=out_affine)
out_affine=out_affine,
level_iters="100 10 1")

npt.assert_equal(os.path.exists(out_moved), True)
npt.assert_equal(os.path.exists(out_affine), True)
@@ -119,14 +123,18 @@ def test_image_registration():
moving_image_file,
metric='wrong_metric')

copy_output(temp_out_dir, folder_path)

# Uncomment for manual debugging
#copy_output(temp_out_dir)

def copy_output(temp_directory_path, folder_path):
out_files = list(glob(pjoin(temp_directory_path, '*.nii.gz')) + glob(pjoin(temp_directory_path, '*.txt')))

for out_file in out_files:
shutil.copy(out_file, folder_path)
# def copy_output(temp_directory_path):
# set the folder_path to the directory where the registered images will be copied.
# folder_path = ''
# out_files = list(glob(pjoin(temp_directory_path, '*.nii.gz')) + glob(pjoin(temp_directory_path, '*.txt')))
#
# for out_file in out_files:
# shutil.copy(out_file, folder_path)


if __name__ == '__main__':

0 comments on commit 94c8b8f

Please sign in to comment.