Esempio n. 1
0
def test_larger_contour():
    locus = pyefd.calculate_dc_coefficients(contour_1)
    coeffs = pyefd.elliptic_fourier_descriptors(contour_1, order=50)
    number_of_points = contour_1.shape[0]

    reconstruction = pyefd.reconstruct_contour(coeffs, locus, number_of_points)
    hausdorff_distance, _, _ = directed_hausdorff(contour_1, reconstruction)
    assert hausdorff_distance < 0.4
Esempio n. 2
0
def create_contour(mask):
    """Turn as mask into a contour polygon. The polygon is smoothed
    via Fourier descriptors
    
    Parameters
    ----------
    mask : 2D numpy array
        mask of a region
    
    Returns
    -------
    recon : Nx2 numpy array 
        coordinates of contour
    """

    # extract contour by recovering contour of filled mask
    reg = skimage.measure.regionprops_table(
        skimage.morphology.label(mask),
        properties=(
            "label",
            "area",
            "filled_area",
            "eccentricity",
            "extent",
            "filled_image",
            "coords",
            "bbox",
        ),
    )
    regp = pd.DataFrame(reg).sort_values(by="filled_area", ascending=False)

    new_mask2 = np.zeros(mask.shape)
    new_mask2[regp.iloc[0]["bbox-0"]:regp.iloc[0]["bbox-2"],
              regp.iloc[0]["bbox-1"]:regp.
              iloc[0]["bbox-3"], ] = regp.iloc[0].filled_image
    area = regp.iloc[0].filled_area

    contour = skimage.measure.find_contours(new_mask2, 0.8)

    sel_contour = contour[np.argmax([len(x) for x in contour])]

    # calculate a smoothed verions using a reconstruction via Fourier descriptors
    coeffs = elliptic_fourier_descriptors(sel_contour,
                                          order=100,
                                          normalize=False)
    coef0 = calculate_dc_coefficients(sel_contour)
    recon = reconstruct_contour(coeffs, locus=coef0, num_points=1500)

    return recon, area
Esempio n. 3
0
def test_fit_1():
    n = 300
    locus = pyefd.calculate_dc_coefficients(contour_1)
    coeffs = pyefd.elliptic_fourier_descriptors(contour_1, order=20)

    t = np.linspace(0, 1.0, n)
    xt = np.ones((n, )) * locus[0]
    yt = np.ones((n, )) * locus[1]

    for n in pyefd._range(coeffs.shape[0]):
        xt += (coeffs[n, 0] * np.cos(2 * (n + 1) * np.pi * t)) + \
              (coeffs[n, 1] * np.sin(2 * (n + 1) * np.pi * t))
        yt += (coeffs[n, 2] * np.cos(2 * (n + 1) * np.pi * t)) + \
              (coeffs[n, 3] * np.sin(2 * (n + 1) * np.pi * t))

    assert True
Esempio n. 4
0
def test_reconstruct_simple_contour():
    simple_polygon = np.array([[1., 1.], [0., 1.], [0., 0.], [1., 0.],
                               [1., 1.]])
    number_of_points = simple_polygon.shape[0]
    locus = pyefd.calculate_dc_coefficients(simple_polygon)
    coeffs = pyefd.elliptic_fourier_descriptors(simple_polygon, order=30)

    reconstruction = pyefd.reconstruct_contour(coeffs, locus, number_of_points)
    # with only 2 decimal accuracy it is a bit of a course test, but it will do
    # directly comparing the two polygons will only work here, because efd coefficients will be cycle-consistent
    np.testing.assert_array_almost_equal(simple_polygon,
                                         reconstruction,
                                         decimal=2)
    hausdorff_distance, _, _ = directed_hausdorff(reconstruction,
                                                  simple_polygon)
    assert hausdorff_distance < 0.01
Esempio n. 5
0
File: tests.py Progetto: hbldh/pyefd
def test_fit_1():
    n = 300
    locus = pyefd.calculate_dc_coefficients(contour_1)
    coeffs = pyefd.elliptic_fourier_descriptors(contour_1, order=20)

    t = np.linspace(0, 1.0, n)
    xt = np.ones((n,)) * locus[0]
    yt = np.ones((n,)) * locus[1]

    for n in pyefd._range(coeffs.shape[0]):
        xt += (coeffs[n, 0] * np.cos(2 * (n + 1) * np.pi * t)) + \
              (coeffs[n, 1] * np.sin(2 * (n + 1) * np.pi * t))
        yt += (coeffs[n, 2] * np.cos(2 * (n + 1) * np.pi * t)) + \
              (coeffs[n, 3] * np.sin(2 * (n + 1) * np.pi * t))

    assert True
    def test_centroid(self):
        geom1 = 'POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'
        geom1 = gv.vectorize_wkt(geom1)

        with self.subTest('It does not accept a numpy ndarray'):
            with self.assertRaises(AssertionError):
                centroid(geom1)

        with self.subTest('It rejects 3D geometries'):
            with self.assertRaises(AssertionError):
                centroid(torch.rand((10, 3)))

        with self.subTest('Our stand-in centroid function does the same as pyefd'):
            geom2 = 'POLYGON((1 1, 0 1, 0 0, 1 0, 1 1))'
            geom2 = gv.vectorize_wkt(geom2)

            coords_batch = geom2[:, :2]
            coords_batch = coords_batch.reshape(1, geom2.shape[0], 2)
            polygon2_tensor = torch.from_numpy(coords_batch)

            pyefd_centroid = pyefd.calculate_dc_coefficients(coords_batch[0])
            pytorch_centroid = centroid(polygon2_tensor)

            np.testing.assert_array_almost_equal(pyefd_centroid, pytorch_centroid[0])

        with self.subTest('It correctly calculates centroids for batches'):
            geom2 = 'POLYGON((1 1, 0 1, 0 0, 1 0, 1 1))'
            geom2 = gv.vectorize_wkt(geom2)

            coords_batch = geom2[:, :2]
            coords_batch = coords_batch.reshape(1, geom2.shape[0], 2)
            polygon2_tensor = torch.from_numpy(coords_batch)
            batch_size = 6
            batch = polygon2_tensor.repeat(batch_size, 1, 1)
            multiply_range = torch.range(1., 6., dtype=batch.dtype).reshape((batch_size, 1, 1))
            batch = batch * multiply_range

            reference_centroids = np.arange(1, batch_size + 1)
            reference_centroids = reference_centroids.reshape(batch_size, 1) * 0.5
            reference_centroids = reference_centroids.repeat(2, axis=1)

            batch_centroids = centroid(batch)

            np.testing.assert_array_almost_equal(reference_centroids, batch_centroids.numpy())
Esempio n. 7
0
def test_locus():
    locus = pyefd.calculate_dc_coefficients(contour_1)
    np.testing.assert_array_almost_equal(locus,
                                         np.mean(contour_1, axis=0),
                                         decimal=0)
Esempio n. 8
0
"""Elliptic Fourier Descriptors
parametrizing a closed countour (in red)"""
import vedo, pyefd

shapes = vedo.load(vedo.dataurl+'timecourse1d.npy')

sh = shapes[55]
sr = vedo.Line(sh).mirror('x').reverse()
sm = vedo.merge(sh, sr).c('red5').lw(3)
pts = sm.points()[:,(0,1)]

rlines = []
for order in range(5,30, 5):
    coeffs = pyefd.elliptic_fourier_descriptors(pts, order=order, normalize=False)
    a0, c0 = pyefd.calculate_dc_coefficients(pts)
    rpts = pyefd.reconstruct_contour(coeffs, locus=(a0,c0), num_points=400)
    color = vedo.colorMap(order, "Blues", 5,30)
    rline = vedo.Line(rpts).lw(3).c(color)
    rlines.append(rline)

sm.z(0.1) # move it on top so it's visible
vedo.show(sm, *rlines, __doc__, axes=1, bg='k', size=(1190, 630), zoom=1.8)
    # create fourier descriptors and save statistics
    normalized_coefficients = np.zeros((dataset.n_images, n_harmonics, 4))
    errors = np.zeros(dataset.n_images)
    for idx in range(dataset.n_images):
        im = dataset.get_image(idx).squeeze().numpy()
        contour = get_contour(im, threshold=threshold)
        if contour is not None:
            # elliptical Fourier descriptor's coefficients.
            coeffs = pyefd.elliptic_fourier_descriptors(contour,
                                                        order=n_harmonics)
            # normalize coeffs
            normalized_coeffs, L = pyefd.normalize_efd(deepcopy(coeffs))
            # recon_contour
            if len(contour) > 0:
                locus = pyefd.calculate_dc_coefficients(contour)
            else:
                locus = (0, 0)
            recon_contour = pyefd.reconstruct_contour(coeffs,
                                                      locus=locus,
                                                      num_points=300)
            # error measure
            error = calc_contours_distance(contour,
                                           recon_contour) / (2 * L) * 100
            normalized_coefficients[idx] = normalized_coeffs
            errors[idx] = error

    print('{} harmonics:  error {}(mean); {}(std); {} (min); {}(max); {}(90p)'.
          format(n_harmonics, errors.mean(), errors.std(), errors.min(),
                 errors.max(), np.percentile(errors, 90)))
Esempio n. 10
0
# diamond
# rCos = np.array([0.5, 0.427, 0.0,  0.0732])
# zSin = np.array([0.0, 0.427, 0.0, -0.0732])

# D
# rCos = np.array([3.0, 0.991,  0.136])
# zSin = np.array([0.0, 1.409, -0.118])

# belt
# rCos = np.array([3.0, 0.453, 0.0, 0.0  ])
# zSin = np.array([0.0, 0.6  , 0.0, 0.196])

# ellipse
# rCos = np.array([3.0, 1.0])
# zSin = np.array([0.0, 3.0])

# evaluate curve geometry given as Fourier coefficients above
n = 300
contour = np.zeros([n,2])
theta = np.linspace(0.0, 2.0*np.pi, n)
mMax = len(rCos)
for m in range(mMax):
    contour[:,0] += rCos[m] * np.cos(m*theta)
    contour[:,1] += zSin[m] * np.sin(m*theta)

# apply pyefd to get elliptic Fourier descriptors
coeffs = pyefd.elliptic_fourier_descriptors(contour)
a0, c0 = pyefd.calculate_dc_coefficients(contour)
pyefd.plot_efd(coeffs, locus=(a0,c0), contour=contour)
Esempio n. 11
0
File: tests.py Progetto: hbldh/pyefd
def test_locus():
    locus = pyefd.calculate_dc_coefficients(contour_1)
    np.testing.assert_array_almost_equal(locus, np.mean(contour_1, axis=0), decimal=0)