Exemplo n.º 1
0
 def testEulers2(self):
     for i in range(100):
         y, p, r = randnums(3, -math.pi * 2, math.pi * 2)
         r1 = rotator(y, p, r)
         self.assertEqual(
             r1,
             rotator(0, 0, r) * rotator(y, 0, 0) * rotator(0, p, 0))
Exemplo n.º 2
0
 def testFromTo2(self):
     for i in range(100):
         x, y, z = randnums(3, -5, 5)
         v = vec3(x, y, z)
         r = rotator(v, -v)
         self.assertEqual(r, rotator(
             vec3(1, 0, 0).cross(v),
             0))  # TODO: wanted to actually test 180 degree rotators
Exemplo n.º 3
0
 def testMatrix1(self):
     for i in range(100):
         a = randangle()
         m = [
             math.cos(a), 0,
             math.sin(a), 0, 1, 0, -math.sin(a), 0,
             math.cos(a)
         ]
         r = rotator(*m)
         self.assertEqual(r, rotator(vec3(0, 1, 0), a))
Exemplo n.º 4
0
 def testMatrix3(self):
     for i in range(100):
         y, p, r = randnums(3, -math.pi * 2, math.pi * 2)
         r1 = rotator(y, p, r)
         y, p, r = randnums(3, -math.pi * 2, math.pi * 2)
         r2 = rotator(y, p, r)
         m1 = r1.toMatrix()
         m2 = r2.toMatrix()
         m = np.asarray(m1).dot(np.asarray(m2)).flat
         eqas_(listSum((r1 * r2).toMatrix()), m)
Exemplo n.º 5
0
 def testXis1(self):
     '''Test the xi values of points on the plane of a SharedImage, calls SharedImage.getPlaneXi().'''
     si = SharedImage('', vec3(), rotator(), (10, 10))
     self.assertEqual(vec3(), si.getPlaneXi(vec3()))
     self.assertEqual(vec3(1, 1), si.getPlaneXi(vec3(10, -10)))
     self.assertEqual(vec3(0.5, 0.5), si.getPlaneXi(vec3(5, -5)))
     self.assertEqual(vec3(0.5, 0.5), si.getPlaneXi(vec3(5, -5)))
Exemplo n.º 6
0
        def _loadAnalyzeFile(filename, name, imgObj, task):
            with f:
                filename = Future.get(filename)
                name = name or self.mgr.getUniqueObjName(
                    splitPathExt(filename)[1])
                img = imgObj or nibabel.load(filename)

                dat = dat = np.asanyarray(img.dataobj)
                hdr = dict(img.get_header())
                hdr['filename'] = filename

                pixdim = hdr['pixdim']
                interval = float(pixdim[4])

                if interval == 0.0 and len(
                        img.shape) == 4 and img.shape[-1] > 1:
                    interval = 1.0

                spacing = vec3(pixdim[1], pixdim[2], pixdim[3])
                dat = eidolon.transposeRowsColsNP(
                    dat)  # transpose from row-column to column-row

                obj = self.createObjectFromArray(name,
                                                 dat,
                                                 interval,
                                                 0,
                                                 vec3(),
                                                 rotator(),
                                                 spacing,
                                                 task=task)
                obj.source = hdr
                f.setObject(obj)
Exemplo n.º 7
0
 def testIdent1(self):
     '''Test the default rotator which should represent the identity transformation.'''
     for i in range(100):
         x, y, z = randnums(3, -5, 5)
         v = vec3(x, y, z)
         r = rotator()
         self.assertEqual(r * v, v)
Exemplo n.º 8
0
 def testInv1(self):
     for i in range(100):
         x, y, z = randnums(3, -5, 5)
         v = vec3(x, y, z)
         y, p, r = randnums(3, -math.pi * 2, math.pi * 2)
         r1 = rotator(y, p, r)
         self.assertEqual(r1 * (r1 / v), v)
Exemplo n.º 9
0
 def testMatrix2(self):
     for i in range(100):
         a = randangle()
         r = rotator(vec3(1, 0, 0), a)
         eqas_(listSum(r.toMatrix()),
               (1, 0, 0, 0, 0, math.cos(a), -math.sin(a), 0, 0, math.sin(a),
                math.cos(a), 0, 0, 0, 0, 1))
Exemplo n.º 10
0
 def testXis2(self):
     '''Test the xi values of corners of a SharedImage, calls getPlaneXi().'''
     si = SharedImage('', vec3(1, -2, 3), rotator(0.1, -0.2, 0.3), (10, 10),
                      (0.678, 0.789))
     corners = si.getCorners()
     self.assertEqual(vec3(), si.getPlaneXi(corners[0]))
     self.assertEqual(vec3(1, 1), si.getPlaneXi(corners[-1]))
     self.assertEqual(vec3(0.5, 0.5), si.getPlaneXi(si.center))
Exemplo n.º 11
0
 def testXis3(self):
     '''Test the xi values of points on the plane of a SharedImage, calls SharedImage.getPlaneXi().'''
     pos = vec3(5, -6, 7)
     si = SharedImage('', pos, rotator(), (10, 10))
     self.assertEqual(vec3(), si.getPlaneXi(pos))
     self.assertEqual(vec3(1, 1), si.getPlaneXi(pos + vec3(10, -10)))
     self.assertEqual(vec3(0.5, 0.5, 5),
                      si.getPlaneXi(pos + vec3(5, -5, 5)))
Exemplo n.º 12
0
 def testXis4(self):
     '''Test the xi values of points on the plane of a SharedImage, calls SharedImage.getPlaneXi().'''
     pos = vec3(5, -6, 7)
     dim = (0.678, 0.789)
     si = SharedImage('', pos, rotator(), (10, 10), dim)
     self.assertEqual(vec3(), si.getPlaneXi(pos))
     self.assertEqual(vec3(1, 1),
                      si.getPlaneXi(pos + vec3(10 * dim[0], -10 * dim[1])))
     self.assertEqual(vec3(0.5, 0.5, 5),
                      si.getPlaneXi(pos + vec3(5 * dim[0], -5 * dim[1], 5)))
Exemplo n.º 13
0
    def setUp(self):
        self.tempdir = tempfile.mkdtemp()
        self.plugin = eidolon.getSceneMgr().getPlugin('Nifti')

        self.vfunc = lambda x, y, z, t: (x + 1) * 1000 + (y + 1) * 100 + (
            z + 1) * 10 + t + 1
        self.volarr = np.fromfunction(self.vfunc, (21, 33, 46, 17))
        self.vpos = vec3(-10, 20, -15)
        self.vrot = rotator(0.1, -0.2, 0.13)

        self.vol = self.plugin.createObjectFromArray('TestVolume',
                                                     self.volarr,
                                                     pos=self.vpos,
                                                     rot=self.vrot)
Exemplo n.º 14
0
def importImages(x4, plugin):
    '''
    Import images from the X4DF object `x4', returning a list of ImageSceneObject instances. The `plugin' must be an
    ImageScenePlugin instance used to create the objects.
    '''
    arrs = {a.name: a for a in x4.arrays}
    results = []

    for im in x4.images:
        name, timescheme, trans, imagedata, _ = im
        images = []
        filenames = []
        tstart, tstep = timescheme or (0, 0)
        trans = trans or idTransform

        for i, imgdat in enumerate(imagedata):
            src, timestep, imgtrans, _ = imgdat
            arr = arrs[src].data
            imgtrans = imgtrans or trans

            filenames.append(arrs[src].filename)

            if timestep is None:
                offset, interval = tstart, tstep
            else:
                offset, interval = tstart + i * tstep, 0

            arr = reverseAxes(
                arr
            )  # array is stored in inverse index order from what is expected

            pos = vec3(*imgtrans.position)
            rot = rotator(*imgtrans.rmatrix.flatten())
            spacing = vec3(*imgtrans.scale) * vec3(
                arr.shape[1], arr.shape[0],
                arr.shape[2] if len(arr.shape) > 2 else 0).inv()

            obj = plugin.createObjectFromArray('tmp', arr, interval, offset,
                                               pos, rot, spacing)
            images += obj.images

        results.append(
            eidolon.ImageSceneObject(name,
                                     None,
                                     images,
                                     filenames=list(filter(bool, filenames))))

    return results
Exemplo n.º 15
0
    def loadImageStackObject(self,name,filenames,pos=vec3(),rot=rotator(),spacing=(1.0,1.0),imgsep=1.0,sortIndex=None,regex=None,reverse=False,task=None):
        '''
        Loads a stack of images (or a sequence of stacks), ordered bottom up, into a ImageSceneObject. If
        `sortIndex' is not None, this is the sorting index in the file names used to sort the stack. The start
        position `pos' is intepreted as the top left position of the bottom-most image. If `filenames' is a list
        of filenames only, the series is not timed, however if it's a list of lists of filenames then each sublist
        is (optionally) sorted and then loaded into a time series object.
        '''

        isTimed=eidolon.isIterable(filenames[0]) and not isinstance(filenames[0],str)

        if isTimed:
            if sortIndex!=None:
                filenames=[sortFilenameList(fn,sortIndex,regex) for fn in filenames]

            if reverse:
                for f in filenames:
                    f.reverse()

            positions=[pos+(rot*vec3(0,0,imgsep*i)) for i in range(len(filenames[0]))]

            imagesteps=[loadImageStack(fn,self.mgr.scene.loadImageFile,positions,rot,spacing,task) for fn in filenames]

            for i,imgs in enumerate(imagesteps):
                for img in imgs:
                    img.timestep=i

            images=listSum(imagesteps)
            filenames=listSum(filenames)
        else:
            if sortIndex!=None:
                filenames=sortFilenameList(filenames,sortIndex,regex)

            if reverse:
                filenames.reverse()

            positions=[pos+(rot*vec3(0,0,imgsep*i)) for i in range(len(filenames))]

            images=loadImageStack(filenames,self.mgr.scene.loadImageFile,positions,rot,spacing,task)

        return self.createSceneObject(name,images,filenames,isTimed)
Exemplo n.º 16
0
def getTransformFromInfo(offcenter, angulation, sliceorient, spacing,
                         dimensions):
    '''
    Returns a (vec3,rotator) pair for the position and orientation of an image given the ParRec parameters for
    offcenter position, angulation in degrees, slice orientation value from SliceOrientations, pixel spacing,
    and image dimensions.
    '''
    cy, cz, cx = offcenter
    theta, phi, rho = map(math.radians, angulation)
    refmat = np.array([[-1, 0, 0], [0, 0, 1], [0, -1, 0]])
    AFRtoLPS = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]])
    torient = np.eye(3)

    # get the slice orientation transform matrix
    if sliceorient == SliceOrientations.Transverse:
        torient = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, -1]])
    elif sliceorient == SliceOrientations.Sagittal:
        torient = np.array([[-1, 0, 0], [0, 0, -1], [0, 1, 0]])
    elif sliceorient == SliceOrientations.Coronal:
        torient = np.array([[0, 0, -1], [1, 0, 0], [0, 1, 0]])

    # convert angulation values to rotation matrices
    tap = np.array([[1, 0, 0], [0, math.cos(theta), -math.sin(theta)],
                    [0, math.sin(theta), math.cos(theta)]])
    tfh = np.array([[math.cos(phi), 0, math.sin(phi)], [0, 1, 0],
                    [-math.sin(phi), 0, math.cos(phi)]])
    trl = np.array([[math.cos(rho), -math.sin(rho), 0],
                    [math.sin(rho), math.cos(rho), 0], [0, 0, 1]])

    # compose transformations and convert to a rotator object
    dirmat = AFRtoLPS.dot(trl).dot(tap).dot(tfh).dot(refmat).dot(torient)
    rot = rotator(*dirmat.flat)

    # Since rotation is defined at the center of the image, need to add a rotated mid vector to the
    # position which is instead defined at the top left corner.
    midoffset = ((spacing * vec3(1, -1, 1)) *
                 (dimensions - vec3(1))) * 0.5 - spacing * vec3(0.5, -0.5, 0)
    pos = vec3(cx, cy, cz) - (rot * midoffset)

    return pos, rot
Exemplo n.º 17
0
 def testEulers5(self):
     for i in range(100):
         a = randangle()
         self.assertEqual(rotator(0, 0, a), rotator(vec3(0, 1, 0), a))
Exemplo n.º 18
0
 def testIdent2(self):
     '''Test a rotator specified as the angle around the zero vector is an identity transformation.'''
     r = rotator(vec3(), randangle())
     self.assertEqual(r, rotator())
Exemplo n.º 19
0
        def _saveFile(path, obj, kwargs, task):
            with f:
                assert isinstance(obj, ImageSceneObject)

                if os.path.isdir(path):
                    path = os.path.join(path, obj.getName())

                if not overwrite and os.path.exists(path):
                    raise IOError('File already exists: %r' % path)

                if not eidolon.hasExtension(path, 'nii', 'nii.gz'):
                    path += '.nii'

                if 'datatype' in kwargs:
                    datatype = kwargs.pop('datatype')
                elif isinstance(obj.source, dict) and 'datatype' in obj.source:
                    datatype = data_type_codes.dtype[int(
                        obj.source['datatype'])]
                else:
                    datatype = np.float32

                mat = self.getImageObjectArray(obj, datatype)
                dat = mat['array']
                pos = mat['pos']
                spacex, spacey, spacez = mat['spacing']
                rot = rotator(vec3(0, 0, 1), math.pi) * mat['rot'] * rotator(
                    vec3(0, 0, 1), -halfpi)
                toffset = mat['toffset']
                interval = mat['interval']

                affine = np.array(rot.toMatrix())
                affine[:, 3] = -pos.x(), -pos.y(), pos.z(), 1.0

                dat = eidolon.transposeRowsColsNP(
                    dat)  # transpose from row-column to column-row

                imgobj = nibabel.nifti1.Nifti1Image(dat, affine)

                # header info: http://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h
                hdr = {
                    'pixdim':
                    np.array([
                        1.0, spacex, spacey, spacez if spacez != 0.0 else 1.0,
                        interval, 1.0, 1.0, 1.0
                    ], np.float32),
                    'toffset':
                    toffset,
                    'slice_duration':
                    interval,
                    'xyzt_units':
                    unit_codes['mm'] | unit_codes['msec'],
                    'qform_code':
                    xform_codes['aligned'],
                    'sform_code':
                    xform_codes['scanner'],
                    'datatype':
                    data_type_codes.code[datatype]
                }

                hdr.update(kwargs)

                for k, v in hdr.items():
                    if k in imgobj.header:
                        imgobj.header[k] = v

                nibabel.save(imgobj, path)

                if setFilenames:
                    obj.plugin.removeObject(obj)
                    obj.plugin = self
                    obj.source = dict(nibabel.load(path).get_header())
                    obj.source['filename'] = path
                elif isinstance(obj.source, dict) and 'filename' in obj.source:
                    obj.source['filename'] = path

                f.setObject(imgobj)
Exemplo n.º 20
0
 def testPlaneXiFunc(self):
     '''Tests the getPlaneXi function directly.'''
     v = vec3(*randnums(3, -5, 5))
     r = rotator(*randnums(4, -1, 1))
     self.assertEqual(vec3(0), getPlaneXi(v, v, r, vec3(1)))
Exemplo n.º 21
0
        def _loadNiftiFile(filename, name, imgObj, task):
            with f:
                filename = Future.get(filename)
                name = name or self.mgr.getUniqueObjName(
                    splitPathExt(filename)[1])
                img = imgObj or nibabel.load(filename)

                hdr = dict(img.header)
                hdr['filename'] = filename

                pixdim = hdr['pixdim']
                xyzt_units = hdr['xyzt_units']
                x = float(hdr['qoffset_x'])
                y = float(hdr['qoffset_y'])
                z = float(hdr['qoffset_z'])
                b = float(hdr['quatern_b'])
                c = float(hdr['quatern_c'])
                d = float(hdr['quatern_d'])
                toffset = float(hdr['toffset'])
                interval = float(pixdim[4])

                if interval == 0.0 and len(
                        img.shape) == 4 and img.shape[-1] > 1:
                    interval = 1.0

                qfac = float(pixdim[0]) or 1.0
                spacing = vec3(pixdim[1], pixdim[2], qfac * pixdim[3])

                if int(hdr['qform_code']) > 0:
                    position = vec3(-x, -y, z)
                    rot = rotator(
                        -c, b, math.sqrt(max(0, 1.0 -
                                             (b * b + c * c + d * d))),
                        -d) * rotator(vec3.Z(), halfpi)
                else:
                    affine = img.get_affine()
                    position = vec3(-affine[0, 3], -affine[1, 3], affine[2, 3])
                    rmat = np.asarray([
                        affine[0, :3] / -spacing.x(),
                        affine[1, :3] / -spacing.y(),
                        affine[2, :3] / spacing.z()
                    ])
                    rot = rotator(*rmat.flatten().tolist()) * rotator(
                        vec3.Z(), halfpi)

                xyzunit = xyzt_units & 0x07  # isolate space units with a bitmask of 7
                tunit = xyzt_units & 0x38  # isolate time units with a bitmask of 56

                if tunit == 0:  # if no tunit provided, try to guess
                    if interval < 1.0:
                        tunit = unit_codes['sec']
                    elif interval > 1000.0:
                        tunit = unit_codes['usec']

                # convert to millimeters
                if xyzunit == unit_codes['meter']:
                    position *= 1000.0
                    spacing *= 1000.0
                elif xyzunit == unit_codes['micron']:
                    position /= 1000.0
                    spacing /= 1000.0

                # convert to milliseconds
                if tunit == unit_codes['sec']:
                    toffset *= 1000.0
                    interval *= 1000.0
                elif tunit == unit_codes['usec']:
                    toffset /= 1000.0
                    interval /= 1000.0

                dobj = img.dataobj
                datshape = tuple(
                    d or 1 for d in dobj.shape
                )  # dimensions are sometimes given as 0 for some reason?

                # reading file data directly is expected to be faster than using nibabel, specifically by using memmap
                if filename.endswith('.gz'):
                    dat = img.get_data()
                    #dat=np.asanyarray(dobj) # same as the above

#                    with gzip.open(filename) as o: # TODO: not sure if this is any faster than the above
#                        o.seek(dobj.offset) # seek beyond the header
#                        dat=np.frombuffer(o.read(),dobj.dtype).reshape(datshape,order=dobj.order)
                else:
                    # mmap the image data below the header in the file
                    dat = np.memmap(dobj.file_like, dobj.dtype, 'r',
                                    dobj.offset, datshape, dobj.order)

                dat = eidolon.transposeRowsColsNP(
                    dat)  # transpose from row-column to column-row

                obj = self.createObjectFromArray(name,
                                                 dat,
                                                 interval,
                                                 toffset,
                                                 position,
                                                 rot,
                                                 spacing,
                                                 task=task)
                obj.source = hdr

                # apply slope since this isn't done automatically when using memmap/gzip
                if not filename.endswith('.gz'):
                    eidolon.applySlopeIntercept(obj,
                                                *img.header.get_slope_inter())

                f.setObject(obj)
Exemplo n.º 22
0
    def testRot1(self):
        '''Tests the creation of a SharedImage with the default vec3 and rotator value, calls SharedImage.getPlaneXi().'''
        si = SharedImage('', vec3(), rotator(), (1, 1))

        self.assertEqual(vec3(1), si.getPlaneXi(vec3(1, -1, 1)))
Exemplo n.º 23
0
 def testPlaneDef3(self):
     r = rotator(vec3(1, 0, 0), vec3(0, 0, 1), vec3(1, 0, 0), vec3(0, 1, 0))
     eqas_(r.getEulers(), (0, halfpi, 0))
Exemplo n.º 24
0
 def testAxis2(self):
     r = rotator(vec3(0, 0, -1), halfpi)
     eqas_(r.getEulers(), (-halfpi, 0, 0))
Exemplo n.º 25
0
 def testFromTo1(self):
     r = rotator(vec3(1, 0, 0), vec3(0, 1, 0))
     self.assertEqual(r, rotator(vec3(0, 0, 1), halfpi))
Exemplo n.º 26
0
 def testEulers1(self):
     for i in range(100):
         y, p, r = randnums(3, -math.pi * 2, math.pi * 2)
         r1 = rotator(y, p, r)
         self.assertEqual(r1, rotator(*r1.getEulers()))
Exemplo n.º 27
0
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# Eidolon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program (LICENSE.txt).  If not, see <http://www.gnu.org/licenses/>

from eidolon import ReprType,vec3, rotator,generateArrow,halfpi, MeshSceneObject,TriDataSet,AxesType

pos=vec3(-10,20,-15)
rot=rotator(0.1,-0.2,0.13)
w,h,d=31,42,53

nodesz,indsz=generateArrow(5)
nodesz=[(n+vec3.Z())*vec3(w,d,h)*vec3(0.1,0.1,0.5) for n in nodesz]
nodesx=[rotator(vec3(0,1,0),halfpi)*n for n in nodesz]
nodesy=[rotator(vec3(1,0,0),-halfpi)*n for n in nodesz]

nodes=[(rot*n)+pos for n in (nodesx+nodesy+nodesz)]
nlen=len(nodesz)
indices=indsz+[(i+nlen,j+nlen,k+nlen) for i,j,k in indsz]+[(i+nlen*2,j+nlen*2,k+nlen*2) for i,j,k in indsz]
field=[2.0]*nlen+[1.0]*nlen+[0.0]*nlen

axes=MeshSceneObject('Axes',TriDataSet('tris',nodes,indices,[('col',field)]))
mgr.addSceneObject(axes)
Exemplo n.º 28
0
 def testFullCircle1(self):
     r = rotator(vec3(1, 0, 0), math.pi * 2)
     self.assertEqual(r, rotator())