Example #1
0
    def test_whole_pixel_shifts(self):
        self.check_skip()
        L = 21
        dims = (L, L + 2)  # avoid square images in tests
        pos = [7, 13]
        expected = np.array([pos])

        image = np.ones(dims, dtype='uint8')
        draw_feature(image, pos, 15)

        guess = np.array([[6, 13]])
        actual = tp.feature.refine(image, image, 6, guess, characterize=False,
                                   engine=self.engine)[:, :2][:, ::-1]
        assert_allclose(actual, expected, atol=0.1)

        guess = np.array([[7, 12]])
        actual = tp.feature.refine(image, image, 6, guess, characterize=False,
                                   engine=self.engine)[:, :2][:, ::-1]
        assert_allclose(actual, expected, atol=0.1)

        guess = np.array([[7, 14]])
        actual = tp.feature.refine(image, image, 6, guess, characterize=False,
                                   engine=self.engine)[:, :2][:, ::-1]
        assert_allclose(actual, expected, atol=0.1)

        guess = np.array([[6, 12]])
        actual = tp.feature.refine(image, image, 6, guess, characterize=False,
                                   engine=self.engine)[:, :2][:, ::-1]
        assert_allclose(actual, expected, atol=0.1)
Example #2
0
    def test_separation_fast(self):
        separation = 20
        for angle in np.arange(0, 360, 15):
            im = np.zeros((128, 128), dtype=np.uint8)
            pos = [[64, 64], [64 + separation * np.sin(angle/180*np.pi),
                              64 + separation * np.cos(angle/180*np.pi)]]

            # setup features: features with equal signal will always be
            # detected by a grey dilation, so make them unequal
            draw_feature(im, pos[0], 3, 240)
            draw_feature(im, pos[1], 3, 250)

            # find both of them
            f = grey_dilation(im, separation - 1, precise=False)
            assert_coordinates_close(f, pos, atol=1)

            # find only the brightest
            if angle in [45, 135, 225, 315]:
                # for unprecise, a too small square kernel is used, which is
                # perfect for 45-degree angles
                f = grey_dilation(im, separation + 1, precise=False)
                assert_coordinates_close(f, pos[1:], atol=1)
            else:
                # but too small by a factor of sqrt(ndim) for 90-degree angles
                f = grey_dilation(im, separation*np.sqrt(2) + 1, precise=False)
                assert_coordinates_close(f, pos[1:], atol=1)
Example #3
0
    def test_separation_fast(self):
        separation = 20
        for angle in np.arange(0, 360, 15):
            im = np.zeros((128, 128), dtype=np.uint8)
            pos = [[64, 64],
                   [
                       64 + separation * np.sin(angle / 180 * np.pi),
                       64 + separation * np.cos(angle / 180 * np.pi)
                   ]]

            # setup features: features with equal signal will always be
            # detected by a grey dilation, so make them unequal
            draw_feature(im, pos[0], 3, 240)
            draw_feature(im, pos[1], 3, 250)

            # find both of them
            f = grey_dilation(im, separation - 1, precise=False)
            assert_coordinates_close(f, pos, atol=1)

            # find only the brightest
            if angle in [45, 135, 225, 315]:
                # for unprecise, a too small square kernel is used, which is
                # perfect for 45-degree angles
                f = grey_dilation(im, separation + 1, precise=False)
                assert_coordinates_close(f, pos[1:], atol=1)
            else:
                # but too small by a factor of sqrt(ndim) for 90-degree angles
                f = grey_dilation(im,
                                  separation * np.sqrt(2) + 1,
                                  precise=False)
                assert_coordinates_close(f, pos[1:], atol=1)
Example #4
0
    def test_reject_peaks_near_edge(self):
        """Check whether local maxima near the edge of the image
        are properly rejected, so as not to cause crashes later."""
        N = 30
        diameter = 9
        y = np.arange(20, 10*N + 1, 20)
        x = np.linspace(diameter / 2. - 2, diameter * 1.5, len(y))
        cols = ['y', 'x']
        expected = DataFrame(np.vstack([y, x]).T, columns=cols)

        dims = (y.max() - y.min() + 5*diameter, int(4 * diameter) - 2)
        image = np.ones(dims, dtype='uint8')
        for ypos, xpos in expected[['y', 'x']].values:
            draw_feature(image, [ypos, xpos], 27, max_value=100)
        def locate(image, **kwargs):
            return tp.locate(image, diameter, 1, preprocess=False,
                             engine=self.engine, **kwargs)[cols]
        # All we care about is that this doesn't crash
        actual = locate(image)
        assert len(actual)
        # Check the other sides
        actual = locate(np.fliplr(image))
        assert len(actual)
        actual = locate(image.transpose())
        assert len(actual)
        actual = locate(np.flipud(image.transpose()))
        assert len(actual)
Example #5
0
    def test_one_centered_gaussian_3D_anisotropic(self):
        self.check_skip()
        L = 21
        dims = (L, L + 2, L + 4)  # avoid square images in tests
        pos = [7, 13, 9]
        cols = ['z', 'y', 'x']
        expected = DataFrame(np.asarray(pos).reshape(1, -1), columns=cols)

        image = np.ones(dims, dtype='uint8')
        draw_feature(image, pos, (21, 27, 27))
        actual = tp.locate(image, (7, 9, 9), 1, preprocess=False,
                           engine=self.engine)[cols]
        assert_allclose(actual, expected, atol=0.1)
Example #6
0
    def test_float_image(self):
        separation = 20
        angle = 45
        im = np.zeros((128, 128), dtype=np.float64)
        pos = [[64, 64], [64 + separation * np.sin(angle/180*np.pi),
                          64 + separation * np.cos(angle/180*np.pi)]]

        # setup features: features with equal signal will always be
        # detected by a grey dilation, so make them unequal
        draw_feature(im, pos[0], 3, 240)
        draw_feature(im, pos[1], 3, 250)

        # find both of them
        f = grey_dilation(im, separation - 1, precise=False)
        assert_coordinates_close(f, pos, atol=1)
Example #7
0
    def test_size_anisotropic(self):
        # The separate columns 'size_x' and 'size_y' reflect the radii of
        # gyration in the two separate directions.

        self.check_skip()
        L = 101
        SIZE = 5
        dims = (L, L + 2)  # avoid square images in tests
        pos = [50, 55]
        for ar in [1.1, 1.5, 2]:
            image = np.zeros(dims, dtype='uint8')
            draw_feature(image, pos, [int(SIZE*8*ar), SIZE*8], rg=0.25)
            f = tp.locate(image, [int(SIZE*4*ar) * 2 - 1, SIZE*8 - 1], 1,
                          preprocess=False, engine=self.engine)
            assert_allclose(f['size_x'], SIZE, rtol=0.1)
            assert_allclose(f['size_y'], SIZE*ar, rtol=0.1)
Example #8
0
    def test_float_image(self):
        separation = 20
        angle = 45
        im = np.zeros((128, 128), dtype=np.float64)
        pos = [[64, 64],
               [
                   64 + separation * np.sin(angle / 180 * np.pi),
                   64 + separation * np.cos(angle / 180 * np.pi)
               ]]

        # setup features: features with equal signal will always be
        # detected by a grey dilation, so make them unequal
        draw_feature(im, pos[0], 3, 240)
        draw_feature(im, pos[1], 3, 250)

        # find both of them
        f = grey_dilation(im, separation - 1, precise=False)
        assert_coordinates_close(f, pos, atol=1)
Example #9
0
    def test_separation_anisotropic(self):
        separation = (10, 20)
        for angle in np.arange(0, 360, 15):
            im = np.zeros((128, 128), dtype=np.uint8)
            pos = [[64, 64], [64 + separation[0] * np.sin(angle/180*np.pi),
                              64 + separation[1] * np.cos(angle/180*np.pi)]]

            # setup features: features with equal signal will always be
            # detected by a grey dilation, so make them unequal
            draw_feature(im, pos[0], 3, 240)
            draw_feature(im, pos[1], 3, 250)

            # find both of them
            f = grey_dilation(im, (9, 19))
            assert_coordinates_close(f, pos, atol=1)

            # find only the brightest
            f = grey_dilation(im, (11, 21))
            assert_coordinates_close(f, pos[1:], atol=1)
Example #10
0
    def test_separation(self):
        separation = 20
        for angle in np.arange(0, 360, 15):
            im = np.zeros((128, 128), dtype=np.uint8)
            pos = [[64, 64], [64 + separation * np.sin(angle/180*np.pi),
                              64 + separation * np.cos(angle/180*np.pi)]]

            # setup features: features with equal signal will always be
            # detected by grey_dilation_legacy, so make them unequal
            draw_feature(im, pos[0], 3, 240)
            draw_feature(im, pos[1], 3, 250)

            # find both of them
            f = grey_dilation_legacy(im, separation - 1)
            assert_coordinates_close(f, pos, atol=1)

            # find only the brightest
            f = grey_dilation_legacy(im, separation + 1)
            assert_coordinates_close(f, pos[1:], atol=1)
Example #11
0
    def test_minmass_maxsize(self):
        # Test the mass- and sizebased filtering here on 4 different features.
        self.check_skip()
        L = 64
        dims = (L, L + 2)
        cols = ['y', 'x']
        PRECISION = 1  # we are not testing for subpx precision here

        image = np.zeros(dims, dtype=np.uint8)
        pos1 = np.array([15, 20])
        pos2 = np.array([40, 40])
        pos3 = np.array([25, 50])
        pos4 = np.array([35, 15])

        draw_feature(image, pos1, size=2.5)
        draw_feature(image, pos2, size=5)
        draw_feature(image, pos3, size=0.8)
        draw_feature(image, pos4, size=3.2)

        # filter on mass
        actual = tp.locate(image,
                           15,
                           engine=self.engine,
                           preprocess=False,
                           minmass=6500,
                           separation=10)[cols]
        actual = pandas_sort(actual, cols)
        expected = pandas_sort(DataFrame([pos2, pos4], columns=cols), cols)
        assert_allclose(actual, expected, atol=PRECISION)

        # filter on size
        actual = tp.locate(image,
                           15,
                           engine=self.engine,
                           preprocess=False,
                           maxsize=3.0,
                           separation=10)[cols]
        actual = pandas_sort(actual, cols)
        expected = pandas_sort(DataFrame([pos1, pos3], columns=cols), cols)
        assert_allclose(actual, expected, atol=PRECISION)

        # filter on both mass and size
        actual = tp.locate(image,
                           15,
                           engine=self.engine,
                           preprocess=False,
                           minmass=600,
                           maxsize=4.0,
                           separation=10)[cols]
        actual = pandas_sort(actual, cols)
        expected = pandas_sort(DataFrame([pos1, pos4], columns=cols), cols)
        assert_allclose(actual, expected, atol=PRECISION)
Example #12
0
    def get_image(self,
                  noise=0,
                  signal_dev=0.,
                  size_dev=0.,
                  separation=None,
                  N=None):
        if N is None:
            N = self.repeats
        if separation is None:
            separation = self.separation
        margin = self.separation
        Nsqrt = int(N**(1 / self.ndim) + 0.9999)
        pos = np.meshgrid(*[np.arange(0, s * Nsqrt, s) for s in separation],
                          indexing='ij')
        pos = np.array([p.ravel() for p in pos], dtype=np.float).T[:N] + margin
        pos += (np.random.random(pos.shape) - 0.5
                )  #randomize subpixel location
        shape = tuple(np.max(pos, axis=0).astype(np.int) + margin)
        if signal_dev > 0:
            signal = self.signal * np.random.uniform(1 - signal_dev,
                                                     1 + signal_dev, N)
        else:
            signal = np.repeat(self.signal, N)
        if size_dev > 0:
            size = np.array([self.size]) * np.random.uniform(
                1 - size_dev, 1 + size_dev, (N, 1))
        else:
            size = np.repeat([self.size], N, axis=0)

        image = np.zeros(shape, dtype=self.dtype)
        for _pos, _signal, _size in zip(pos, signal, size):
            draw_feature(image, _pos, _size, _signal, self.feat_func,
                         **self.feat_kwargs)
        if self.isotropic:
            size = size[:, 0]

        if noise > 0:
            image = image + np.random.poisson(noise, shape)
            if image.max() <= 255:
                image = image.astype(np.uint8)

        return image, (pos, signal, size)
Example #13
0
    def test_ep_anisotropic(self):
        # The separate columns 'ep_x' and 'ep_y' reflect the static errors
        # in the two separate directions. The error in the direction with the
        # smallest mask size should be lowest; their ratio is equal to the
        # mask aspect ratio.

        self.check_skip()
        L = 101
        SIZE = 5
        dims = (L, L + 2)  # avoid square images in tests
        pos = [50, 55]
        noise = 0.2
        for ar in [1.1, 1.5, 2]:  # sizeY / sizeX
            image = np.random.randint(0, int(noise*255), dims).astype('uint8')
            draw_feature(image, pos, [int(SIZE*8*ar), SIZE*8],
                         max_value=int((1-noise)*255))
            f = tp.locate(image, [int(SIZE*4*ar) * 2 - 1, SIZE*8 - 1],
                          threshold=int(noise*64), topn=1,
                          engine=self.engine).loc[0]
            assert_allclose(f['ep_y'] / f['ep_x'], ar, rtol=0.1)
Example #14
0
    def test_size(self):
        # To draw Gaussians with radii 2, 3, 5, and 7 px, we supply the draw
        # function with rg=0.25. This means that the radius of gyration will be
        # one fourth of the max radius in the draw area, which is diameter/2.

        # The 'size' comes out to be within 3%, which is because of the
        # pixelation of the Gaussian.

        # The IDL code has mistake in this area, documented here:
        # http://www.physics.emory.edu/~weeks/idl/radius.html

        self.check_skip()
        L = 101
        dims = (L, L + 2)  # avoid square images in tests
        for pos in [[50, 55], [50.2, 55], [50.5, 55]]:
            for SIZE in [2, 3, 5, 7]:
                image = np.zeros(dims, dtype='uint8')
                draw_feature(image, pos, SIZE*8, rg=0.25)
                actual = tp.locate(image, SIZE*8 - 1, 1, preprocess=False,
                                   engine=self.engine)['size']
                assert_allclose(actual, SIZE, rtol=0.1)
Example #15
0
    def test_eccentricity(self):
        # Eccentricity (elongation) is measured with good accuracy and
        # ~0.02 precision, as long as the mask is large enough to cover
        # the whole object.
        self.check_skip()
        L = 501 
        dims = (L + 2, L)  # avoid square images in tests
        pos = [50, 55]
        cols = ['y', 'x']

        ECC = 0
        image = np.ones(dims, dtype='uint8')
        draw_feature(image, pos, 27, ecc=ECC)
        actual = tp.locate(image, 21, 1, preprocess=False,
                           engine=self.engine)['ecc']
        expected = ECC
        assert_allclose(actual, expected, atol=0.02)

        ECC = 0.2
        image = np.ones(dims, dtype='uint8')
        draw_feature(image, pos, 27, ecc=ECC)
        actual = tp.locate(image, 21, 1, preprocess=False,
                           engine=self.engine)['ecc']
        expected = ECC
        assert_allclose(actual, expected, atol=0.1)

        ECC = 0.5
        image = np.ones(dims, dtype='uint8')
        draw_feature(image, pos, 27, ecc=ECC)
        actual = tp.locate(image, 21, 1, preprocess=False,
                           engine=self.engine)['ecc']
        expected = ECC
        assert_allclose(actual, expected, atol=0.1)
Example #16
0
    def test_separation_anisotropic(self):
        separation = (10, 20)
        for angle in np.arange(0, 360, 15):
            im = np.zeros((128, 128), dtype=np.uint8)
            pos = [[64, 64],
                   [
                       64 + separation[0] * np.sin(angle / 180 * np.pi),
                       64 + separation[1] * np.cos(angle / 180 * np.pi)
                   ]]

            # setup features: features with equal signal will always be
            # detected by a grey dilation, so make them unequal
            draw_feature(im, pos[0], 3, 240)
            draw_feature(im, pos[1], 3, 250)

            # find both of them
            f = grey_dilation(im, (9, 19))
            assert_coordinates_close(f, pos, atol=1)

            # find only the brightest
            f = grey_dilation(im, (11, 21))
            assert_coordinates_close(f, pos[1:], atol=1)
Example #17
0
    def test_separation(self):
        separation = 20
        for angle in np.arange(0, 360, 15):
            im = np.zeros((128, 128), dtype=np.uint8)
            pos = [[64, 64],
                   [
                       64 + separation * np.sin(angle / 180 * np.pi),
                       64 + separation * np.cos(angle / 180 * np.pi)
                   ]]

            # setup features: features with equal signal will always be
            # detected by grey_dilation_legacy, so make them unequal
            draw_feature(im, pos[0], 3, 240)
            draw_feature(im, pos[1], 3, 250)

            # find both of them
            f = grey_dilation_legacy(im, separation - 1)
            assert_coordinates_close(f, pos, atol=1)

            # find only the brightest
            f = grey_dilation_legacy(im, separation + 1)
            assert_coordinates_close(f, pos[1:], atol=1)
Example #18
0
    def test_uncertainty_failure(self):
        """When the uncertainty ("ep") calculation results in a nonsense negative
        value, it should return NaN instead.
        """
        self.check_skip()
        L = 21
        dims = (L, L + 2)  # avoid square images in tests
        pos = np.array([7, 13])
        cols = ['x', 'y']
        expected = DataFrame(pos[::-1].reshape(1, -1), columns=cols)

        image = 100*np.ones(dims, dtype='uint8')
        # For a feature to have a negative uncertainty, its integrated mass
        # must be less than if it were not there at all (replaced
        # with the average background intensity). So our feature will be a
        # small bright spot surrounded by a dark annulus.
        draw_feature(image, pos, 6, max_value=-100)
        draw_feature(image, pos, 4, max_value=200)
        
        actual = tp.locate(image, 9, 1, preprocess=False, engine=self.engine)
        assert np.allclose(actual[['x', 'y']], expected[['x', 'y']])
        assert np.isnan(np.asscalar(actual.ep))
Example #19
0
    def get_image(self, noise=0, signal_dev=0., size_dev=0., separation=None,
                  N=None):
        if N is None:
            N = self.repeats
        if separation is None:
            separation = self.separation
        margin = self.separation
        Nsqrt = int(N**(1/self.ndim) + 0.9999)
        pos = np.meshgrid(*[np.arange(0, s * Nsqrt, s) for s in separation],
                          indexing='ij')
        pos = np.array([p.ravel() for p in pos], dtype=np.float).T[:N] + margin
        pos += (np.random.random(pos.shape) - 0.5)  #randomize subpixel location
        shape = tuple(np.max(pos, axis=0).astype(np.int) + margin)
        if signal_dev > 0:
            signal = self.signal * np.random.uniform(1-signal_dev, 1+signal_dev,
                                                     N)
        else:
            signal = np.repeat(self.signal, N)
        if size_dev > 0:
            size = np.array([self.size]) * np.random.uniform(1-size_dev,
                                                             1+size_dev,
                                                             (N, 1))
        else:
            size = np.repeat([self.size], N, axis=0)

        image = np.zeros(shape, dtype=self.dtype)
        for _pos, _signal, _size in zip(pos, signal, size):
            draw_feature(image, _pos, _size, _signal,
                         self.feat_func, **self.feat_kwargs)
        if self.isotropic:
            size = size[:, 0]

        if noise > 0:
            image = image + np.random.poisson(noise, shape)
            if image.max() <= 255:
                image = image.astype(np.uint8)

        return image, (pos, signal, size)
Example #20
0
    def test_minmass_maxsize(self):
        # Test the mass- and sizebased filtering here on 4 different features.
        self.check_skip()
        L = 64
        dims = (L, L + 2)
        cols = ['y', 'x']
        PRECISION = 1  # we are not testing for subpx precision here

        image = np.zeros(dims, dtype=np.uint8)
        pos1 = np.array([15, 20])
        pos2 = np.array([40, 40])
        pos3 = np.array([25, 45])
        pos4 = np.array([35, 15])

        draw_feature(image, pos1, 15)
        draw_feature(image, pos2, 30)
        draw_feature(image, pos3, 5)
        draw_feature(image, pos4, 20)

        # filter on mass
        actual = tp.locate(image, 15, engine=self.engine, preprocess=False,
                           minmass=6500)[cols]
        actual = actual.sort(cols)
        expected = DataFrame([pos2, pos4], columns=cols).sort(cols)
        assert_allclose(actual, expected, atol=PRECISION)

        # filter on size
        actual = tp.locate(image, 15, engine=self.engine, preprocess=False,
                           maxsize=3.0)[cols]
        actual = actual.sort(cols)
        expected = DataFrame([pos1, pos3], columns=cols).sort(cols)
        assert_allclose(actual, expected, atol=PRECISION)

        # filter on both mass and size
        actual = tp.locate(image, 15, engine=self.engine, preprocess=False,
                           minmass=600, maxsize=4.0)[cols]
        actual = actual.sort(cols)
        expected = DataFrame([pos1, pos4], columns=cols).sort(cols)
        assert_allclose(actual, expected, atol=PRECISION)