def test_more_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis): path_tmp = tmp_create(basename="test_reorient") path_tmp = "." im_src = fake_3dimage_sct.copy() im_src.save(os.path.join(path_tmp, "src.nii"), mutable=True) print(im_src.orientation, im_src.data.shape) def orient2shape(orient): # test-data-specific thing letter2dim = dict( L=7, R=7, A=8, P=8, I=9, S=9, ) return tuple([letter2dim[x] for x in orient]) orientation = im_src.orientation # LPI assert im_src.header.get_best_affine()[:3, 3].tolist() == [0, 0, 0] im_dst = msct_image.change_orientation(im_src, "RPI") print(im_dst.orientation, im_dst.data.shape) assert im_dst.data.shape == orient2shape("RPI") assert im_dst.header.get_best_affine()[:3, 3].tolist() == [7 - 1, 0, 0] # spot check orientation = im_src.orientation # LPI im_dst = msct_image.change_orientation(im_src, "IRP") print(im_dst.orientation, im_dst.data.shape) assert im_dst.data.shape == orient2shape("IRP") # to & fro im_dst2 = msct_image.change_orientation(im_dst, orientation) print(im_dst2.orientation, im_dst2.data.shape) assert im_dst2.orientation == im_src.orientation assert im_dst2.data.shape == orient2shape(orientation) assert (im_dst2.data == im_src.data).all() assert np.allclose(im_src.header.get_best_affine(), im_dst2.header.get_best_affine()) #fn = os.path.join(path_tmp, "pouet.nii") im_ref = fake_3dimage_sct.copy() im_src = fake_3dimage_sct.copy() orientation = im_src.orientation im_src.change_orientation("ASR").change_orientation(orientation) assert im_src.orientation == im_ref.orientation assert (im_dst2.data == im_src.data).all() assert np.allclose(im_src.header.get_best_affine(), im_ref.header.get_best_affine()) im_dst2 = msct_image.change_orientation(im_dst, orientation) print(im_dst2.orientation, im_dst2.data.shape) assert im_dst2.orientation == im_src.orientation assert im_dst2.data.shape == orient2shape(orientation) assert (im_dst2.data == im_src.data).all() assert np.allclose(im_src.header.get_best_affine(), im_dst2.header.get_best_affine()) # copy im_dst = im_src.copy().change_orientation("IRP") assert im_dst.data.shape == orient2shape("IRP") print(im_dst.orientation, im_dst.data.shape) print("Testing orientation persistence") img = im_src.copy() orientation = img.orientation fn = os.path.join(path_tmp, "pouet.nii") img.change_orientation("PIR").save(fn) assert img.data.shape == orient2shape("PIR") img = msct_image.Image(fn) assert img.orientation == "PIR" assert img.data.shape == orient2shape("PIR") print(img.orientation, img.data.shape) # typical pattern img = fake_3dimage_sct_vis.copy() print(img.header.get_best_affine()) orientation = img.orientation path_tmp = "." fn = os.path.join(path_tmp, "vis.nii") fn2 = img.save(fn, mutable=True).change_orientation( "ALS", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "ALS" assert img.data.shape == orient2shape("ALS") print(img.header.get_best_affine()) fn2 = img.save(fn, mutable=True).change_orientation( "RAS", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "RAS" assert img.data.shape == orient2shape("RAS") print(img.header.get_best_affine()) fn2 = img.save(fn, mutable=True).change_orientation( "RPI", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "RPI" assert img.data.shape == orient2shape("RPI") print(img.header.get_best_affine()) fn2 = img.save(fn, mutable=True).change_orientation( "PLI", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "PLI" assert img.data.shape == orient2shape("PLI") print(img.header.get_best_affine()) # print(src.header) possibilities = [ "ASR", "SRA", "RAS", ] possibilities = msct_image.all_refspace_strings() for orientation in possibilities: dst = msct_image.change_orientation(im_src, orientation) # dst.save("pouet-{}.nii".format(dst.orientation)) print(orientation, dst.orientation, dst.data.shape, dst.dim) assert orientation == dst.orientation
def test_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis): path_tmp = tmp_create(basename="test_reorient") path_tmp = "." print("Spot-checking that physical coordinates don't change") for shape_is in (1, 2, 3): shape = (1, 1, shape_is) print("Simple image with shape {}".format(shape)) data = np.ones(shape, order="F") data[:, :, shape_is - 1] += 1 im_src = fake_3dimage_sct_custom(data) im_dst = msct_image.change_orientation(im_src, "ASR") # Basic check assert im_dst.orientation == "ASR" # Basic data check assert im_dst.data.mean() == im_src.data.mean() # Basic header check: check that the same voxel # remains at the same physical position aff_src = im_src.header.get_best_affine() aff_dst = im_dst.header.get_best_affine() # Take the extremities "a" & "z"... # consider the original LPI position pta_src = np.array([[0, 0, 0, 1]]).T ptz_src = np.array([[0, 0, shape_is - 1, 1]]).T # and the position in ASR pta_dst = np.array([[0, shape_is - 1, 0, 1]]).T ptz_dst = np.array([[0, 0, 0, 1]]).T # The physical positions should be: posa_src = np.matmul(aff_src, pta_src) posa_dst = np.matmul(aff_dst, pta_dst) print("A at src {}".format(posa_src.T)) print("A at dst {}".format(posa_dst.T)) posz_src = np.matmul(aff_src, ptz_src) posz_dst = np.matmul(aff_dst, ptz_dst) # and they should be equal assert (posa_src == posa_dst).all() assert (posz_src == posz_dst).all() fn = "".join(str(x) for x in im_src.data.shape) im_src.save("{}-src.nii".format(fn)) im_dst.save("{}-dst.nii".format(fn)) np.random.seed(0) print("More checking that physical coordinates don't change") if 1: shape = (7, 8, 9) print("Simple image with shape {}".format(shape)) data = np.ones(shape, order="F") * 10 data[4, 4, 4] = 4 data[3, 3, 3] = 3 data[0, 0, 0] = 0 values = (0, 3, 4) im_ref = fake_3dimage_sct_custom(data) im_ref.header.set_xyzt_units("mm", "msec") import scipy.linalg def rand_rot(): q, _ = scipy.linalg.qr(np.random.randn(3, 3)) if scipy.linalg.det(q) < 0: q[:, 0] = -q[:, 0] return q affine = im_ref.header.get_best_affine() affine[:3, :3] = rand_rot() affine[3, :3] = 0.0 affine[:3, 3] = np.random.random((3)) affine[3, 3] = 1.0 affine[0, 0] *= 2 im_ref.header.set_sform(affine, code='scanner') orientations = msct_image.all_refspace_strings() for ori_src in orientations: for ori_dst in orientations: print("{} -> {}".format(ori_src, ori_dst)) im_src = msct_image.change_orientation(im_ref, ori_src) im_dst = msct_image.change_orientation(im_src, ori_dst) assert im_src.orientation == ori_src assert im_dst.orientation == ori_dst assert im_dst.data.mean() == im_src.data.mean() # Basic header check: check that the same voxel # remains at the same physical position aff_src = im_src.header.get_best_affine() aff_dst = im_dst.header.get_best_affine() data_src = np.array(im_src.data) data_dst = np.array(im_dst.data) for value in values: pt_src = np.argwhere(data_src == value)[0] pt_dst = np.argwhere(data_dst == value)[0] pos_src = np.matmul( aff_src, np.hstack((pt_src, [1])).reshape((4, 1))) pos_dst = np.matmul( aff_dst, np.hstack((pt_dst, [1])).reshape((4, 1))) if 0: print("P at src {}".format(pos_src.T)) print("P at dst {}".format(pos_dst.T)) assert np.allclose(pos_src, pos_dst, atol=1e-3)
def notest_transfo_more_exhaustive_wrt_orientations(): dir_tmp = "." print("Figuring out which orientations work without workaround") all_orientations = msct_image.all_refspace_strings() orientations_ok = [] orientations_ng = [] orientations_dk = [] for orientation_src in all_orientations: for orientation_ref in all_orientations: shift = np.array([1,2,3]) shift_wanted = shift.copy() shift[2] *= -1 # ANTs / ITK reference frame is LPS, ours is LPI # (see docs or test_transfo_figure_out_ants_frame_exhaustive()) print(" Shifting {} in {} ref {}".format(shift_wanted, orientation_src, orientation_ref)) path_src = "warp2-{}.nii".format(orientation_src) img_src = fake_3dimage_sct().change_orientation(orientation_src).save(path_src) path_ref = "warp2-{}.nii".format(orientation_ref) img_ref = fake_3dimage_sct().change_orientation(orientation_ref).save(path_ref) # Create warping field shape = tuple(list(img_src.data.shape) + [1,3]) data = np.zeros(shape, order="F") data[:,:,:,0] = shift path_warp = "warp-{}-{}-field.nii".format(orientation_src, orientation_ref) img_warp = fake_image_sct_custom(data) img_warp.header.set_intent('vector', (), '') img_warp.change_orientation(orientation_ref).save(path_warp) #print(" Affine:\n{}".format(img_warp.header.get_best_affine())) path_dst = "warp-{}-{}-dst.nii".format(orientation_src, orientation_ref) xform = sct_apply_transfo.Transform(path_src, path_warp, path_ref, path_dst) xform.apply() img_src2 = msct_image.Image(path_src) img_dst = msct_image.Image(path_dst) assert img_ref.orientation == img_dst.orientation assert img_ref.data.shape == img_dst.data.shape dat_src = img_src.data dat_dst = np.array(img_dst.data) value = 50505 aff_src = img_src.header.get_best_affine() aff_dst = img_dst.header.get_best_affine() pt_src = np.argwhere(dat_src == value)[0] try: pt_dst = np.argwhere(dat_dst == value)[0] 1/0 except: # Work around numerical inaccuracy, that is somehow introduced by ANTs min_ = np.round(np.min(np.abs(dat_dst - value)), 1) pt_dst = np.array(np.unravel_index(np.argmin(np.abs(dat_dst - value)), dat_dst.shape))#, order="F")) print(" Point %s -> %s (%s) %s" % (pt_src, pt_dst, dat_dst[tuple(pt_dst)], min_)) if min_ != 0: orientations_dk.append((orientation_src, orientation_ref)) continue pos_src = np.matmul(aff_src, np.hstack((pt_src, [1])).reshape((4,1))) pos_dst = np.matmul(aff_dst, np.hstack((pt_dst, [1])).reshape((4,1))) displacement = (pos_dst - pos_src).reshape((-1))[:3] displacement_log = pt_dst - pt_src #print(" Displacement (logical): %s" % (displacement_log)) if not np.allclose(displacement, shift_wanted): orientations_ng.append((orientation_src, orientation_ref)) print(" \x1B[31;1mDisplacement (physical): %s\x1B[0m" % (displacement)) else: orientations_ok.append((orientation_src, orientation_ref)) print(" Displacement (physical): %s" % (displacement)) print("") def ori_str(x): return " ".join(["{}->{}".format(x,y) for (x,y) in x]) print("Orientations OK: {}".format(ori_str(orientations_ok))) print("Orientations NG: {}".format(ori_str(orientations_ng))) print("Orientations DK: {}".format(ori_str(orientations_dk)))
def test_transfo_figure_out_ants_frame_exhaustive(): dir_tmp = "." all_orientations = msct_image.all_refspace_strings() #all_orientations = ("LPS", "LPI") print("Wondering which orientation is native to ANTs") working_orientations = [] # there can't be only one... for orientation in all_orientations: print(" Shifting +1,+1,+1 (in {})".format(orientation)) path_src = "warp-{}-src.nii".format(orientation) img_src = fake_3dimage_sct().change_orientation(orientation).save(path_src) # Create warping field shape = tuple(list(img_src.data.shape) + [1,3]) data = np.ones(shape, order="F") path_warp = "warp-{}-field.nii".format(orientation) img_warp = fake_image_sct_custom(data) img_warp.header.set_intent('vector', (), '') img_warp.change_orientation(orientation).save(path_warp) print(" Affine:\n{}".format(img_warp.header.get_best_affine())) path_dst = "warp-{}-dst.nii".format(orientation) xform = sct_apply_transfo.Transform(path_src, path_warp, path_src, path_dst) xform.apply() img_src2 = msct_image.Image(path_src) img_dst = msct_image.Image(path_dst) assert img_src.orientation == img_dst.orientation assert img_src.data.shape == img_dst.data.shape dat_src = img_src.data dat_dst = np.array(img_dst.data) value = 222 aff_src = img_dst.header.get_best_affine() aff_dst = img_dst.header.get_best_affine() pt_src = np.array(np.unravel_index(np.argmin(np.abs(dat_src - value)), dat_src.shape))#, order="F")) pt_dst = np.array(np.unravel_index(np.argmin(np.abs(dat_dst - value)), dat_dst.shape))#, order="F")) print("Point %s -> %s" % (pt_src, pt_dst)) pos_src = np.matmul(aff_src, np.hstack((pt_src, [1])).reshape((4,1))) pos_dst = np.matmul(aff_dst, np.hstack((pt_dst, [1])).reshape((4,1))) displacement = (pos_dst - pos_src).T[:3] print("Displacement (physical): %s" % (displacement)) displacement = pt_dst - pt_src print("Displacement (logical): %s" % (displacement)) assert dat_src.shape == dat_dst.shape if 0: for idx_slice in range(9): print(dat_src[...,idx_slice]) print(dat_dst[...,idx_slice]) print("") try: # Check same as before assert np.allclose(dat_dst[0,:,:], 0) assert np.allclose(dat_dst[:,0,:], 0) assert np.allclose(dat_dst[:,:,0], 0) assert np.allclose(dat_src[:-1,:-1,:-1], dat_dst[1:,1:,1:]) working_orientations.append(orientation) except AssertionError as e: continue print("\x1B[31;1m Failed in {}\x1B[0m".format(orientation)) for idx_slice in range(shape[2]): print(dat_src[...,idx_slice]) print(dat_dst[...,idx_slice]) print("") print("-> Working orientation: {}".format(" ".join(working_orientations)))
def test_more_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis): path_tmp = sct.tmp_create(basename="test_reorient") path_tmp = "." im_src = fake_3dimage_sct.copy() im_src.save(os.path.join(path_tmp, "src.nii"), mutable=True) print(im_src.orientation, im_src.data.shape) def orient2shape(orient): # test-data-specific thing letter2dim = dict( L=7, R=7, A=8, P=8, I=9, S=9, ) return tuple([letter2dim[x] for x in orient]) orientation = im_src.orientation # LPI assert im_src.header.get_best_affine()[:3,3].tolist() == [0,0,0] im_dst = msct_image.change_orientation(im_src, "RPI") print(im_dst.orientation, im_dst.data.shape) assert im_dst.data.shape == orient2shape("RPI") assert im_dst.header.get_best_affine()[:3,3].tolist() == [7-1,0,0] # spot check orientation = im_src.orientation # LPI im_dst = msct_image.change_orientation(im_src, "IRP") print(im_dst.orientation, im_dst.data.shape) assert im_dst.data.shape == orient2shape("IRP") # to & fro im_dst2 = msct_image.change_orientation(im_dst, orientation) print(im_dst2.orientation, im_dst2.data.shape) assert im_dst2.orientation == im_src.orientation assert im_dst2.data.shape == orient2shape(orientation) assert (im_dst2.data == im_src.data).all() assert np.allclose(im_src.header.get_best_affine(), im_dst2.header.get_best_affine()) #fn = os.path.join(path_tmp, "pouet.nii") im_ref = fake_3dimage_sct.copy() im_src = fake_3dimage_sct.copy() orientation = im_src.orientation im_src.change_orientation("ASR").change_orientation(orientation) assert im_src.orientation == im_ref.orientation assert (im_dst2.data == im_src.data).all() assert np.allclose(im_src.header.get_best_affine(), im_ref.header.get_best_affine()) im_dst2 = msct_image.change_orientation(im_dst, orientation) print(im_dst2.orientation, im_dst2.data.shape) assert im_dst2.orientation == im_src.orientation assert im_dst2.data.shape == orient2shape(orientation) assert (im_dst2.data == im_src.data).all() assert np.allclose(im_src.header.get_best_affine(), im_dst2.header.get_best_affine()) # copy im_dst = im_src.copy().change_orientation("IRP") assert im_dst.data.shape == orient2shape("IRP") print(im_dst.orientation, im_dst.data.shape) print("Testing orientation persistence") img = im_src.copy() orientation = img.orientation fn = os.path.join(path_tmp, "pouet.nii") img.change_orientation("PIR").save(fn) assert img.data.shape == orient2shape("PIR") img = msct_image.Image(fn) assert img.orientation == "PIR" assert img.data.shape == orient2shape("PIR") print(img.orientation, img.data.shape) # typical pattern img = fake_3dimage_sct_vis.copy() print(img.header.get_best_affine()) orientation = img.orientation path_tmp = "." fn = os.path.join(path_tmp, "vis.nii") fn2 = img.save(fn, mutable=True).change_orientation("ALS", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "ALS" assert img.data.shape == orient2shape("ALS") print(img.header.get_best_affine()) fn2 = img.save(fn, mutable=True).change_orientation("RAS", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "RAS" assert img.data.shape == orient2shape("RAS") print(img.header.get_best_affine()) fn2 = img.save(fn, mutable=True).change_orientation("RPI", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "RPI" assert img.data.shape == orient2shape("RPI") print(img.header.get_best_affine()) fn2 = img.save(fn, mutable=True).change_orientation("PLI", generate_path=True).save().absolutepath img = msct_image.Image(fn2) assert img.orientation == "PLI" assert img.data.shape == orient2shape("PLI") print(img.header.get_best_affine()) #print(src.header) possibilities = [ "ASR", "SRA", "RAS", ] possibilities = msct_image.all_refspace_strings() for orientation in possibilities: dst = msct_image.change_orientation(im_src, orientation) #dst.save("pouet-{}.nii".format(dst.orientation)) print(orientation, dst.orientation, dst.data.shape, dst.dim) assert orientation == dst.orientation
def test_change_orientation(fake_3dimage_sct, fake_3dimage_sct_vis): path_tmp = sct.tmp_create(basename="test_reorient") path_tmp = "." print("Spot-checking that physical coordinates don't change") for shape_is in (1,2,3): shape = (1,1,shape_is) print("Simple image with shape {}".format(shape)) data = np.ones(shape, order="F") data[:,:,shape_is-1] += 1 im_src = fake_3dimage_sct_custom(data) im_dst = msct_image.change_orientation(im_src, "ASR") # Basic check assert im_dst.orientation == "ASR" # Basic data check assert im_dst.data.mean() == im_src.data.mean() # Basic header check: check that the same voxel # remains at the same physical position aff_src = im_src.header.get_best_affine() aff_dst = im_dst.header.get_best_affine() # Take the extremities "a" & "z"... # consider the original LPI position pta_src = np.array([[0,0,0,1]]).T ptz_src = np.array([[0,0,shape_is-1,1]]).T # and the position in ASR pta_dst = np.array([[0,shape_is-1,0,1]]).T ptz_dst = np.array([[0,0,0,1]]).T # The physical positions should be: posa_src = np.matmul(aff_src, pta_src) posa_dst = np.matmul(aff_dst, pta_dst) print("A at src {}".format(posa_src.T)) print("A at dst {}".format(posa_dst.T)) posz_src = np.matmul(aff_src, ptz_src) posz_dst = np.matmul(aff_dst, ptz_dst) # and they should be equal assert (posa_src == posa_dst).all() assert (posz_src == posz_dst).all() fn = "".join(str(x) for x in im_src.data.shape) im_src.save("{}-src.nii".format(fn)) im_dst.save("{}-dst.nii".format(fn)) np.random.seed(0) print("More checking that physical coordinates don't change") if 1: shape = (7,8,9) print("Simple image with shape {}".format(shape)) data = np.ones(shape, order="F") * 10 data[4,4,4] = 4 data[3,3,3] = 3 data[0,0,0] = 0 values = (0,3,4) im_ref = fake_3dimage_sct_custom(data) im_ref.header.set_xyzt_units("mm", "msec") import scipy.linalg def rand_rot(): q, _ = scipy.linalg.qr(np.random.randn(3, 3)) if scipy.linalg.det(q) < 0: q[:, 0] = -q[:, 0] return q affine = im_ref.header.get_best_affine() affine[:3,:3] = rand_rot() affine[3,:3] = 0.0 affine[:3,3] = np.random.random((3)) affine[3,3] = 1.0 affine[0,0] *= 2 im_ref.header.set_sform(affine, code='scanner') orientations = msct_image.all_refspace_strings() for ori_src in orientations: for ori_dst in orientations: print("{} -> {}".format(ori_src, ori_dst)) im_src = msct_image.change_orientation(im_ref, ori_src) im_dst = msct_image.change_orientation(im_src, ori_dst) assert im_src.orientation == ori_src assert im_dst.orientation == ori_dst assert im_dst.data.mean() == im_src.data.mean() # Basic header check: check that the same voxel # remains at the same physical position aff_src = im_src.header.get_best_affine() aff_dst = im_dst.header.get_best_affine() data_src = np.array(im_src.data) data_dst = np.array(im_dst.data) for value in values: pt_src = np.argwhere(data_src == value)[0] pt_dst = np.argwhere(data_dst == value)[0] pos_src = np.matmul(aff_src, np.hstack((pt_src, [1])).reshape((4,1))) pos_dst = np.matmul(aff_dst, np.hstack((pt_dst, [1])).reshape((4,1))) if 0: print("P at src {}".format(pos_src.T)) print("P at dst {}".format(pos_dst.T)) assert np.allclose(pos_src, pos_dst, atol=1e-3)