def show_name(hs, nx, nx2_cxs=None, fnum=0, sel_cxs=[], subtitle='', annote=False, **kwargs): print('[viz] show_name nx=%r' % nx) nx2_name = hs.tables.nx2_name cx2_nx = hs.tables.cx2_nx name = nx2_name[nx] if not nx2_cxs is None: cxs = nx2_cxs[nx] else: cxs = np.where(cx2_nx == nx)[0] print('[viz] show_name %r' % hs.cidstr(cxs)) nRows, nCols = get_square_row_cols(len(cxs)) print('[viz*] r=%r, c=%r' % (nRows, nCols)) #gs2 = gridspec.GridSpec(nRows, nCols) pnum = lambda px: (nRows, nCols, px + 1) fig = df2.figure(fnum=fnum, pnum=pnum(0), **kwargs) fig.clf() # Trigger computation of all chips in parallel hs.refresh_features(cxs) for px, cx in enumerate(cxs): show_chip(hs, cx=cx, pnum=pnum(px), draw_ell=annote, kpts_alpha=.2) if cx in sel_cxs: ax = df2.gca() df2.draw_border(ax, df2.GREEN, 4) #plot_cx3(hs, cx) if isinstance(nx, np.ndarray): nx = nx[0] if isinstance(name, np.ndarray): name = name[0] figtitle = 'Name View nx=%r name=%r' % (nx, name) df2.set_figtitle(figtitle)
def plot_time(unixtime_list): import draw_func2 as df2 unixtime_list = np.array(unixtime_list) fixed_time = unixtime_list[unixtime_list > 0] df2.plot(sorted(unixtime_list)) ax = df2.gca() ax.set_ylim(fixed_time.min(), fixed_time.max())
def _distplot(dists, color, label, distkey, plot_type=plot_type): data = sorted(dists) ax = df2.gca() min_ = distkey2_min[distkey] max_ = distkey2_max[distkey] if plot_type == 'plot': df2.plot(data, color=color, label=label) #xticks = np.linspace(np.min(data), np.max(data), 3) #yticks = np.linspace(0, len(data), 5) #ax.set_xticks(xticks) #ax.set_yticks(yticks) ax.set_ylim(min_, max_) ax.set_xlim(0, len(dists)) ax.set_ylabel('distance') ax.set_xlabel('matches indexes (sorted by distance)') df2.legend(loc='lower right') if plot_type == 'pdf': df2.plot_pdf(data, color=color, label=label) ax.set_ylabel('pr') ax.set_xlabel('distance') ax.set_xlim(min_, max_) df2.legend(loc='upper right') df2.dark_background(ax) df2.small_xticks(ax) df2.small_yticks(ax)
def show_keypoints(rchip, kpts, draw_ell=True, draw_pts=False, sel_fx=None, fnum=0, pnum=None, color=None, rect=False, **kwargs): df2.imshow(rchip, fnum=fnum, pnum=pnum, **kwargs) _annotate_kpts(kpts, sel_fx, draw_ell, draw_pts, color=color, rect=rect) ax = df2.gca() ax._hs_viewtype = 'keypoints' ax._hs_kpts = kpts
def _on_chip_click(event): print_('[inter] clicked chip') ax, x, y = event.inaxes, event.xdata, event.ydata if ax is None or x is None: # The click is not in any axis print('... out of axis') annote_ptr[0] = (annote_ptr[0] + 1) % 3 mode = annote_ptr[0] draw_ell = mode == 1 draw_pts = mode == 2 print('... default kpts view mode=%r' % mode) _chip_view(draw_ell=draw_ell, draw_pts=draw_pts) else: hs_viewtype = ax.__dict__.get('_hs_viewtype', '') print_(' hs_viewtype=%r' % hs_viewtype) if hs_viewtype == 'chip' and event.key == 'shift': print('... masking') # TODO: Do better integration of masking _chip_view() df2.disconnect_callback(fig, 'button_press_event') mc = mask_creator.MaskCreator(df2.gca()) # NOQA elif hs_viewtype == 'chip': kpts = hs.get_kpts(cx) if len(kpts) > 0: fx = nearest_point(x, y, kpts)[0] print('... clicked fx=%r' % fx) _select_ith_kpt(fx) else: print('... len(kpts) == 0') else: print('...Unknown viewtype') viz.draw()
def _plotarrow(x, y, dx, dy, color=df2.BLUE, label=''): ax = df2.gca() arrowargs = dict(head_width=.5, length_includes_head=True, label='') arrow = df2.FancyArrow(x, y, dx, dy, **arrowargs) arrow.set_edgecolor(color) arrow.set_facecolor(color) ax.add_patch(arrow) df2.update()
def annotate_chipres(hs, res, cx, showTF=True, showScore=True, title_pref='', title_suff='', show_2nd_gname=True, show_2nd_name=True, show_1st=True, time_appart=True, in_image=False, offset1=(0, 0), offset2=(0, 0), show_query=True, xywh2=None, **kwargs): printDBG('[viz] annotate_chipres()') #print('Did not expect args: %r' % (kwargs.keys(),)) qcx = res.qcx score = res.cx2_score[cx] matched_kpts = np.float32(len(res.cx2_fs[cx])) # print('matched_kpts= %r'%str(matched_kpts)) # TODO Use this function when you clean show_chipres (truestr, falsestr, nonamestr) = ('TRUE', 'FALSE', '???') is_true, is_unknown = hs.is_true_match(qcx, cx) isgt_str = nonamestr if is_unknown else (truestr if is_true else falsestr) match_color = { nonamestr: df2.UNKNOWN_PURP, truestr: df2.TRUE_GREEN, falsestr: df2.FALSE_RED }[isgt_str] # Build title title = '*%s*' % isgt_str if showTF else '' if showScore: score_str = (' score=' + helpers.num_fmt(score)) % (score) score_str += (' matched_kpts=' + helpers.num_fmt(matched_kpts)) % (matched_kpts) title += score_str title = title_pref + str(title) + title_suff # Build xlabel xlabel_ = [] if 'show_1st': xlabel_.append('top_gname=%r' % hs.cx2_gname(qcx)) xlabel_.append('top_name=%r' % hs.cx2_name(qcx)) if 'show_2nd_gname': xlabel_.append('\n below_gname=%r' % hs.cx2_gname(cx)) if 'show_2nd_name': xlabel_.append('below_name=%r' % hs.cx2_name(cx)) if 'time_appart': xlabel_.append('\n' + hs.get_timedelta_str(qcx, cx)) xlabel = ', '.join(xlabel_) ax = df2.gca() ax._hs_viewtype = 'chipres' ax._hs_qcx = qcx ax._hs_cx = cx if NO_LABEL_OVERRIDE: title = '' xlabel = '' df2.set_title(title, ax) df2.set_xlabel(xlabel, ax) if in_image: roi1 = hs.cx2_roi(qcx) + np.array(list(offset1) + [0, 0]) roi2 = hs.cx2_roi(cx) + np.array(list(offset2) + [0, 0]) theta1 = hs.cx2_theta(qcx) theta2 = hs.cx2_theta(cx) # HACK! lbl1 = 'q' + hs.cidstr(qcx) lbl2 = hs.cidstr(cx) if show_query: df2.draw_roi(roi1, bbox_color=df2.ORANGE, label=lbl1, theta=theta1) df2.draw_roi(roi2, bbox_color=match_color, label=lbl2, theta=theta2) # No matches draw a red box if len(res.cx2_fm[cx]) == 0: df2.draw_boxedX(roi2, theta=theta2) else: if xywh2 is None: xy, w, h = df2._axis_xy_width_height(ax) xywh2 = (xy[0], xy[1], w, h) df2.draw_border(ax, match_color, 4, offset=offset2) # No matches draw a red box if len(res.cx2_fm[cx]) == 0: df2.draw_boxedX(xywh2)
def annotate_chipres(hs, res, cx, showTF=True, showScore=True, title_pref='', title_suff='', show_gname=False, show_name=True, time_appart=True, in_image=False, offset1=(0, 0), offset2=(0, 0), show_query=True, xywh2=None, **kwargs): printDBG('[viz] annotate_chipres()') #print('Did not expect args: %r' % (kwargs.keys(),)) qcx = res.qcx score = res.cx2_score[cx] # TODO Use this function when you clean show_chipres (truestr, falsestr, nonamestr) = ('TRUE', 'FALSE', '???') is_true, is_unknown = hs.is_true_match(qcx, cx) isgt_str = nonamestr if is_unknown else (truestr if is_true else falsestr) match_color = {nonamestr: df2.UNKNOWN_PURP, truestr: df2.TRUE_GREEN, falsestr: df2.FALSE_RED}[isgt_str] # Build title title = '*%s*' % isgt_str if showTF else '' if showScore: score_str = (' score=' + helpers.num_fmt(score)) % (score) title += score_str title = title_pref + str(title) + title_suff # Build xlabel xlabel_ = [] if 'show_gname': xlabel_.append('gname=%r' % hs.cx2_gname(cx)) if 'show_name': xlabel_.append('name=%r' % hs.cx2_name(cx)) if 'time_appart': xlabel_.append('\n' + hs.get_timedelta_str(qcx, cx)) xlabel = ', '.join(xlabel_) ax = df2.gca() ax._hs_viewtype = 'chipres' ax._hs_qcx = qcx ax._hs_cx = cx if NO_LABEL_OVERRIDE: title = '' xlabel = '' df2.set_title(title, ax) df2.set_xlabel(xlabel, ax) if in_image: roi1 = hs.cx2_roi(qcx) + np.array(list(offset1) + [0, 0]) roi2 = hs.cx2_roi(cx) + np.array(list(offset2) + [0, 0]) theta1 = hs.cx2_theta(qcx) theta2 = hs.cx2_theta(cx) # HACK! lbl1 = 'q' + hs.cidstr(qcx) lbl2 = hs.cidstr(cx) if show_query: df2.draw_roi(roi1, bbox_color=df2.ORANGE, label=lbl1, theta=theta1) df2.draw_roi(roi2, bbox_color=match_color, label=lbl2, theta=theta2) # No matches draw a red box if len(res.cx2_fm[cx]) == 0: df2.draw_boxedX(roi2, theta=theta2) else: if xywh2 is None: xy, w, h = df2._axis_xy_width_height(ax) xywh2 = (xy[0], xy[1], w, h) df2.draw_border(ax, match_color, 4, offset=offset2) # No matches draw a red box if len(res.cx2_fm[cx]) == 0: df2.draw_boxedX(xywh2)
def in_depth_ellipse2x2(rchip, kp): #----------------------- # SETUP #----------------------- from hotspotter import draw_func2 as df2 np.set_printoptions(precision=8) tau = 2 * np.pi df2.reset() df2.figure(9003, docla=True, doclf=True) ax = df2.gca() ax.invert_yaxis() def _plotpts(data, px, color=df2.BLUE, label=''): #df2.figure(9003, docla=True, pnum=(1, 1, px)) df2.plot2(data.T[0], data.T[1], '.', '', color=color, label=label) df2.update() def _plotarrow(x, y, dx, dy, color=df2.BLUE, label=''): ax = df2.gca() arrowargs = dict(head_width=.5, length_includes_head=True, label=label) arrow = df2.FancyArrow(x, y, dx, dy, **arrowargs) arrow.set_edgecolor(color) arrow.set_facecolor(color) ax.add_patch(arrow) df2.update() def _2x2_eig(M2x2): (evals, evecs) = np.linalg.eig(M2x2) l1, l2 = evals v1, v2 = evecs return l1, l2, v1, v2 #----------------------- # INPUT #----------------------- # We will call perdoch's invA = invV print('--------------------------------') print('Let V = Perdoch.A') print('Let Z = Perdoch.E') print('--------------------------------') print('Input from Perdoch\'s detector: ') # We are given the keypoint in invA format (x, y, ia11, ia21, ia22), ia12 = kp, 0 invV = np.array([[ia11, ia12], [ia21, ia22]]) V = np.linalg.inv(invV) # <HACK> #invV = V / np.linalg.det(V) #V = np.linalg.inv(V) # </HACK> Z = (V.T).dot(V) print('invV is a transform from points on a unit-circle to the ellipse') helpers.horiz_print('invV = ', invV) print('--------------------------------') print('V is a transformation from points on the ellipse to a unit circle') helpers.horiz_print('V = ', V) print('--------------------------------') print('Points on a matrix satisfy (x).T.dot(Z).dot(x) = 1') print('where Z = (V.T).dot(V)') helpers.horiz_print('Z = ', Z) # Define points on a unit circle theta_list = np.linspace(0, tau, 50) cicrle_pts = np.array([(np.cos(t), np.sin(t)) for t in theta_list]) # Transform those points to the ellipse using invV ellipse_pts1 = invV.dot(cicrle_pts.T).T # Transform those points to the ellipse using V ellipse_pts2 = V.dot(cicrle_pts.T).T #Lets check our assertion: (x_).T.dot(Z).dot(x_) = 1 checks1 = [x_.T.dot(Z).dot(x_) for x_ in ellipse_pts1] checks2 = [x_.T.dot(Z).dot(x_) for x_ in ellipse_pts2] assert all([abs(1 - check) < 1E-11 for check in checks1]) #assert all([abs(1 - check) < 1E-11 for check in checks2]) print('... all of our plotted points satisfy this') #======================= # THE CONIC SECTION #======================= # All of this was from the Perdoch paper, now lets move into conic sections # We will use the notation from wikipedia # http://en.wikipedia.org/wiki/Conic_section # http://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections #----------------------- # MATRIX REPRESENTATION #----------------------- # The matrix representation of a conic is: (A, B2, B2_, C) = Z.flatten() (D, E, F) = (0, 0, 1) B = B2 * 2 assert B2 == B2_, 'matrix should by symmetric' print('--------------------------------') print('Now, using wikipedia\' matrix representation of a conic.') con = np.array(((' A', 'B / 2', 'D / 2'), ('B / 2', ' C', 'E / 2'), ('D / 2', 'E / 2', ' F'))) helpers.horiz_print('A matrix A_Q = ', con) # A_Q is our conic section (aka ellipse matrix) A_Q = np.array((( A, B / 2, D / 2), (B / 2, C, E / 2), (D / 2, E / 2, F))) helpers.horiz_print('A_Q = ', A_Q) #----------------------- # DEGENERATE CONICS #----------------------- print('----------------------------------') print('As long as det(A_Q) != it is not degenerate.') print('If the conic is not degenerate, we can use the 2x2 minor: A_33') print('det(A_Q) = %s' % str(np.linalg.det(A_Q))) assert np.linalg.det(A_Q) != 0, 'degenerate conic' A_33 = np.array((( A, B / 2), (B / 2, C))) helpers.horiz_print('A_33 = ', A_33) #----------------------- # CONIC CLASSIFICATION #----------------------- print('----------------------------------') print('The determinant of the minor classifies the type of conic it is') print('(det == 0): parabola, (det < 0): hyperbola, (det > 0): ellipse') print('det(A_33) = %s' % str(np.linalg.det(A_33))) assert np.linalg.det(A_33) > 0, 'conic is not an ellipse' print('... this is indeed an ellipse') #----------------------- # CONIC CENTER #----------------------- print('----------------------------------') print('the centers of the ellipse are obtained by: ') print('x_center = (B * E - (2 * C * D)) / (4 * A * C - B ** 2)') print('y_center = (D * B - (2 * A * E)) / (4 * A * C - B ** 2)') # Centers are obtained by solving for where the gradient of the quadratic # becomes 0. Without going through the derivation the calculation is... # These should be 0, 0 if we are at the origin, or our original x, y # coordinate specified by the keypoints. I'm doing the calculation just for # shits and giggles x_center = (B * E - (2 * C * D)) / (4 * A * C - B ** 2) y_center = (D * B - (2 * A * E)) / (4 * A * C - B ** 2) helpers.horiz_print('x_center = ', x_center) helpers.horiz_print('y_center = ', y_center) #----------------------- # MAJOR AND MINOR AXES #----------------------- # Now we are going to determine the major and minor axis # of this beast. It just the center augmented by the eigenvecs print('----------------------------------') # The angle between the major axis and our x axis is: l1, l2, v1, v2 = _2x2_eig(A_33) x_axis = np.array([1, 0]) theta = np.arccos(x_axis.dot(v1)) # The eccentricity is determined by: nu = 1 numer = 2 * np.sqrt((A - C) ** 2 + B ** 2) denom = nu * (A + C) + np.sqrt((A - C) ** 2 + B ** 2) eccentricity = np.sqrt(numer / denom) from scipy.special import ellipeinc #----------------------- # DRAWING #----------------------- # Lets start off by drawing the ellipse that we are goign to work with # Create unit circle sample # Draw the keypoint using the tried and true df2 # Other things should subsiquently align df2.draw_kpts2(np.array([(0, 0, ia11, ia21, ia22)]), ell_linewidth=4, ell_color=df2.DEEP_PINK, ell_alpha=1, arrow=True, rect=True) # Plot ellipse points _plotpts(ellipse_pts1, 0, df2.YELLOW, label='invV.dot(cicrle_pts.T).T') # Plot ellipse axis # !HELP! I DO NOT KNOW WHY I HAVE TO DIVIDE, SQUARE ROOT, AND NEGATE!!! l1, l2, v1, v2 = _2x2_eig(A_33) dx1, dy1 = (v1 / np.sqrt(l1)) dx2, dy2 = (v2 / np.sqrt(l2)) _plotarrow(0, 0, dx1, -dy1, color=df2.ORANGE, label='ellipse axis') _plotarrow(0, 0, dx2, -dy2, color=df2.ORANGE) # Plot ellipse orientation orient_axis = invV.dot(np.eye(2)) dx1, dx2, dy1, dy2 = orient_axis.flatten() _plotarrow(0, 0, dx1, dy1, color=df2.BLUE, label='ellipse rotation') _plotarrow(0, 0, dx2, dy2, color=df2.BLUE) df2.legend() df2.dark_background() df2.gca().invert_yaxis() return locals()
def begin_interaction(type_, fnum): print('[inter] starting %s interaction' % type_) fig = df2.figure(fnum=fnum, docla=True, doclf=True) ax = df2.gca() df2.disconnect_callback(fig, 'button_press_event', axes=[ax]) return fig
def query_last_feature(): viz.show_nearest_descriptors(hs, qcx, last_state.last_fx, df2.next_fnum()) fig3 = df2.gca() df2.connect_callback(fig3, 'button_press_event', _click_chipres_click) df2.update()
def show_descriptors_match_distances(orgres2_distance, fnum=1, db_name='', **kwargs): disttype_list = orgres2_distance.itervalues().next().keys() orgtype_list = orgres2_distance.keys() (nRow, nCol) = len(orgtype_list), len(disttype_list) nColors = nRow * nCol color_list = df2.distinct_colors(nColors) df2.figure(fnum=fnum, docla=True, doclf=True) pnum_ = lambda px: (nRow, nCol, px + 1) plot_type = helpers.get_arg('--plot-type', default='plot') # Remember min and max val for each distance type (l1, emd...) distkey2_min = {distkey: np.uint64(-1) for distkey in disttype_list} distkey2_max = {distkey: 0 for distkey in disttype_list} def _distplot(dists, color, label, distkey, plot_type=plot_type): data = sorted(dists) ax = df2.gca() min_ = distkey2_min[distkey] max_ = distkey2_max[distkey] if plot_type == 'plot': df2.plot(data, color=color, label=label, yscale='linear') #xticks = np.linspace(np.min(data), np.max(data), 3) #yticks = np.linspace(0, len(data), 5) #ax.set_xticks(xticks) #ax.set_yticks(yticks) ax.set_ylim(min_, max_) ax.set_xlim(0, len(dists)) ax.set_ylabel('distance') ax.set_xlabel('matches indexes (sorted by distance)') df2.legend(loc='lower right') if plot_type == 'pdf': df2.plot_pdf(data, color=color, label=label) ax.set_ylabel('pr') ax.set_xlabel('distance') ax.set_xlim(min_, max_) df2.legend(loc='upper left') df2.dark_background(ax) df2.small_xticks(ax) df2.small_yticks(ax) px = 0 for orgkey in orgtype_list: for distkey in disttype_list: dists = orgres2_distance[orgkey][distkey] if len(dists) == 0: continue min_ = dists.min() max_ = dists.max() distkey2_min[distkey] = min(distkey2_min[distkey], min_) distkey2_max[distkey] = max(distkey2_max[distkey], max_) for count, orgkey in enumerate(orgtype_list): for distkey in disttype_list: printDBG('[allres-viz] plotting: %r' % ((orgkey, distkey), )) dists = orgres2_distance[orgkey][distkey] df2.figure(fnum=fnum, pnum=pnum_(px)) color = color_list[px] title = distkey + ' ' + orgkey label = 'P(%s | %s)' % (distkey, orgkey) _distplot(dists, color, label, distkey, **kwargs) if count == 0: ax = df2.gca() ax.set_title(distkey) px += 1 subtitle = 'the matching distances between sift descriptors' title = '(sift) matching distances' if db_name != '': title = db_name + ' ' + title df2.set_figtitle(title, subtitle) df2.adjust_subplots_safe()
def in_depth_ellipse2x2(rchip, kp): #----------------------- # SETUP #----------------------- from hotspotter import draw_func2 as df2 np.set_printoptions(precision=8) tau = 2 * np.pi df2.reset() df2.figure(9003, docla=True, doclf=True) ax = df2.gca() ax.invert_yaxis() def _plotpts(data, px, color=df2.BLUE, label=''): #df2.figure(9003, docla=True, pnum=(1, 1, px)) df2.plot2(data.T[0], data.T[1], '.', '', color=color, label=label) df2.update() def _plotarrow(x, y, dx, dy, color=df2.BLUE, label=''): ax = df2.gca() arrowargs = dict(head_width=.5, length_includes_head=True, label=label) arrow = df2.FancyArrow(x, y, dx, dy, **arrowargs) arrow.set_edgecolor(color) arrow.set_facecolor(color) ax.add_patch(arrow) df2.update() def _2x2_eig(M2x2): (evals, evecs) = np.linalg.eig(M2x2) l1, l2 = evals v1, v2 = evecs return l1, l2, v1, v2 #----------------------- # INPUT #----------------------- # We will call perdoch's invA = invV print('--------------------------------') print('Let V = Perdoch.A') print('Let Z = Perdoch.E') print('--------------------------------') print('Input from Perdoch\'s detector: ') # We are given the keypoint in invA format (x, y, ia11, ia21, ia22), ia12 = kp, 0 invV = np.array([[ia11, ia12], [ia21, ia22]]) V = np.linalg.inv(invV) # <HACK> #invV = V / np.linalg.det(V) #V = np.linalg.inv(V) # </HACK> Z = (V.T).dot(V) print('invV is a transform from points on a unit-circle to the ellipse') helpers.horiz_print('invV = ', invV) print('--------------------------------') print('V is a transformation from points on the ellipse to a unit circle') helpers.horiz_print('V = ', V) print('--------------------------------') print('Points on a matrix satisfy (x).T.dot(Z).dot(x) = 1') print('where Z = (V.T).dot(V)') helpers.horiz_print('Z = ', Z) # Define points on a unit circle theta_list = np.linspace(0, tau, 50) cicrle_pts = np.array([(np.cos(t), np.sin(t)) for t in theta_list]) # Transform those points to the ellipse using invV ellipse_pts1 = invV.dot(cicrle_pts.T).T # Transform those points to the ellipse using V ellipse_pts2 = V.dot(cicrle_pts.T).T #Lets check our assertion: (x_).T.dot(Z).dot(x_) = 1 checks1 = [x_.T.dot(Z).dot(x_) for x_ in ellipse_pts1] checks2 = [x_.T.dot(Z).dot(x_) for x_ in ellipse_pts2] assert all([abs(1 - check) < 1E-11 for check in checks1]) #assert all([abs(1 - check) < 1E-11 for check in checks2]) print('... all of our plotted points satisfy this') #======================= # THE CONIC SECTION #======================= # All of this was from the Perdoch paper, now lets move into conic sections # We will use the notation from wikipedia # http://en.wikipedia.org/wiki/Conic_section # http://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections #----------------------- # MATRIX REPRESENTATION #----------------------- # The matrix representation of a conic is: (A, B2, B2_, C) = Z.flatten() (D, E, F) = (0, 0, 1) B = B2 * 2 assert B2 == B2_, 'matrix should by symmetric' print('--------------------------------') print('Now, using wikipedia\' matrix representation of a conic.') con = np.array(((' A', 'B / 2', 'D / 2'), ('B / 2', ' C', 'E / 2'), ('D / 2', 'E / 2', ' F'))) helpers.horiz_print('A matrix A_Q = ', con) # A_Q is our conic section (aka ellipse matrix) A_Q = np.array(((A, B / 2, D / 2), (B / 2, C, E / 2), (D / 2, E / 2, F))) helpers.horiz_print('A_Q = ', A_Q) #----------------------- # DEGENERATE CONICS #----------------------- print('----------------------------------') print('As long as det(A_Q) != it is not degenerate.') print('If the conic is not degenerate, we can use the 2x2 minor: A_33') print('det(A_Q) = %s' % str(np.linalg.det(A_Q))) assert np.linalg.det(A_Q) != 0, 'degenerate conic' A_33 = np.array(((A, B / 2), (B / 2, C))) helpers.horiz_print('A_33 = ', A_33) #----------------------- # CONIC CLASSIFICATION #----------------------- print('----------------------------------') print('The determinant of the minor classifies the type of conic it is') print('(det == 0): parabola, (det < 0): hyperbola, (det > 0): ellipse') print('det(A_33) = %s' % str(np.linalg.det(A_33))) assert np.linalg.det(A_33) > 0, 'conic is not an ellipse' print('... this is indeed an ellipse') #----------------------- # CONIC CENTER #----------------------- print('----------------------------------') print('the centers of the ellipse are obtained by: ') print('x_center = (B * E - (2 * C * D)) / (4 * A * C - B ** 2)') print('y_center = (D * B - (2 * A * E)) / (4 * A * C - B ** 2)') # Centers are obtained by solving for where the gradient of the quadratic # becomes 0. Without going through the derivation the calculation is... # These should be 0, 0 if we are at the origin, or our original x, y # coordinate specified by the keypoints. I'm doing the calculation just for # shits and giggles x_center = (B * E - (2 * C * D)) / (4 * A * C - B**2) y_center = (D * B - (2 * A * E)) / (4 * A * C - B**2) helpers.horiz_print('x_center = ', x_center) helpers.horiz_print('y_center = ', y_center) #----------------------- # MAJOR AND MINOR AXES #----------------------- # Now we are going to determine the major and minor axis # of this beast. It just the center augmented by the eigenvecs print('----------------------------------') # The angle between the major axis and our x axis is: l1, l2, v1, v2 = _2x2_eig(A_33) x_axis = np.array([1, 0]) theta = np.arccos(x_axis.dot(v1)) # The eccentricity is determined by: nu = 1 numer = 2 * np.sqrt((A - C)**2 + B**2) denom = nu * (A + C) + np.sqrt((A - C)**2 + B**2) eccentricity = np.sqrt(numer / denom) from scipy.special import ellipeinc #----------------------- # DRAWING #----------------------- # Lets start off by drawing the ellipse that we are goign to work with # Create unit circle sample # Draw the keypoint using the tried and true df2 # Other things should subsiquently align df2.draw_kpts2(np.array([(0, 0, ia11, ia21, ia22)]), ell_linewidth=4, ell_color=df2.DEEP_PINK, ell_alpha=1, arrow=True, rect=True) # Plot ellipse points _plotpts(ellipse_pts1, 0, df2.YELLOW, label='invV.dot(cicrle_pts.T).T') # Plot ellipse axis # !HELP! I DO NOT KNOW WHY I HAVE TO DIVIDE, SQUARE ROOT, AND NEGATE!!! l1, l2, v1, v2 = _2x2_eig(A_33) dx1, dy1 = (v1 / np.sqrt(l1)) dx2, dy2 = (v2 / np.sqrt(l2)) _plotarrow(0, 0, dx1, -dy1, color=df2.ORANGE, label='ellipse axis') _plotarrow(0, 0, dx2, -dy2, color=df2.ORANGE) # Plot ellipse orientation orient_axis = invV.dot(np.eye(2)) dx1, dx2, dy1, dy2 = orient_axis.flatten() _plotarrow(0, 0, dx1, dy1, color=df2.BLUE, label='ellipse rotation') _plotarrow(0, 0, dx2, dy2, color=df2.BLUE) df2.legend() df2.dark_background() df2.gca().invert_yaxis() return locals()