def fit_ellipse(myimg, X, disp_log): debug_graphics = False #disp_log=True EllipseFit = [] reg = el.LsqEllipse().fit(X) center, width, height, phi = reg.as_parameters() EllipseFit = [center, width, height, phi] #section=((baryY-center[1])/center[1]) XE = reg.return_fit(n_points=2000) if disp_log or debug_graphics: print() print(f'center: {center[0]:.3f}, {center[1]:.3f}') print(f'width: {width*2:.3f}') print(f'height: {height*2:.3f}') print(f'phi: {np.rad2deg(phi):.3f}') if debug_graphics: plt.imshow(myimg) # plot ellipse in blue ellipse = Ellipse(xy=center, width=2 * width, height=2 * height, angle=np.rad2deg(phi), edgecolor='b', fc='None', lw=1, label='Fit', zorder=2) # plot edges on image as red dots np_m = np.asarray(X) xm, ym = np_m.T plt.scatter(xm, ym, s=0.1, marker='.', edgecolors=('red')) ax = plt.gca() ax.add_patch(ellipse) plt.show() return EllipseFit, XE
#https://github.com/bdhammel/least-squares-ellipse-fitting #To install: pip install lsq-ellipse import pandas as pd import math import ellipse as el import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import Ellipse # X1, X2 = el.make_test_ellipse() df = pd.read_csv("outputData.txt", sep=" ") df.columns = ["x", "y", "z"] X = np.array(list(zip(df["x"], df["y"]))) reg = el.LsqEllipse().fit(X) center, width, height, phi = reg.as_parameters() print("Ellipse Parameter:", center, width, height, phi) plt.close('all') fig = plt.figure(figsize=(6, 6)) ax = fig.add_subplot(111) ax.axis('equal') ax.plot(df["x"], df["y"], 'ro', label='Messungen', zorder=1) ellipse = Ellipse(xy=center, width=2 * width, height=2 * height, angle=np.rad2deg(phi), edgecolor='b', fc='None',
def best_fit(self, points): r"""Find ellipse of best fit for points This function computes the ellipse of best fit for a set of points. It calls the `least-squares-ellipse-fitting`_ package, which implements a published fitting algorithm in Python. [#halir]_ The current instance of the class is used as an initial guess for the ellipse of best fit. Since an ellipse can be expressed multiple ways (e.g. rotate 90 degrees and flip the axes), this initial guess is used to choose from the multiple parameter sets. Args: points (list or numpy.ndarray): An Nx2 list of points to fit. Returns: .Ellipse: An instance of the class that best fits the points. .. _`least-squares-ellipse-fitting`: https://github.com/bdhammel/least-squares-ellipse-fitting .. [#halir] Halir, R., Flusser, J., "Numerically Stable Direct Least Squares Fitting of Ellipses," *6th International Conference in Central Europe on Computer Graphics and Visualization*, Vol. 98, 1998. (http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.1.7559&rep=rep1&type=pdf) """ # NOQA: E501 pts = np.array(points) pt_cen = pts.mean(axis=0) pts -= pt_cen.reshape(1, -1) reg = lsqel.LsqEllipse().fit(pts) center, width, height, phi = reg.as_parameters() xc, yc = center xc += pt_cen[0] yc += pt_cen[1] # Find pair closest to self s = np.sin(phi) c = np.cos(phi) rot = np.array([[c, -s], [s, c]]) x_ax_seed = np.array(self.matrix)[:, 0] x_dot, y_dot = rot.T.dot(x_ax_seed) if np.abs(x_dot) > np.abs(y_dot): if x_dot > 0: x_ax_fit = rot[:, 0] else: x_ax_fit = -rot[:, 0] a = width b = height else: if y_dot > 0: x_ax_fit = rot[:, 1] else: x_ax_fit = -rot[:, 1] a = height b = width ang_diff = np.arcsin(np.cross(x_ax_seed, x_ax_fit)) ang_rad = self.angle_rad + ang_diff return type(self)(center=(xc, yc), a=a, b=b, angle_rad=ang_rad)
def detect_fit_ellipse(myimg, y1, y2, zexcl): edgeX = [] edgeY = [] cercle_edge = [] #detect si pas de limbes droits et/ou gauche print() y1, y2 = detect_bord(myimg, axis=1, offset=5) # bords verticaux x1, x2 = detect_bord(myimg, axis=0, offset=5) # bords horizontaux toprint = 'Position X des limbes droit et gauche x1, x2 : ' + str( x1) + ' ' + str(x2) mylog.append(toprint + '\n') print(toprint) iw = myimg.shape[1] TailleX = int(x2 - x1) if TailleX + 10 < int(iw / 5) or TailleX + 10 > int(iw * .99): toprint = 'Pas de limbe solaire pour determiner la geometrie' print(toprint) mylog.append(toprint + '\n') toprint = 'Reprendre les traitements en manuel avec ISIS' print(toprint) mylog.append(toprint + '\n') #print(TailleX, iw) ratio = 0.5 EllipseFit = [0, 0, ratio, 1, 0] section = 0 zone_fit = abs(y2 - y1) ze = int(zexcl * zone_fit) for i in range(y1 + ze, y2 - ze): li = myimg[i, :-5] #li_filter=savgol_filter(li,31,3) li_filter = gaussian_filter1d(li, 11) li_gr = np.gradient(li_filter) #if i==650: #plt.plot(li) #plt.plot(li_gr) #plt.show() a = np.where((abs(li_gr) > 80)) s = a[0] if s.size != 0: c_x1 = s[0] + 10 c_x2 = s[-1] - 10 edgeX.append(c_x1) edgeY.append(i) edgeX.append(c_x2) edgeY.append(i) cercle_edge.append([c_x1, i]) cercle_edge.append([c_x2, i]) zy = np.mean(edgeY) X = np.array(list(zip(edgeX, edgeY))) reg = el.LsqEllipse().fit(X) center, width, height, phi = reg.as_parameters() EllipseFit = [center, width, height, phi] r = height / width section = ((zy - center[1]) / center[1]) print(f'center: {center[0]:.3f}, {center[1]:.3f}') print(f'width: {width*2:.3f}') print(f'height: {height*2:.3f}') #print(f'phi: {np.rad2deg(phi):.3f}') print(f'SY/SX ellipse: {r:.3f}') # print(f'Section: {section:.3f}') """ plt.imshow(myimg) #plt.plot(edgeX, edgeY, 'ro', zorder=1) ellipse = Ellipse( xy=center, width=2*width, height=2*height, angle=np.rad2deg(phi), edgecolor='b', fc='None', lw=1, label='Fit', zorder=2) # plot cercle sur image np_m=np.asarray(cercle_edge) xm,ym=np_m.T plt.scatter(xm,ym,s=0.1, marker='.', edgecolors=('red')) ax=plt.gca() ax.add_patch(ellipse) plt.show() """ return EllipseFit, section