예제 #1
0
 def data_xform(self, slice_idx, zyx_coords):
     """Given the a sliceplots slicing index and the current vox position,
     get a slice of data.
     """
     slicer = [slice(0,d) for d in self.shape]
     slicer[slice_idx] = self.zyx2vox(zyx_coords)[slice_idx]
     slicer = tuple(slicer)
     Msub = self.plane_xform(slice_idx)
     Msub = reverse(reverse(Msub, axis=-1), axis=-2)
     xform = compose_xform(Msub)
     return xform(self[slicer])
예제 #2
0
    def transform(self, new_mapping=None, transform=None, force=False):
        """Updates the voxel to real-space transform.

        There are two modes of usage--
        1) supply a new voxel to real mapping.
           In this case a voxel to voxel transform is found, and the image
           is rotated in-plane around the origin. Only transposes and
           reflections are supported. Image info is updated appropriately

        2) supply a real to real transform to apply to the current mapping.
           In this case the data is not updated, but the mapping is updated.

        """
        if new_mapping is None and transform is None:
            return
        if new_mapping is not None and transform is not None:
            print """
            The user must specify either a new mapping to convert to,
            or a transform to apply, but cannot specify both."""
            return
        if transform is not None:
            # this doesn't change the image array, it just updates the
            # transformation
            old_xform = self.orientation_xform.tomatrix()
            if isinstance(transform, Quaternion):
                transform = transform.tomatrix()
            dim_scale = np.array([self.isize, self.jsize, self.ksize])
            r0 = np.array([self.x0, self.y0, self.z0])
            origin_voxels = np.round(np.linalg.solve(old_xform*dim_scale, -r0))
            # now derive r0 again.. Tmap*(i,j,k)^T + r0^T = (x,y,z)^T
            r0 = -np.dot(transform*dim_scale, origin_voxels)
            self.x0, self.y0, self.z0 = r0
            self.orientation_xform = Quaternion(M=transform)
            return
        # else handle the new mapping
        from recon.slicerimage import nearest_simple_transform
        # Tr already maps [i,j,k]^T into [R,A,S] ...
        # Here I want to change coordinates with this relationship:
        # Tr*[i,j,k]^T = Tnew*[i',j',k']^T
        # so Tnew*(Tvx*[i,j,k]^T) = Tr*[i,j,k]^T
        # So inv(Tnew)*Tr*[i,j,k] = [i',j',k'] = orientation of choice!
        # The task is to analyze Tvx = (Tnew^-1 * Tr) to get rotation
        
        Tr = self.orientation_xform.tomatrix()
        Tvx = np.linalg.solve(new_mapping, Tr)
        Tvxp = nearest_simple_transform(Tvx)
        # allow a goodly amount of wiggle room for each element of the
        # rotation matrix
        if not np.allclose(Tvxp, Tvx, atol=1e-4):
            # Tvxp might be a good choice in this case.. so could suggest
            # Tnew'*Tvxp = Tr
            # (Tvxp^T * Tnew'^T) = Tr^T
            # Tnew' = solve(Tvxp^T, Tr^T)^T
            Tnew_suggest = np.linalg.solve(Tvxp.T, Tr.T).T
            if not force:
                raise ValueError("""This method will not transform the data to
                the stated new mapping because the transformation cannot be
                accomplished through transposes and reflections. The closest new
                mapping you can perform is:\n"""+str(Tnew_suggest))
            else:
                print """It is not possible to rotate simply to the stated
                mapping; proceeding with this mapping:\n"""+str(Tnew_suggest)+\
                """\nbut lying about the final mapping."""
                #new_mapping = Tnew_suggest
                Tvx = Tvxp
        else:
            # if Tvx is adequately close to its trimmed version,
            # let's go ahead and use the simple transform
            Tvx = Tvxp
        if not Tvx[-1,-1]:
            raise ValueError("This operation only makes in-plane rotations. "\
                             "EG you cannot use the sagittal transform for "\
                             "an image in the coronal plane.")
        if (Tvx==np.identity(3)).all():
            print "Already in place, not transforming"
            return
        # this is for simple mixing of indices
        Tvx_abs = np.abs(Tvx)
        r0 = np.array([self.x0, self.y0, self.z0])
        dvx_0 = np.array([self.isize, self.jsize, self.ksize])
        # mix up the voxel sizes
        dvx_1 = np.dot(Tvx_abs, dvx_0)
        (self.isize, self.jsize, self.ksize) = dvx_1
        
        dim_sizes = np.array(self.shape[-3:][::-1])
        # solve for (i,j,k) where Tr*(i,j,k)^T + r0 = (0,0,0)        
        # columns are i,j,k space, so scale columns by vox sizes
        vx_0 = np.linalg.solve(Tr*dvx_0, -r0)
        # transform the voxels --
        # can normalize to {0..I-1},{0..J-1},{0..K-1} due to periodicity        
        vx_1 = (np.dot(Tvx, vx_0) + dim_sizes) % dim_sizes
        r0_prime = -np.dot(new_mapping*dvx_1, vx_1)
        (self.x0, self.y0, self.z0) = r0_prime
        if self.shape[-1] != self.shape[-2]:
            func = compose_xform(Tvx, view=False, square=False)
            if self.tdim:
                new_shape = (self.tdim,)
            else:
                new_shape = ()
            new_shape += tuple(np.dot(Tvx_abs, self.shape[::-1]).astype('i'))[::-1]
            temp = func(self[:])
            self.resize(new_shape)
            self[:] = temp.copy()
            del temp
        else:
            func = compose_xform(Tvx, view=False)
            func(self[:])
        self.orientation_xform = Quaternion(M=new_mapping)
예제 #3
0
    def transform(self, new_mapping=None, transform=None, force=False):
        """Updates the voxel to real-space transform.

        There are two modes of usage--
        1) supply a new voxel to real mapping.
           In this case a voxel to voxel transform is found, and the image
           is rotated in-plane around the origin. Only transposes and
           reflections are supported. Image info is updated appropriately

        2) supply a real to real transform to apply to the current mapping.
           In this case the data is not updated, but the mapping is updated.

        """
        if new_mapping is None and transform is None:
            return
        if new_mapping is not None and transform is not None:
            print """
            The user must specify either a new mapping to convert to,
            or a transform to apply, but cannot specify both."""
            return
        if transform is not None:
            # this doesn't change the image array, it just updates the
            # transformation
            old_xform = self.orientation_xform.tomatrix()
            if isinstance(transform, Quaternion):
                transform = transform.tomatrix()
            dim_scale = np.array([self.isize, self.jsize, self.ksize])
            r0 = np.array([self.x0, self.y0, self.z0])
            origin_voxels = np.round(
                np.linalg.solve(old_xform * dim_scale, -r0))
            # now derive r0 again.. Tmap*(i,j,k)^T + r0^T = (x,y,z)^T
            r0 = -np.dot(transform * dim_scale, origin_voxels)
            self.x0, self.y0, self.z0 = r0
            self.orientation_xform = Quaternion(M=transform)
            return
        # else handle the new mapping
        from recon.slicerimage import nearest_simple_transform
        # Tr already maps [i,j,k]^T into [R,A,S] ...
        # Here I want to change coordinates with this relationship:
        # Tr*[i,j,k]^T = Tnew*[i',j',k']^T
        # so Tnew*(Tvx*[i,j,k]^T) = Tr*[i,j,k]^T
        # So inv(Tnew)*Tr*[i,j,k] = [i',j',k'] = orientation of choice!
        # The task is to analyze Tvx = (Tnew^-1 * Tr) to get rotation

        Tr = self.orientation_xform.tomatrix()
        Tvx = np.linalg.solve(new_mapping, Tr)
        Tvxp = nearest_simple_transform(Tvx)
        # allow a goodly amount of wiggle room for each element of the
        # rotation matrix
        if not np.allclose(Tvxp, Tvx, atol=1e-4):
            # Tvxp might be a good choice in this case.. so could suggest
            # Tnew'*Tvxp = Tr
            # (Tvxp^T * Tnew'^T) = Tr^T
            # Tnew' = solve(Tvxp^T, Tr^T)^T
            Tnew_suggest = np.linalg.solve(Tvxp.T, Tr.T).T
            if not force:
                raise ValueError("""This method will not transform the data to
                the stated new mapping because the transformation cannot be
                accomplished through transposes and reflections. The closest new
                mapping you can perform is:\n""" + str(Tnew_suggest))
            else:
                print """It is not possible to rotate simply to the stated
                mapping; proceeding with this mapping:\n"""+str(Tnew_suggest)+\
                """\nbut lying about the final mapping."""
                #new_mapping = Tnew_suggest
                Tvx = Tvxp
        else:
            # if Tvx is adequately close to its trimmed version,
            # let's go ahead and use the simple transform
            Tvx = Tvxp
        if not Tvx[-1, -1]:
            raise ValueError("This operation only makes in-plane rotations. "\
                             "EG you cannot use the sagittal transform for "\
                             "an image in the coronal plane.")
        if (Tvx == np.identity(3)).all():
            print "Already in place, not transforming"
            return
        # this is for simple mixing of indices
        Tvx_abs = np.abs(Tvx)
        r0 = np.array([self.x0, self.y0, self.z0])
        dvx_0 = np.array([self.isize, self.jsize, self.ksize])
        # mix up the voxel sizes
        dvx_1 = np.dot(Tvx_abs, dvx_0)
        (self.isize, self.jsize, self.ksize) = dvx_1

        dim_sizes = np.array(self.shape[-3:][::-1])
        # solve for (i,j,k) where Tr*(i,j,k)^T + r0 = (0,0,0)
        # columns are i,j,k space, so scale columns by vox sizes
        vx_0 = np.linalg.solve(Tr * dvx_0, -r0)
        # transform the voxels --
        # can normalize to {0..I-1},{0..J-1},{0..K-1} due to periodicity
        vx_1 = (np.dot(Tvx, vx_0) + dim_sizes) % dim_sizes
        r0_prime = -np.dot(new_mapping * dvx_1, vx_1)
        (self.x0, self.y0, self.z0) = r0_prime
        if self.shape[-1] != self.shape[-2]:
            func = compose_xform(Tvx, view=False, square=False)
            if self.tdim:
                new_shape = (self.tdim, )
            else:
                new_shape = ()
            new_shape += tuple(np.dot(Tvx_abs,
                                      self.shape[::-1]).astype('i'))[::-1]
            temp = func(self[:])
            self.resize(new_shape)
            self[:] = temp.copy()
            del temp
        else:
            func = compose_xform(Tvx, view=False)
            func(self[:])
        self.orientation_xform = Quaternion(M=new_mapping)