コード例 #1
0
ファイル: scene3dcanvas.py プロジェクト: laurenpan02/fsleyes
    def lightPos(self):
        """Takes the values of :attr:`.Scene3DOpts.lightPos` and
        :attr:`.Scene3DOpts.lightDistance`, and converts it to a position in
        the display coordinate system. The ``Scene3DOpts.lightPos`` property
        contains rotations about the centre of the display bounding box,
        and the :attr:`.Scene3DOpts.lightDistance` property specifies the
        distance of the light from the bounding box centre.
        """
        b = self.__displayCtx.bounds
        centre = np.array([
            b.xlo + 0.5 * (b.xhi - b.xlo), b.ylo + 0.5 * (b.yhi - b.ylo),
            b.zlo + 0.5 * (b.zhi - b.zlo)
        ])

        yaw, pitch, roll = self.opts.lightPos
        distance = self.opts.lightDistance
        yaw = yaw * np.pi / 180
        pitch = pitch * np.pi / 180
        roll = roll * np.pi / 180

        rotmat = affine.axisAnglesToRotMat(pitch, roll, yaw)
        xform = affine.compose([1, 1, 1], [0, 0, 0], rotmat, origin=centre)

        lightPos = centre + [0, 0, distance * b.zlen]
        lightPos = affine.transform(lightPos, xform)

        return lightPos
コード例 #2
0
def test_newImage():
    shape  = (10, 20, 30)
    pixdim = (1.3, -5.4, 3.2)
    dtype  = np.uint8
    affine = fslaffine.compose((2, 3, 4), (-20, 15, 25), (1.5, 1.2, -2.1))

    img    = newimage.newImage(shape, pixdim, dtype, affine)

    assert tuple( img.shape)        == shape
    assert tuple( img.pixdim)       == tuple(np.abs(pixdim))
    assert        img.dtype         == dtype
    assert np.all(img.voxToWorldMat == affine)
    assert        img.xyzUnits      == constants.NIFTI_UNITS_MM
    assert        img.timeUnits     == constants.NIFTI_UNITS_SEC
    assert        img.name          == 'new'

    img = newimage.newImage(shape, pixdim, dtype, affine,
                            xyzUnits=constants.NIFTI_UNITS_METER,
                            timeUnits=constants.NIFTI_UNITS_MSEC,
                            name='whaa')

    assert tuple( img.shape)        == shape
    assert tuple( img.pixdim)       == tuple(np.abs(pixdim))
    assert        img.dtype         == dtype
    assert np.all(img.voxToWorldMat == affine)
    assert        img.xyzUnits      == constants.NIFTI_UNITS_METER
    assert        img.timeUnits     == constants.NIFTI_UNITS_MSEC
    assert        img.name          == 'whaa'
コード例 #3
0
def test_applyDeformation_altref():
    src2ref = affine.compose(
        np.random.randint(2, 5, 3),
        np.random.randint(1, 10, 3),
        np.random.random(3))
    ref2src = affine.invert(src2ref)

    srcdata = np.random.randint(1, 65536, (10, 10, 10))
    refdata = np.random.randint(1, 65536, (10, 10, 10))

    src   = fslimage.Image(srcdata)
    ref   = fslimage.Image(refdata, xform=src2ref)
    field = _affine_field(src, ref, ref2src, 'world', 'world')

    altrefxform = affine.concat(
        src2ref,
        affine.scaleOffsetXform([1, 1, 1], [5, 0, 0]))

    altref = fslimage.Image(refdata, xform=altrefxform)

    expect, xf = resample.resampleToReference(
        src, altref, matrix=src2ref, order=1, mode='constant', cval=0)
    result = nonlinear.applyDeformation(
        src, field, ref=altref, order=1, mode='constant', cval=0)

    # boundary voxels can get truncated
    # (4 is the altref-ref overlap boundary)
    expect[4, :, :] = 0
    result[4, :, :] = 0
    expect = expect[1:-1, 1:-1, 1:-1]
    result = result[1:-1, 1:-1, 1:-1]

    assert np.all(np.isclose(expect, result))
コード例 #4
0
def test_convert_flirt():
    with tempdir.tempdir():
        src = random_image()
        ref = random_image()
        src.save('src')
        ref.save('ref')

        xform = affine.compose(np.random.randint(1, 10, 3),
                               np.random.randint(-100, 100, 3),
                               (np.random.random(3) - 0.5) * np.pi)

        np.savetxt('src2ref.mat', xform)

        fsl_convert_x5.main('flirt -s src -r ref '
                            'src2ref.mat src2ref.x5'.split())
        expxform = affine.concat(ref.getAffine('fsl', 'world'), xform,
                                 src.getAffine('world', 'fsl'))
        gotxform, gotsrc, gotref = x5.readLinearX5('src2ref.x5')
        assert np.all(np.isclose(gotxform, expxform))
        assert src.sameSpace(gotsrc)
        assert ref.sameSpace(gotref)

        fsl_convert_x5.main('flirt src2ref.x5 src2ref_copy.mat'.split())

        gotxform = flirt.readFlirt('src2ref_copy.mat')
        assert np.all(np.isclose(gotxform, xform))
コード例 #5
0
def _random_image():
    vx, vy, vz = np.random.randint(10, 50, 3)
    dx, dy, dz = np.random.randint(1, 10, 3)
    data = (np.random.random((vx, vy, vz)) - 0.5) * 10
    aff = affine.compose((dx, dy, dz), np.random.randint(1, 100, 3),
                         np.random.random(3) * np.pi / 2)

    return fslimage.Image(data, xform=aff)
コード例 #6
0
def test_applyDeformation_premat():

    src2ref = affine.compose(
        np.random.randint(2, 5, 3),
        np.random.randint(1, 10, 3),
        [0, 0, 0])
    ref2src = affine.invert(src2ref)

    srcdata = np.random.randint(1, 65536, (10, 10, 10))
    refdata = np.random.randint(1, 65536, (10, 10, 10))

    src   = fslimage.Image(srcdata)
    ref   = fslimage.Image(refdata, xform=src2ref)
    field = _affine_field(src, ref, ref2src, 'world', 'world')

    # First try a down-sampled version
    # of the original source image
    altsrc, xf = resample.resample(src, (5, 5, 5), origin='corner')
    altsrc     = fslimage.Image(altsrc, xform=xf, header=src.header)
    expect, xf = resample.resampleToReference(
        altsrc, ref, matrix=src2ref, order=1, mode='nearest')
    premat = affine.concat(src   .getAffine('world', 'voxel'),
                           altsrc.getAffine('voxel', 'world'))
    result = nonlinear.applyDeformation(
        altsrc, field, order=1, mode='nearest', premat=premat)
    assert np.all(np.isclose(expect, result))

    # Now try a down-sampled ROI
    # of the original source image
    altsrc     = roi.roi(src, [(2, 9), (2, 9), (2, 9)])
    altsrc, xf = resample.resample(altsrc, (4, 4, 4))
    altsrc     = fslimage.Image(altsrc, xform=xf, header=src.header)
    expect, xf = resample.resampleToReference(
        altsrc, ref, matrix=src2ref, order=1, mode='nearest')
    premat = affine.concat(src   .getAffine('world', 'voxel'),
                           altsrc.getAffine('voxel', 'world'))
    result = nonlinear.applyDeformation(
        altsrc, field, order=1, mode='nearest', premat=premat)
    assert np.all(np.isclose(expect, result))

    # down-sampled and offset ROI
    # of the original source image
    altsrc     = roi.roi(src, [(-5, 8), (-5, 8), (-5, 8)])
    altsrc, xf = resample.resample(altsrc, (6, 6, 6))
    altsrc     = fslimage.Image(altsrc, xform=xf, header=src.header)
    expect, xf = resample.resampleToReference(
        altsrc, ref, matrix=src2ref, order=1, mode='nearest')
    premat = affine.concat(src   .getAffine('world', 'voxel'),
                           altsrc.getAffine('voxel', 'world'))
    result = nonlinear.applyDeformation(
        altsrc, field, order=1, mode='nearest', premat=premat)
    assert np.all(np.isclose(expect, result))
コード例 #7
0
ファイル: test_flirt.py プロジェクト: physimals/fslpy
def test_toFlirt():

    src = affine.compose(np.random.randint(1, 5, 3),
                         np.random.randint(-20, 20, 3),
                         np.random.random(3) - 0.5)
    ref = affine.compose(np.random.randint(1, 5, 3),
                         np.random.randint(-20, 20, 3),
                         np.random.random(3) - 0.5)

    src = fslimage.Image(make_random_image(xform=src))
    ref = fslimage.Image(make_random_image(xform=ref))
    flirtmat = affine.concat(ref.getAffine('world', 'fsl'),
                             src.getAffine('fsl', 'world'))

    spaces = it.permutations(('voxel', 'fsl', 'world'), 2)

    for from_, to in spaces:
        xform = affine.concat(ref.getAffine('world', to),
                              src.getAffine(from_, 'world'))
        got = flirt.toFlirt(xform, src, ref, from_, to)

        assert np.all(np.isclose(got, flirtmat))
コード例 #8
0
def oblique(infile):

    basename = fslimage.removeExt(op.basename(infile))
    outfile = '{}_oblique.nii.gz'.format(basename)
    img = fslimage.Image(infile)
    xform = img.getAffine('voxel', 'world')
    rot = affine.compose([1, 1, 1], [0, 0, 0], [0, 0, 1])
    xform = affine.concat(rot, xform)
    img = fslimage.Image(img.data, xform=xform)

    img.save(outfile)

    return outfile
コード例 #9
0
ファイル: newimage.py プロジェクト: marcobarilari/fsleyes
    def __onPixdim(self, ev):
        """Called when any pixdim widget changes. If linking is enabled,
        reconstructs the affine with the new pixdim values.
        """
        if not self.link:
            return

        # If we construct an affine with
        # scales == 0, we get explosions
        if any([p == 0 for p in self.pixdim]):
            return

        offsets, rotations = fslaffine.decompose(self.affine)[1:]
        self.affine = fslaffine.compose(self.pixdim, offsets, rotations)
コード例 #10
0
ファイル: test_affine.py プロジェクト: physimals/fslpy
def test_transform_vector(seed):

    # Some transform with a
    # translation component
    xform = affine.compose([1, 2, 3], [5, 10, 15], [np.pi / 2, np.pi / 2, 0])

    vecs = np.random.random((20, 3))

    for v in vecs:

        vecExpected = np.dot(xform, list(v) + [0])[:3]
        ptExpected = np.dot(xform, list(v) + [1])[:3]

        vecResult = affine.transform(v, xform, vector=True)
        vec33Result = affine.transform(v, xform[:3, :3], vector=True)
        ptResult = affine.transform(v, xform, vector=False)

        assert np.all(np.isclose(vecExpected, vecResult))
        assert np.all(np.isclose(vecExpected, vec33Result))
        assert np.all(np.isclose(ptExpected, ptResult))
コード例 #11
0
ファイル: test_affine.py プロジェクト: physimals/fslpy
def test_transformNormal(seed):

    normals = -100 + 200 * np.random.random((50, 3))

    def tn(n, xform):

        xform = npla.inv(xform[:3, :3]).T
        return np.dot(xform, n)

    for n in normals:

        scales = -10 + np.random.random(3) * 10
        offsets = -100 + np.random.random(3) * 200
        rotations = -np.pi + np.random.random(3) * 2 * np.pi
        origin = -100 + np.random.random(3) * 200

        xform = affine.compose(scales, offsets, rotations, origin)

        expected = tn(n, xform)
        result = affine.transformNormal(n, xform)

        assert np.all(np.isclose(expected, result))
コード例 #12
0
def _test_NewImageAction_existing(panel, overlayList, displayCtx):
    act = panel.frame.menuActions[newimage.NewImageAction]

    img = newimage.newImage((20, 30, 40),
                            (1.5, 1, 2.5),
                            np.int32,
                            fslaffine.compose((-1.5, 1, 2.5),
                                              (-20, 30, 40),
                                              (1.5, 1.2, -1.5)))

    overlayList.append(img)
    realYield()

    with mock.patch('fsleyes.actions.newimage.NewImageDialog', MockNewImageDialog):
        MockNewImageDialog.ShowModalRet = wx.ID_OK
        MockNewImageDialog.initOverride = True
        act()
        realYield()
        assert len(overlayList) == 2

        old, new = overlayList
        assert old.sameSpace(new)
        assert new.dtype == np.int32
コード例 #13
0
ファイル: test_x5.py プロジェクト: physimals/fslpy
def test_readWriteLinearX5():
    with tempdir.tempdir():
        make_random_image('src.nii')
        make_random_image('ref.nii')
        xform = affine.compose(np.random.randint(1, 5, 3),
                               np.random.randint(-10, 10, 3),
                               -np.pi / 4 + np.random.random(3) * np.pi / 2)

        src = fslimage.Image('src.nii')
        ref = fslimage.Image('ref.nii')

        x5.writeLinearX5('linear.x5', xform, src, ref)

        gotxform, gotsrc, gotref = x5.readLinearX5('linear.x5')
        assert np.all(np.isclose(gotxform, xform))
        assert gotsrc.sameSpace(src)
        assert gotref.sameSpace(ref)

        with h5py.File('linear.x5', 'r') as f:
            _check_metadata(f)
            assert f.attrs['Type'] == 'linear'
            _check_affine(f['/Transform'], xform)
            _check_space(f['/A'], src)
            _check_space(f['/B'], ref)
コード例 #14
0
def _test_NewImageAction(panel, overlayList, displayCtx):
    act = panel.frame.menuActions[newimage.NewImageAction]

    def check(ovl, shape, pixdim, dtype, affine):
        assert tuple( ovl.shape)        == tuple(shape)
        assert tuple( ovl.pixdim)       == tuple(pixdim)
        assert        ovl.dtype         == dtype
        assert np.all(ovl.voxToWorldMat == affine)

    tests = [
        ((100, 100, 100), (1,   1,   1),   np.float32, np.eye(4)),
        (( 50,  50,  50), (2,   2,   2),   np.uint8,   np.diag([2, 2, 2, 1])),
        (( 20,  30,  40), (1.5, 1.2, 1.3), np.int32,   fslaffine.scaleOffsetXform([2, 3, 4], [-4, -3, -2])),
        ((100, 100, 100), (1,   1,   1),   np.float64, fslaffine.compose((2, 3, 1), (1, 2, 3), (1, 1.5, 2))),
    ]

    with mock.patch('fsleyes.actions.newimage.NewImageDialog', MockNewImageDialog):
        MockNewImageDialog.ShowModalRet = wx.ID_CANCEL
        MockNewImageDialog.initOverride = False
        act()
        realYield()
        assert len(overlayList) == 0

        MockNewImageDialog.ShowModalRet = wx.ID_OK

        for shape, pixdim, dtype, affine in tests:
            MockNewImageDialog.shapeRet  = shape
            MockNewImageDialog.pixdimRet = pixdim
            MockNewImageDialog.dtypeRet  = dtype
            MockNewImageDialog.affineRet = affine
            act()
            realYield()
            assert len(overlayList) == 1
            check(overlayList[0], shape, pixdim, dtype, affine)
            overlayList.clear()
            realYield()
コード例 #15
0
def test_convert_flirt_sameformat():
    with tempdir.tempdir():
        src = random_image()
        ref = random_image()
        src.save('src')
        ref.save('ref')

        xform = affine.compose(np.random.randint(1, 10, 3),
                               np.random.randint(-100, 100, 3),
                               (np.random.random(3) - 0.5) * np.pi)

        np.savetxt('src2ref.mat', xform)

        # test both .mat and .x5
        fsl_convert_x5.main('flirt -s src -r ref '
                            'src2ref.mat src2ref.x5'.split())

        # mat -> mat
        fsl_convert_x5.main('flirt -s src -r ref '
                            'src2ref.mat copy.mat'.split())

        # x5 -> x5
        fsl_convert_x5.main('flirt -s src -r ref '
                            'src2ref.x5 copy.x5'.split())

        with open('src2ref.mat', 'rb') as f:
            origmat = hashlib.md5(f.read()).digest()
        with open('copy.mat', 'rb') as f:
            copymat = hashlib.md5(f.read()).digest()
        with open('src2ref.x5', 'rb') as f:
            origx5 = hashlib.md5(f.read()).digest()
        with open('copy.x5', 'rb') as f:
            copyx5 = hashlib.md5(f.read()).digest()

        assert origmat == copymat
        assert origx5 == copyx5
コード例 #16
0
def random_affine():
    return compose(np.random.randint(1, 10, 3), np.random.randint(-50, 50, 3),
                   np.random.randint(-3, 3, 3))
コード例 #17
0
ファイル: test_affine.py プロジェクト: physimals/fslpy
def test_compose_and_decompose():

    testfile = op.join(datadir, 'test_transform_test_compose.txt')
    lines = readlines(testfile)
    ntests = len(lines) // 4

    for i in range(ntests):

        xform = lines[i * 4:i * 4 + 4]
        xform = np.genfromtxt(xform)

        scales, offsets, rotations, shears = affine.decompose(xform,
                                                              shears=True)

        result = affine.compose(scales, offsets, rotations, shears=shears)

        assert np.all(np.isclose(xform, result, atol=1e-5))

        # The decompose function does not support a
        # different rotation origin, but we test
        # explicitly passing the origin for
        # completeness
        scales, offsets, rotations, shears = affine.decompose(xform,
                                                              shears=True)
        result = affine.compose(scales,
                                offsets,
                                rotations,
                                origin=[0, 0, 0],
                                shears=shears)

        assert np.all(np.isclose(xform, result, atol=1e-5))

    # compose should also accept a rotation matrix
    rots = [np.pi / 5, np.pi / 4, np.pi / 3]
    rmat = affine.axisAnglesToRotMat(*rots)
    xform = affine.compose([1, 1, 1], [0, 0, 0], rmat)

    # And the angles flag should cause decompose
    # to return the rotation matrix, instead of
    # the axis angls
    sc, of, rot = affine.decompose(xform)
    scat, ofat, rotat = affine.decompose(xform, angles=True)
    scaf, ofaf, rotaf = affine.decompose(xform, angles=False)

    sc, of, rot = np.array(sc), np.array(of), np.array(rot)
    scat, ofat, rotat = np.array(scat), np.array(ofat), np.array(rotat)
    scaf, ofaf, rotaf = np.array(scaf), np.array(ofaf), np.array(rotaf)

    assert np.all(np.isclose(sc, [1, 1, 1]))
    assert np.all(np.isclose(of, [0, 0, 0]))
    assert np.all(np.isclose(scat, [1, 1, 1]))
    assert np.all(np.isclose(ofat, [0, 0, 0]))
    assert np.all(np.isclose(scaf, [1, 1, 1]))
    assert np.all(np.isclose(ofaf, [0, 0, 0]))

    assert np.all(np.isclose(rot, rots))
    assert np.all(np.isclose(rotat, rots))
    assert np.all(np.isclose(rotaf, rmat))

    # decompose should accept a 3x3
    # affine, and return translations of 0
    affine.decompose(xform[:3, :3])
    sc, of, rot = affine.decompose(xform[:3, :3])
    sc, of, rot = np.array(sc), np.array(of), np.array(rot)
    assert np.all(np.isclose(sc, [1, 1, 1]))
    assert np.all(np.isclose(of, [0, 0, 0]))
    assert np.all(np.isclose(rot, rots))
コード例 #18
0
ファイル: test_fsl_apply_x5.py プロジェクト: physimals/fslpy
def _random_affine():
    return affine.compose(np.random.randint(2, 5, 3),
                          np.random.randint(1, 10, 3), np.random.random(3))
コード例 #19
0
ファイル: scene3dcanvas.py プロジェクト: laurenpan02/fsleyes
    def __drawLegend(self):
        """Draws a legend in the bottom left corner of the screen, showing
        anatomical orientation.
        """

        copts = self.opts
        b = self.__displayCtx.bounds
        w, h = self.GetSize()
        xlen, ylen = glroutines.adjust(b.xlen, b.ylen, w, h)

        # A line for each axis
        vertices = np.zeros((6, 3), dtype=np.float32)
        vertices[0, :] = [-1, 0, 0]
        vertices[1, :] = [1, 0, 0]
        vertices[2, :] = [0, -1, 0]
        vertices[3, :] = [0, 1, 0]
        vertices[4, :] = [0, 0, -1]
        vertices[5, :] = [0, 0, 1]

        # Each axis line is scaled to
        # 60 pixels, and the legend is
        # offset from the bottom-left
        # corner by twice this amount.
        scale = [xlen * 30.0 / w] * 3
        offset = [
            -0.5 * xlen + 2.0 * scale[0], -0.5 * ylen + 2.0 * scale[1], 0
        ]

        # Apply the current camera
        # angle and rotation settings
        # to the legend vertices. Offset
        # anatomical labels off each
        # axis line by a small amount.
        rotation = affine.decompose(self.__viewMat)[2]
        xform = affine.compose(scale, offset, rotation)
        labelPoses = affine.transform(vertices * 1.2, xform)
        vertices = affine.transform(vertices, xform)

        # Draw the legend lines
        gl.glDisable(gl.GL_DEPTH_TEST)
        gl.glColor3f(*copts.cursorColour[:3])
        gl.glLineWidth(2)
        gl.glBegin(gl.GL_LINES)
        gl.glVertex3f(*vertices[0])
        gl.glVertex3f(*vertices[1])
        gl.glVertex3f(*vertices[2])
        gl.glVertex3f(*vertices[3])
        gl.glVertex3f(*vertices[4])
        gl.glVertex3f(*vertices[5])
        gl.glEnd()

        canvas = np.array([w, h])
        view = np.array([xlen, ylen])

        # Draw each label
        for i, label in enumerate(self.__legendLabels):

            # Calculate pixel x/y
            # location for this label
            xx, xy = canvas * (labelPoses[i, :2] + 0.5 * view) / view

            label.xpix = xx
            label.ypix = xy

            label.draw(w, h)
コード例 #20
0
    def __drawLegend(self):
        """Draws a legend in the bottom left corner of the screen, showing
        anatomical orientation.
        """

        copts      = self.opts
        b          = self.__displayCtx.bounds
        w, h       = self.GetSize()
        xlen, ylen = glroutines.adjust(b.xlen, b.ylen, w, h)

        # A line for each axis
        vertices       = np.zeros((6, 3), dtype=np.float32)
        vertices[0, :] = [-1,  0,  0]
        vertices[1, :] = [ 1,  0,  0]
        vertices[2, :] = [ 0, -1,  0]
        vertices[3, :] = [ 0,  1,  0]
        vertices[4, :] = [ 0,  0, -1]
        vertices[5, :] = [ 0,  0,  1]

        # Each axis line is scaled to
        # 60 pixels, and the legend is
        # offset from the bottom-left
        # corner by twice this amount.
        scale      = [xlen * 30.0 / w] * 3
        offset     = [-0.5 * xlen + 2.0 * scale[0],
                      -0.5 * ylen + 2.0 * scale[1],
                       0]

        # Apply the current camera
        # angle and rotation settings
        # to the legend vertices. Offset
        # anatomical labels off each
        # axis line by a small amount.
        rotation   = affine.decompose(self.__viewMat)[2]
        xform      = affine.compose(scale, offset, rotation)
        labelPoses = affine.transform(vertices * 1.2, xform)
        vertices   = affine.transform(vertices,       xform)

        # Draw the legend lines
        gl.glDisable(gl.GL_DEPTH_TEST)
        gl.glColor3f(*copts.cursorColour[:3])
        gl.glLineWidth(2)
        gl.glBegin(gl.GL_LINES)
        gl.glVertex3f(*vertices[0])
        gl.glVertex3f(*vertices[1])
        gl.glVertex3f(*vertices[2])
        gl.glVertex3f(*vertices[3])
        gl.glVertex3f(*vertices[4])
        gl.glVertex3f(*vertices[5])
        gl.glEnd()


        # Figure out the anatomical
        # labels for each axis.
        overlay = self.__displayCtx.getSelectedOverlay()
        dopts   = self.__displayCtx.getOpts(overlay)
        labels  = dopts.getLabels()[0]

        # getLabels returns (xlo, ylo, zlo, xhi, yhi, zhi) -
        # - rearrange them to (xlo, xhi, ylo, yhi, zlo, zhi)
        labels = [labels[0],
                  labels[3],
                  labels[1],
                  labels[4],
                  labels[2],
                  labels[5]]

        canvas = np.array([w, h])
        view   = np.array([xlen, ylen])

        # Draw each label
        for i in range(6):

            # Calculate pixel x/y
            # location for this label
            xx, xy = canvas * (labelPoses[i, :2] + 0.5 * view) / view

            # Calculate the size of the label
            # in pixels, so we can centre the
            # label
            tw, th = glroutines.text2D(labels[i], (xx, xy), 10, (w, h),
                                       calcSize=True)

            # Draw the text
            xx -= 0.5 * tw
            xy -= 0.5 * th
            gl.glColor3f(*copts.legendColour[:3])
            glroutines.text2D(labels[i], (xx, xy), 10, (w, h))