def test_rotate2d(): # Rotate an image in 2d on a square grid, should result in transposed image g = AffineTransform.from_params('ij', 'xy', np.diag([0.7, 0.5, 1])) g2 = AffineTransform.from_params('ij', 'xy', np.diag([0.5, 0.7, 1])) i = Image(np.ones((100, 100)), g) # This sets the image data by writing into the array i.get_data()[50:55, 40:55] = 3. a = np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]], np.float) ir = resample(i, g2, a, (100, 100)) assert_array_almost_equal(ir.get_data().T, i.get_data())
def test_rotate3d(): # Rotate / transpose a 3d image on a non-square grid g = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5, 0.6, 0.7, 1])) g2 = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5, 0.7, 0.6, 1])) shape = (100, 90, 80) i = Image(np.ones(shape), g) i.get_data()[50:55, 40:55, 30:33] = 3. a = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1.]]) ir = resample(i, g2, a, (100, 80, 90)) assert_array_almost_equal(np.transpose(ir.get_data(), (0, 2, 1)), i.get_data())
def test_rotate2d(): # Rotate an image in 2d on a square grid, should result in transposed image g = AffineTransform.from_params('ij', 'xy', np.diag([0.7,0.5,1])) g2 = AffineTransform.from_params('ij', 'xy', np.diag([0.5,0.7,1])) i = Image(np.ones((100,100)), g) # This sets the image data by writing into the array i.get_data()[50:55,40:55] = 3. a = np.array([[0,1,0], [1,0,0], [0,0,1]], np.float) ir = resample(i, g2, a, (100, 100)) assert_array_almost_equal(ir.get_data().T, i.get_data())
def test_rotate2d2(): # Rotate an image in 2d on a non-square grid, # should result in transposed image g = AffineTransform.from_params("ij", "xy", np.diag([0.7, 0.5, 1])) g2 = AffineTransform.from_params("ij", "xy", np.diag([0.5, 0.7, 1])) i = Image(np.ones((100, 80)), g) i[50:55, 40:55] = 3.0 a = np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]], np.float) ir = resample(i, g2, a, (80, 100)) yield assert_array_almost_equal, np.asarray(ir).T, i
def test_rotate3d(): # Rotate / transpose a 3d image on a non-square grid g = AffineTransform.from_params("ijk", "xyz", np.diag([0.5, 0.6, 0.7, 1])) g2 = AffineTransform.from_params("ijk", "xyz", np.diag([0.5, 0.7, 0.6, 1])) shape = (100, 90, 80) i = Image(np.ones(shape), g) i[50:55, 40:55, 30:33] = 3.0 a = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1.0]]) ir = resample(i, g2, a, (100, 80, 90)) yield assert_array_almost_equal, np.transpose(np.asarray(ir), (0, 2, 1)), i
def test_rotate3d(): # Rotate / transpose a 3d image on a non-square grid g = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5,0.6,0.7,1])) g2 = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5,0.7,0.6,1])) shape = (100,90,80) i = Image(np.ones(shape), g) i.get_data()[50:55,40:55,30:33] = 3. a = np.array([[1,0,0,0], [0,0,1,0], [0,1,0,0], [0,0,0,1.]]) ir = resample(i, g2, a, (100,80,90)) assert_array_almost_equal(np.transpose(ir.get_data(), (0,2,1)), i.get_data())
def test_nonaffine(): # resamples an image along a curve through the image. # # FIXME: use the reference.evaluate.Grid to perform this nicer # FIXME: Remove pylab references def curve(x): # function accept N by 1, returns N by 2 return (np.vstack([5 * np.sin(x.T), 5 * np.cos(x.T)]).T + [52, 47]) for names in (('xy', 'ij', 't', 'u'), ('ij', 'xy', 't', 's')): in_names, out_names, tin_names, tout_names = names g = AffineTransform.from_params(in_names, out_names, np.identity(3)) img = Image(np.ones((100, 90)), g) img.get_data()[50:55, 40:55] = 3. tcoordmap = AffineTransform.from_start_step(tin_names, tout_names, [0], [np.pi * 1.8 / 100]) ir = resample(img, tcoordmap, curve, (100, )) if gui_review: import pylab pylab.figure(num=3) pylab.imshow(img, interpolation='nearest') d = curve(np.linspace(0, 1.8 * np.pi, 100)) pylab.plot(d[0], d[1]) pylab.gca().set_ylim([0, 99]) pylab.gca().set_xlim([0, 89]) pylab.figure(num=4) pylab.plot(ir.get_data())
def test_slice_from_3d(): # Resample a 3d image, returning a zslice, yslice and xslice # # This example creates a coordmap that coincides with # a given z, y, or x slice of an image, and checks that # resampling agrees with the data in the given slice. shape = (100,90,80) g = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5,0.5,0.5,1])) img = Image(np.ones(shape), g) img.get_data()[50:55,40:55,30:33] = 3 I = np.identity(4) zsl = slices.zslice(26, ((0,49.5), 100), ((0,44.5), 90), img.reference) ir = resample(img, zsl, I, (100, 90)) assert_array_almost_equal(ir.get_data(), img[:,:,53].get_data()) ysl = slices.yslice(22, ((0,49.5), 100), ((0,39.5), 80), img.reference) ir = resample(img, ysl, I, (100, 80)) assert_array_almost_equal(ir.get_data(), img[:,45,:].get_data()) xsl = slices.xslice(15.5, ((0,44.5), 90), ((0,39.5), 80), img.reference) ir = resample(img, xsl, I, (90, 80)) assert_array_almost_equal(ir.get_data(), img[32,:,:].get_data())
def test_nonaffine(): # resamples an image along a curve through the image. # # FIXME: use the reference.evaluate.Grid to perform this nicer # FIXME: Remove pylab references def curve(x): # function accept N by 1, returns N by 2 return np.vstack([5 * np.sin(x.T), 5 * np.cos(x.T)]).T + [52, 47] for names in (("xy", "ij", "t", "u"), ("ij", "xy", "t", "s")): in_names, out_names, tin_names, tout_names = names g = AffineTransform.from_params(in_names, out_names, np.identity(3)) img = Image(np.ones((100, 90)), g) img[50:55, 40:55] = 3.0 tcoordmap = AffineTransform.from_start_step(tin_names, tout_names, [0], [np.pi * 1.8 / 100]) ir = resample(img, tcoordmap, curve, (100,)) if gui_review: import pylab pylab.figure(num=3) pylab.imshow(img, interpolation="nearest") d = curve(np.linspace(0, 1.8 * np.pi, 100)) pylab.plot(d[0], d[1]) pylab.gca().set_ylim([0, 99]) pylab.gca().set_xlim([0, 89]) pylab.figure(num=4) pylab.plot(np.asarray(ir))
def test_resample2d3(): # Same as test_resample2d, only a different way of specifying # the transform: here it is an (A,b) pair g = AffineTransform.from_params('ij', 'xy', np.diag([0.5,0.5,1])) i = Image(np.ones((100,90)), g) i.get_data()[50:55,40:55] = 3. a = np.identity(3) a[:2,-1] = 4. ir = resample(i, i.coordmap, a, (100,90)) assert_array_almost_equal(ir.get_data()[42:47,32:47], 3.)
def test_resample2d2(): g = AffineTransform.from_params('ij', 'xy', np.diag([0.5,0.5,1])) i = Image(np.ones((100,90)), g) i.get_data()[50:55,40:55] = 3. a = np.identity(3) a[:2,-1] = 4. A = np.identity(2) b = np.ones(2)*4 ir = resample(i, i.coordmap, (A, b), (100,90)) assert_array_almost_equal(ir.get_data()[42:47,32:47], 3.)
def test_resample2d2(): g = AffineTransform.from_params('ij', 'xy', np.diag([0.5, 0.5, 1])) i = Image(np.ones((100, 90)), g) i.get_data()[50:55, 40:55] = 3. a = np.identity(3) a[:2, -1] = 4. A = np.identity(2) b = np.ones(2) * 4 ir = resample(i, i.coordmap, (A, b), (100, 90)) assert_array_almost_equal(ir.get_data()[42:47, 32:47], 3.)
def test_resample2d3(): # Same as test_resample2d, only a different way of specifying # the transform: here it is an (A,b) pair g = AffineTransform.from_params("ij", "xy", np.diag([0.5, 0.5, 1])) i = Image(np.ones((100, 90)), g) i[50:55, 40:55] = 3.0 a = np.identity(3) a[:2, -1] = 4.0 ir = resample(i, i.coordmap, a, (100, 90)) yield assert_array_almost_equal, ir[42:47, 32:47], 3.0
def test_resample2d3(): # Same as test_resample2d, only a different way of specifying # the transform: here it is an (A,b) pair g = AffineTransform.from_params('ij', 'xy', np.diag([0.5, 0.5, 1])) i = Image(np.ones((100, 90)), g) i.get_data()[50:55, 40:55] = 3. a = np.identity(3) a[:2, -1] = 4. ir = resample(i, i.coordmap, a, (100, 90)) assert_array_almost_equal(ir.get_data()[42:47, 32:47], 3.)
def test_resample2d2(): g = AffineTransform.from_params("ij", "xy", np.diag([0.5, 0.5, 1])) i = Image(np.ones((100, 90)), g) i[50:55, 40:55] = 3.0 a = np.identity(3) a[:2, -1] = 4.0 A = np.identity(2) b = np.ones(2) * 4 ir = resample(i, i.coordmap, (A, b), (100, 90)) yield assert_array_almost_equal, ir[42:47, 32:47], 3.0
def test_rotate2d3(): # Another way to rotate/transpose the image, similar to # test_rotate2d2 and test_rotate2d, except the world of the # output coordmap is the same as the world of the # original image. That is, the data is transposed on disk, but the # output coordinates are still 'x,'y' order, not 'y', 'x' order as # above # this functionality may or may not be used a lot. if data is to # be transposed but one wanted to keep the NIFTI order of output # coords this would do the trick g = AffineTransform.from_params('xy', 'ij', np.diag([0.5, 0.7, 1])) i = Image(np.ones((100, 80)), g) # This sets the image data by writing into the array i.get_data()[50:55, 40:55] = 3. a = np.identity(3) g2 = AffineTransform.from_params( 'xy', 'ij', np.array([[0, 0.5, 0], [0.7, 0, 0], [0, 0, 1]])) ir = resample(i, g2, a, (80, 100)) assert_array_almost_equal(ir.get_data().T, i.get_data())
def test_rotate2d3(): # Another way to rotate/transpose the image, similar to # test_rotate2d2 and test_rotate2d except the world of the # output coordmap are the same as the world of the # original image. That is, the data is transposed on disk, but the # output coordinates are still 'x,'y' order, not 'y', 'x' order as # above # this functionality may or may not be used a lot. if data is to # be transposed but one wanted to keep the NIFTI order of output # coords this would do the trick g = AffineTransform.from_params("xy", "ij", np.diag([0.5, 0.7, 1])) i = Image(np.ones((100, 80)), g) i[50:55, 40:55] = 3.0 a = np.identity(3) g2 = AffineTransform.from_params("xy", "ij", np.array([[0, 0.5, 0], [0.7, 0, 0], [0, 0, 1]])) ir = resample(i, g2, a, (80, 100)) v2v = compose(g.inverse(), g2) yield assert_array_almost_equal, np.asarray(ir).T, i
def test_rotate2d3(): # Another way to rotate/transpose the image, similar to # test_rotate2d2 and test_rotate2d, except the world of the # output coordmap is the same as the world of the # original image. That is, the data is transposed on disk, but the # output coordinates are still 'x,'y' order, not 'y', 'x' order as # above # this functionality may or may not be used a lot. if data is to # be transposed but one wanted to keep the NIFTI order of output # coords this would do the trick g = AffineTransform.from_params('xy', 'ij', np.diag([0.5,0.7,1])) i = Image(np.ones((100,80)), g) # This sets the image data by writing into the array i.get_data()[50:55,40:55] = 3. a = np.identity(3) g2 = AffineTransform.from_params('xy', 'ij', np.array([[0,0.5,0], [0.7,0,0], [0,0,1]])) ir = resample(i, g2, a, (80,100)) assert_array_almost_equal(ir.get_data().T, i.get_data())
def test_2d_from_3d(): # Resample a 3d image on a 2d affine grid # This example creates a coordmap that coincides with # the 10th slice of an image, and checks that # resampling agrees with the data in the 10th slice. shape = (100, 90, 80) g = AffineTransform.from_params("ijk", "xyz", np.diag([0.5, 0.5, 0.5, 1])) i = Image(np.ones(shape), g) i[50:55, 40:55, 30:33] = 3.0 a = np.identity(4) g2 = ArrayCoordMap.from_shape(g, shape)[10] ir = resample(i, g2.coordmap, a, g2.shape) yield assert_array_almost_equal, np.asarray(ir), np.asarray(i[10])
def test_2d_from_3d(): # Resample a 3d image on a 2d affine grid # This example creates a coordmap that coincides with # the 10th slice of an image, and checks that # resampling agrees with the data in the 10th slice. shape = (100, 90, 80) g = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5, 0.5, 0.5, 1])) i = Image(np.ones(shape), g) i.get_data()[50:55, 40:55, 30:33] = 3. a = np.identity(4) g2 = ArrayCoordMap.from_shape(g, shape)[10] ir = resample(i, g2.coordmap, a, g2.shape) assert_array_almost_equal(ir.get_data(), i[10].get_data())
def test_resample2d1(): # Tests the same as test_resample2d, only using a callable instead of # an AffineTransform instance g = AffineTransform.from_params('ij', 'xy', np.diag([0.5,0.5,1])) i = Image(np.ones((100,90)), g) i.get_data()[50:55,40:55] = 3. a = np.identity(3) a[:2,-1] = 4. A = np.identity(2) b = np.ones(2)*4 def mapper(x): return np.dot(x, A.T) + b ir = resample(i, i.coordmap, mapper, (100,90)) assert_array_almost_equal(ir.get_data()[42:47,32:47], 3.)
def test_resample2d1(): # Tests the same as test_resample2d, only using a callable instead of # an AffineTransform instance g = AffineTransform.from_params('ij', 'xy', np.diag([0.5, 0.5, 1])) i = Image(np.ones((100, 90)), g) i.get_data()[50:55, 40:55] = 3. a = np.identity(3) a[:2, -1] = 4. A = np.identity(2) b = np.ones(2) * 4 def mapper(x): return np.dot(x, A.T) + b ir = resample(i, i.coordmap, mapper, (100, 90)) assert_array_almost_equal(ir.get_data()[42:47, 32:47], 3.)
def test_resample2d(): g = AffineTransform.from_params('ij', 'xy', np.diag([0.5,0.5,1])) i = Image(np.ones((100,90)), g) i.get_data()[50:55,40:55] = 3. # This mapping describes a mapping from the "target" physical # coordinates to the "image" physical coordinates. The 3x3 matrix # below indicates that the "target" physical coordinates are related # to the "image" physical coordinates by a shift of -4 in each # coordinate. Or, to find the "image" physical coordinates, given # the "target" physical coordinates, we add 4 to each "target # coordinate". The resulting resampled image should show the # overall image shifted -8,-8 voxels towards the origin a = np.identity(3) a[:2,-1] = 4. ir = resample(i, i.coordmap, a, (100,90)) assert_array_almost_equal(ir.get_data()[42:47,32:47], 3.)
def test_resample2d(): g = AffineTransform.from_params('ij', 'xy', np.diag([0.5, 0.5, 1])) i = Image(np.ones((100, 90)), g) i.get_data()[50:55, 40:55] = 3. # This mapping describes a mapping from the "target" physical # coordinates to the "image" physical coordinates. The 3x3 matrix # below indicates that the "target" physical coordinates are related # to the "image" physical coordinates by a shift of -4 in each # coordinate. Or, to find the "image" physical coordinates, given # the "target" physical coordinates, we add 4 to each "target # coordinate". The resulting resampled image should show the # overall image shifted -8,-8 voxels towards the origin a = np.identity(3) a[:2, -1] = 4. ir = resample(i, i.coordmap, a, (100, 90)) assert_array_almost_equal(ir.get_data()[42:47, 32:47], 3.)
def test_resample3d(): g = AffineTransform.from_params("ijk", "xyz", np.diag([0.5, 0.5, 0.5, 1])) shape = (100, 90, 80) i = Image(np.ones(shape), g) i[50:55, 40:55, 30:33] = 3.0 # This mapping describes a mapping from the "target" physical # coordinates to the "image" physical coordinates. The 4x4 matrix # below indicates that the "target" physical coordinates are related # to the "image" physical coordinates by a shift of -4 in each # coordinate. Or, to find the "image" physical coordinates, given # the "target" physical coordinates, we add 4 to each "target # coordinate". The resulting resampled image should show the # overall image shifted [-6,-8,-10] voxels towards the origin a = np.identity(4) a[:3, -1] = [3, 4, 5] ir = resample(i, i.coordmap, a, (100, 90, 80)) yield assert_array_almost_equal, ir[44:49, 32:47, 20:23], 3.0
def output_resid(outfile, fmri_image, clobber=False): """ Create an output file of the residuals parameter from the OLS pass of fmristat. Uses affine part of the first image to output resids unless fmri_image is an Image. Parameters ---------- outfile : fmri_image : ``FmriImageList`` or 4D image If ``FmriImageList``, needs attributes ``volume_start_times``, supports len(), and object[0] has attributes ``affine``, ``coordmap`` and ``shape``, from which we create a new 4D coordmap and shape If 4D image, use the images coordmap and shape clobber : bool if True, overwrite previous output Returns ------- regression_output : """ if isinstance(fmri_image, FmriImageList): n = len(fmri_image.list) T = np.zeros((5,5)) g = fmri_image[0].coordmap T[1:,1:] = fmri_image[0].affine T[0,0] = (fmri_image.volume_start_times[1:] - fmri_image.volume_start_times[:-1]).mean() # FIXME: NIFTI specific naming here innames = ["l"] + list(g.input_coords.coord_names) outnames = ["t"] + list(g.output_coords.coord_names) cmap = AffineTransform.from_params(innames, outnames, T) shape = (n,) + fmri_image[0].shape elif isinstance(fmri_image, Image): cmap = fmri_image.coordmap shape = fmri_image.shape else: raise ValueError, "expecting FmriImageList or 4d Image" outim = ModelOutputImage(outfile, cmap, shape, clobber=clobber) return regression.RegressionOutput(outim, regression.output_resid)
def test_resample3d(): g = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5, 0.5, 0.5, 1])) shape = (100, 90, 80) i = Image(np.ones(shape), g) i.get_data()[50:55, 40:55, 30:33] = 3. # This mapping describes a mapping from the "target" physical # coordinates to the "image" physical coordinates. The 4x4 matrix # below indicates that the "target" physical coordinates are related # to the "image" physical coordinates by a shift of -4 in each # coordinate. Or, to find the "image" physical coordinates, given # the "target" physical coordinates, we add 4 to each "target # coordinate". The resulting resampled image should show the # overall image shifted [-6,-8,-10] voxels towards the origin a = np.identity(4) a[:3, -1] = [3, 4, 5] ir = resample(i, i.coordmap, a, (100, 90, 80)) assert_array_almost_equal(ir.get_data()[44:49, 32:47, 20:23], 3.)
def output_resid(outfile, fmri_image, clobber=False): """ Create an output file of the residuals parameter from the OLS pass of fmristat. Uses affine part of the first image to output resids unless fmri_image is an Image. Parameters ---------- outfile : fmri_image : ``FmriImageList`` or 4D image If ``FmriImageList``, needs attributes ``volume_start_times``, supports len(), and object[0] has attributes ``affine``, ``coordmap`` and ``shape``, from which we create a new 4D coordmap and shape If 4D image, use the images coordmap and shape clobber : bool if True, overwrite previous output Returns ------- regression_output : """ if isinstance(fmri_image, FmriImageList): n = len(fmri_image.list) T = np.zeros((5, 5)) g = fmri_image[0].coordmap T[1:, 1:] = fmri_image[0].affine T[0, 0] = (fmri_image.volume_start_times[1:] - fmri_image.volume_start_times[:-1]).mean() # FIXME: NIFTI specific naming here innames = ["t"] + list(g.function_domain.coord_names) outnames = ["t"] + list(g.function_range.coord_names) cmap = AffineTransform.from_params(innames, outnames, T) shape = (n, ) + fmri_image[0].shape elif isinstance(fmri_image, Image): cmap = fmri_image.coordmap shape = fmri_image.shape else: raise ValueError, "expecting FmriImageList or 4d Image" outim = ModelOutputImage(outfile, cmap, shape, clobber=clobber) return outputters.RegressionOutput(outim, outputters.output_resid)
def test_slice_from_3d(): # Resample a 3d image, returning a zslice, yslice and xslice # # This example creates a coordmap that coincides with # a given z, y, or x slice of an image, and checks that # resampling agrees with the data in the given slice. shape = (100, 90, 80) g = AffineTransform.from_params('ijk', 'xyz', np.diag([0.5, 0.5, 0.5, 1])) img = Image(np.ones(shape), g) img.get_data()[50:55, 40:55, 30:33] = 3 I = np.identity(4) zsl = slices.zslice(26, ((0, 49.5), 100), ((0, 44.5), 90), img.reference) ir = resample(img, zsl, I, (100, 90)) assert_array_almost_equal(ir.get_data(), img[:, :, 53].get_data()) ysl = slices.yslice(22, ((0, 49.5), 100), ((0, 39.5), 80), img.reference) ir = resample(img, ysl, I, (100, 80)) assert_array_almost_equal(ir.get_data(), img[:, 45, :].get_data()) xsl = slices.xslice(15.5, ((0, 44.5), 90), ((0, 39.5), 80), img.reference) ir = resample(img, xsl, I, (90, 80)) assert_array_almost_equal(ir.get_data(), img[32, :, :].get_data())
def test_slice_from_3d(): # Resample a 3d image, returning a zslice, yslice and xslice # # This example creates a coordmap that coincides with # the 10th slice of an image, and checks that # resampling agrees with the data in the 10th slice. shape = (100, 90, 80) g = AffineTransform.from_params("ijk", "xyz", np.diag([0.5, 0.5, 0.5, 1])) i = Image(np.ones(shape), g) i[50:55, 40:55, 30:33] = 3 a = np.identity(4) zsl = slices.zslice(26, ((0, 44.5), 90), ((0, 39.5), 80), i.reference) ir = resample(i, zsl, a, (90, 80)) yield assert_true(np.allclose(np.asarray(ir), np.asarray(i[53]))) ysl = slices.yslice(22, (0, 49.5), (0, 39.5), i.reference, (100, 80)) ir = resample(i, ysl.coordmap, a, ysl.shape) yield assert_true(np.allclose(np.asarray(ir), np.asarray(i[:, 45]))) xsl = slices.xslice(15.5, (0, 49.5), (0, 44.5), i.reference, (100, 90)) ir = resample(i, xsl.coordmap, a, xsl.shape) yield assert_true(np.allclose(np.asarray(ir), np.asarray(i[:, :, 32])))
def test_array_coord_map(): # array coord map recreates the affine when you slice an image. In # general, if you take an integer slice in some dimension, the # corresponding column of the affine will go, leaving a row for the # lost dimension, with all zeros, execpt for the translation in the # now-removed dimension, encoding the position of that particular # slice xz = 1.1; yz = 2.3; zz = 3.5 xt = 10.0; yt = 11; zt = 12 aff = np.diag([xz, yz, zz, 1]) aff[:3,3] = [xt, yt, zt] shape = (2,3,4) cmap = AffineTransform.from_params('ijk', 'xyz', aff) acm = acs.ArrayCoordMap(cmap, shape) # slice the coordinate map for the first axis sacm = acm[1] # The affine has lost the first column, but has a remaining row (the # first) encoding the translation to get to this slice assert_array_almost_equal(sacm.coordmap.affine, np.array([ [0, 0, xz+xt], [yz, 0, yt], [0, zz, zt], [0, 0, 1]])) sacm = acm[:,1] # lost second column, remaining second row with translation assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, 0, yz+yt], [0, zz, zt], [0, 0, 1]])) sacm = acm[:,:,2] # ditto third column and row assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, yz, yt], [0, 0, 2*zz+zt], [0, 0, 1]])) # check ellipsis slicing is the same as [:,: ... sacm = acm[...,2] assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, yz, yt], [0, 0, 2*zz+zt], [0, 0, 1]])) # that ellipsis can follow other slice types sacm = acm[:,...,2] assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, yz, yt], [0, 0, 2*zz+zt], [0, 0, 1]])) # that there can be only one ellipsis assert_raises(ValueError, acm.__getitem__, ( (Ellipsis, Ellipsis,2))) # that you can integer slice in all three dimensions, leaving only # the translation column sacm = acm[1,0,2] assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz+xt], [yt], [2*zz+zt], [1]])) # that anything other than an int, slice or Ellipsis is an error assert_raises(ValueError, acm.__getitem__, ([0,2],)) assert_raises(ValueError, acm.__getitem__, (np.array([0,2]),))
def test_affine_transform_from_array(): X = np.random.standard_normal((4, 4)) X[-1] = [0, 0, 0, 1] function_domain = CoordinateSystem("ijk", "input") function_range = CoordinateSystem(lps, "output") cmap = AffineTransform(function_domain, function_range, X) A, _ = niref.affine_transform_from_array(X, "ijk", []) yield assert_almost_equal, X, A.affine yield assert_raises, ValueError, niref.affine_transform_from_array, X[:, 1:], "ijk", [] yield assert_raises, ValueError, niref.affine_transform_from_array, X, "ij", [] threed, fourd = niref.affine_transform_from_array(X, "ijk", [3.5]) yield assert_almost_equal, X, threed.affine yield assert_almost_equal, fourd.affine[3:, 3:], np.diag([3.5, 1]) # get the pixdim back out A, p = niref.ni_affine_pixdim_from_affine(fourd) yield assert_almost_equal, X, A.affine yield assert_almost_equal, p, 3.5 # try strict A, p = niref.ni_affine_pixdim_from_affine(fourd, strict=True) # try using RAS cmap = fourd.renamed_range(dict(zip(lps, ras_output_coordnames))) A, p = niref.ni_affine_pixdim_from_affine(cmap, strict=True) # will have been flipped to LPS yield assert_almost_equal, A.affine, np.dot(np.diag([-1, -1, 1, 1]), X) yield assert_equal, A.function_range.coord_names, lps # use coordinates that aren't OK and strict raises an exception cmap = fourd.renamed_range(dict(zip(lps, "xyz"))) yield assert_raises, ValueError, niref.ni_affine_pixdim_from_affine, cmap, True # use coordinates that aren't OK and not strict just guesses LPS cmap4 = fourd.renamed_range(dict(zip(lps, "xyz"))) A, p = niref.ni_affine_pixdim_from_affine(cmap4, False) yield assert_almost_equal, A.affine, X yield assert_equal, A.function_range.coord_names, lps yield assert_almost_equal, p, 3.5 # non-square affine fails Z = np.random.standard_normal((5, 4)) Z[-1] = [0, 0, 0, 1] affine = AffineTransform.from_params("ijk", "xyzt", Z) yield assert_raises, ValueError, niref.ni_affine_pixdim_from_affine, affine # CoordinateMap fails ijk = CoordinateSystem("ijk") xyz = CoordinateSystem("xzy") cmap = CoordinateMap(ijk, xyz, np.exp) yield assert_raises, ValueError, niref.ni_affine_pixdim_from_affine, cmap, True # non-diagonal above 3rd dimension, with strict True raises an exception cmap5 = cmap4.renamed_range(dict(zip("xyz", lps))) cmap5.affine[3, -1] = 4.0 yield assert_raises, ValueError, niref.ni_affine_pixdim_from_affine, cmap5, True B, p = niref.ni_affine_pixdim_from_affine(cmap5) yield assert_equal, p, 3.5
def test_array_coord_map(): # array coord map recreates the affine when you slice an image. In # general, if you take an integer slice in some dimension, the # corresponding column of the affine will go, leaving a row for the # lost dimension, with all zeros, execpt for the translation in the # now-removed dimension, encoding the position of that particular # slice xz = 1.1; yz = 2.3; zz = 3.5 xt = 10.0; yt = 11; zt = 12 aff = np.diag([xz, yz, zz, 1]) aff[:3,3] = [xt, yt, zt] shape = (2,3,4) cmap = AffineTransform.from_params('ijk', 'xyz', aff) acm = acs.ArrayCoordMap(cmap, shape) # slice the coordinate map for the first axis sacm = acm[1] # The affine has lost the first column, but has a remaining row (the # first) encoding the translation to get to this slice yield assert_array_almost_equal(sacm.coordmap.affine, np.array([ [0, 0, xz+xt], [yz, 0, yt], [0, zz, zt], [0, 0, 1]])) sacm = acm[:,1] # lost second column, remaining second row with translation yield assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, 0, yz+yt], [0, zz, zt], [0, 0, 1]])) sacm = acm[:,:,2] # ditto third column and row yield assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, yz, yt], [0, 0, 2*zz+zt], [0, 0, 1]])) # check ellipsis slicing is the same as [:,: ... sacm = acm[...,2] yield assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, yz, yt], [0, 0, 2*zz+zt], [0, 0, 1]])) # that ellipsis can follow other slice types sacm = acm[:,...,2] yield assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz, 0, xt], [0, yz, yt], [0, 0, 2*zz+zt], [0, 0, 1]])) # that there can be only one ellipsis yield assert_raises(ValueError, acm.__getitem__, ( (Ellipsis,Ellipsis,2))) # that you can integer slice in all three dimensions, leaving only # the translation column sacm = acm[1,0,2] yield assert_array_almost_equal(sacm.coordmap.affine, np.array([ [xz+xt], [yt], [2*zz+zt], [1]])) # that anything other than an int, slice or Ellipsis is an error yield assert_raises(ValueError, acm.__getitem__, ([0,2],)) yield assert_raises(ValueError, acm.__getitem__, (np.array([0,2]),))
def affine_transform_from_array(affine, ijk, pixdim): """Generate a AffineTransform from an affine transform. This is a convenience function to create a AffineTransform from image attributes. It assumes that the first three axes in the image (and therefore affine) are spatial (in 'ijk' in input and equal to 'xyz' in output), and appends the standard names for further dimensions (e.g. 'l' as the 4th in input, 't' as the 4th in output). Parameters ---------- affine : array affine for affine_transform ijk : sequence sequence, some permutation of 'ijk', giving spatial axis ordering. These are the spatial input axis names pixdim : sequence of floats Pixdims for dimensions beyond 3. Returns ------- 3daffine_transform : ``AffineTransform`` affine transform corresponding to `affine` and `ijk` domain names with LPS range names full_transform: ``AffineTransform`` affine transform corresponding to `affine` and `ijk` domain names for first 3 coordinates, diagonal with pixdim values beyond Examples -------- >>> af_tr3d, af_tr = affine_transform_from_array(np.diag([2,3,4,1]), 'ijk', []) >>> af_tr.function_domain.coord_names ('i', 'j', 'k') >>> af_tr3d.function_domain.coord_names ('i', 'j', 'k') >>> af_tr.function_range.coord_names ('x+LR', 'y+PA', 'z+SI') >>> af_tr3d.function_range.coord_names ('x+LR', 'y+PA', 'z+SI') >>> af_tr3d, af_tr = affine_transform_from_array(np.diag([2,3,4,1]), 'kij', [3.5]) >>> af_tr.function_domain.coord_names ('k', 'i', 'j', 't') >>> af_tr.function_range.coord_names ('x+LR', 'y+PA', 'z+SI', 't') >>> af_tr3d.function_domain.coord_names ('k', 'i', 'j') >>> af_tr3d.function_range.coord_names ('x+LR', 'y+PA', 'z+SI') >>> print af_tr3d AffineTransform( function_domain=CoordinateSystem(coord_names=('k', 'i', 'j'), name='', coord_dtype=float64), function_range=CoordinateSystem(coord_names=('x+LR', 'y+PA', 'z+SI'), name='', coord_dtype=float64), affine=array([[ 2., 0., 0., 0.], [ 0., 3., 0., 0.], [ 0., 0., 4., 0.], [ 0., 0., 0., 1.]]) ) >>> print af_tr AffineTransform( function_domain=CoordinateSystem(coord_names=('k', 'i', 'j', 't'), name='product', coord_dtype=float64), function_range=CoordinateSystem(coord_names=('x+LR', 'y+PA', 'z+SI', 't'), name='product', coord_dtype=float64), affine=array([[ 2. , 0. , 0. , 0. , 0. ], [ 0. , 3. , 0. , 0. , 0. ], [ 0. , 0. , 4. , 0. , 0. ], [ 0. , 0. , 0. , 3.5, 0. ], [ 0. , 0. , 0. , 0. , 1. ]]) ) FIXME: This is an internal function and should be revisited when the AffineTransform is refactored. """ if affine.shape != (4, 4) or len(ijk) != 3: raise ValueError('affine must be square, 4x4, ijk of length 3') innames = tuple(ijk) + tuple('tuvw'[:len(pixdim)]) incoords = CS(innames, 'voxel') outnames = lps_output_coordnames + tuple('tuvw'[:len(pixdim)]) outcoords = CS(outnames, 'world') transform3d = AT(CS(incoords.coord_names[:3]), CS(outcoords.coord_names[:3]), affine) if pixdim: nonspatial = AT.from_params(incoords.coord_names[3:], outcoords.coord_names[3:], np.diag(list(pixdim) + [1])) transform_full = mapping_product(transform3d, nonspatial) else: transform_full = transform3d return transform3d, transform_full