def step_7_ellipse_fit(self): """ Extract the cylinder and ellipse diameter of each stem Args: None Returns: None """ for i in self.finalstems: # if the tree points has enough points to fit a ellipse if len(i['tree']) > 5: # find a matrix that rotates the stem to be colinear to the z axis R = utils.rotation_matrix_from_vectors(i['model'][3:6], [0, 0, 1]) # we center the stem to the origen then rotate it centeredtree = i['tree'] - i['model'][0:3] correctedcyl = (R @ centeredtree.T).T # fit an ellipse using only the xy coordinates reg = LsqEllipse().fit(correctedcyl[:, 0:2]) center, a, b, phi = reg.as_parameters() ellipse_diameter = (3 * (a + b) - np.sqrt( (3 * a + b) * (a + 3 * b))) cylinder_diameter = i['model'][6] * 2 i['cylinder_diameter'] = cylinder_diameter i['ellipse_diameter'] = ellipse_diameter i['final_diameter'] = max(ellipse_diameter, cylinder_diameter) else: i['cylinder_diameter'] = None i['ellipse_diameter'] = None i['final_diameter'] = None
def test_if_perfect_circle(): X = make_dataset(center=[0, 0], width=1, height=1, phi=0, n_points=50) elp = LsqEllipse().fit(X) _center, _width, _height, _phi = elp.as_parameters() nptest.assert_array_almost_equal(_center, [0, 0]) nptest.assert_almost_equal(_width, 1) nptest.assert_almost_equal(_height, 1)
def test_minimum_data_points(): X = make_dataset(center=[0, 0], width=1, height=.5, phi=0, n_points=5) elp = LsqEllipse() elp.fit(X) _center, _width, _height, _phi = elp.as_parameters() nptest.assert_array_almost_equal(_center, [0, 0]) nptest.assert_almost_equal(_width, 1) nptest.assert_almost_equal(_height, .5) nptest.assert_almost_equal(_phi, 0)
def test_return_fit_returns_correct_ellipse(n_points): X = make_dataset(center=[0, 0], width=1, height=.5, phi=0, n_points=n_points) elp = LsqEllipse().fit(X) x = elp.return_fit(n_points) nptest.assert_array_almost_equal(x, X)
def test_if_no_ellipse_found(): """ This data causes a divide by zero error TODO: add in check of this """ X = make_dataset(center=[0, 0], width=1, height=1, phi=0, n_points=5) elp = LsqEllipse().fit(X) _center, _width, _height, _phi = elp.as_parameters() nptest.assert_array_almost_equal(_center, [0, 0]) nptest.assert_almost_equal(_width, 1) nptest.assert_almost_equal(_height, 1)
def test_ellipse_fit(center, width, height, phi): X = make_dataset(center=center, width=width, height=height, phi=phi, n_points=10) elp = LsqEllipse() elp.fit(X) _center, _width, _height, _phi = elp.as_parameters() nptest.assert_array_almost_equal(_center, center) nptest.assert_almost_equal(_width, width) nptest.assert_almost_equal(_height, height) nptest.assert_almost_equal(_phi, phi)
def test_return_fit_returns_correct_ellipse(n_points): X = make_dataset(center=[0, 0], width=1, height=.5, phi=0, n_points=n_points) elp = LsqEllipse().fit(X) t = np.linspace(0, 1.8 * np.pi, n_points) center, major, minor, phi = elp.as_parameters() with mock.patch.object(LsqEllipse, 'as_parameters') as as_parameters: as_parameters.return_value = (center, *_normalize_result(major, minor, phi)) x = elp.return_fit(n_points, t=t) nptest.assert_array_almost_equal(x, X)
def test_minimum_data_points(): X = make_dataset(center=[0, 0], width=1, height=.5, phi=np.pi / 20, n_points=5) elp = LsqEllipse() elp.fit(X) _center, _major, _minor, _phi = elp.as_parameters() _width, _height, _phi = _normalize_result(_major, _minor, _phi) nptest.assert_array_almost_equal(_center, [0, 0]) nptest.assert_almost_equal(_width, 1) nptest.assert_almost_equal(_height, .5) nptest.assert_almost_equal(_phi, np.pi / 20)
def ellipse_fit(image): ''' Dada uma imagem binária, extrai os pixels brancos como vértices e busca uma elipse que se encaixe neles. Parâmetros: image (np.array): array contendo os pixels da imagem. Retorno: ellipse_data (ellipse.LsqEllipse): elipse detectada. ''' white_pixels = np.argwhere(image == 255) ellipse_data = LsqEllipse().fit(white_pixels) center, width, height, angle = ellipse_data.as_parameters() center = (center[1], center[0]) ellipse_data = (center, (width * 2, height * 2), angle) return ellipse_data
def get_distance_func(self, phi, index): ''' Compute the ellipse parameters and the distance of each pixel position to this ellipse (Shape prior) Args: phi: Signed distance function at the kth iteration index: List of indexes of the points that are close to the level-set zero of the phi function. This will provide a set of points from which to compute the ellipse Returns: 2D array of the size of the original image, where each pixel value represents the distance from that pixel position to the estimated ellipse. This distance is normalized so all the distances values are between 0 and 1. ''' # We need at least 6 points to have an unique solution. If we don't, then # we skip this distance function if (index[0].shape[0]) < 6: return np.zeros(phi.shape) index = np.array(index, dtype=np.float) index = np.swapaxes(index, 0, 1) # The Ellipse module requires to have as first index X and the second # index Y, which is the inverse of our code index[:, [0, 1]] = index[:, [1, 0]] reg = LsqEllipse().fit(index) a, b, c, d, e, f = reg.coefficients xv, yv = np.meshgrid(range(phi.shape[1]), range(phi.shape[0])) xv_2 = np.power(xv, 2) yv_2 = np.power(yv, 2) xv_yv = np.multiply(xv, yv) distances = a * xv_2 + b * xv_yv + c * yv_2 + d * xv + e * yv + f distances /= (np.max(np.absolute(distances)) + 1) return distances
t = np.linspace(0, 2 * np.pi, 1000) x_noise, y_noise = np.random.rand(2, len(t)) ellipse_x = center[0] + width * np.cos(t) * np.cos(phi) - height * np.sin( t) * np.sin(phi) + x_noise / 2. # noqa: E501 ellipse_y = center[1] + width * np.cos(t) * np.sin(phi) + height * np.sin( t) * np.cos(phi) + y_noise / 2. # noqa: E501 return [ellipse_x, ellipse_y] if __name__ == '__main__': X1, X2 = make_test_ellipse() X = np.array(list(zip(X1, X2))) reg = LsqEllipse().fit(X) center, width, height, phi = reg.as_parameters() print(f'center: {center[0]:.3f}, {center[1]:.3f}') print(f'width: {width:.3f}') print(f'height: {height:.3f}') print(f'phi: {phi:.3f}') fig = plt.figure(figsize=(6, 6)) ax = plt.subplot() ax.axis('equal') ax.plot(X1, X2, 'ro', zorder=1) ellipse = Ellipse(xy=center, width=2 * width, height=2 * height, angle=np.rad2deg(phi),
def test_cannot_get_coef_without_fitting(): elp = LsqEllipse() with pytest.raises(ValueError): elp.coefficients
def test_less_than_minimum_data_points_raises_err(): X = make_dataset(center=[0, 0], width=1, height=.5, phi=0, n_points=4) elp = LsqEllipse() with pytest.raises(ValueError): elp.fit(X)
def ellipse_fit(data): X = data[:, 0, 0] Y = data[:, 0, 1] Z = np.array(list(zip(X, Y))) reg = LsqEllipse().fit(Z) return reg