def _annotate_kpts(kpts, sel_fx, draw_ell, draw_pts, color=None, nRandKpts=None, rect=False): #print('[viz] _annotate_kpts()') if color is None: color = 'distinct' if sel_fx is None else df2.ORANGE ell_args = { 'ell': draw_ell, 'pts': draw_pts, 'rect': rect, 'ell_alpha': .4, 'ell_linewidth': 2, 'ell_color': color, } if draw_ell and nRandKpts is not None: # show a random sample of kpts nkpts1 = len(kpts) fxs1 = np.arange(nkpts1) size = nRandKpts replace = False p = np.ones(nkpts1) p = p / p.sum() fxs_randsamp = np.random.choice(fxs1, size, replace, p) kpts = kpts[fxs_randsamp] # TODO Fix this. This should not set the xlabel df2.set_xlabel('displaying %r/%r keypoints' % (nRandKpts, nkpts1)) elif draw_ell or draw_pts: # draw all keypoints df2.draw_kpts2(kpts, **ell_args) if sel_fx is not None: # Draw selected keypoint sel_kpts = kpts[sel_fx:sel_fx + 1] df2.draw_kpts2(sel_kpts, ell_color=df2.BLUE, arrow=True, rect=True)
def draw_keypoint_patch(rchip, kp, sift=None, warped=False, **kwargs): #print('--------------------') #print('[extract] Draw Patch') if warped: wpatch, wkp = get_warped_patch(rchip, kp) patch = wpatch subkp = wkp else: patch, subkp = get_patch(rchip, kp) #print('[extract] kp = '+str(kp)) #print('[extract] subkp = '+str(subkp)) #print('[extract] patch.shape = %r' % (patch.shape,)) color = (0, 0, 1) fig, ax = df2.imshow(patch, **kwargs) df2.draw_kpts2([subkp], ell_color=color, pts=True) if not sift is None: df2.draw_sift(sift, [subkp]) return ax
def test(hs, qcx): fx2_scale = sv2.keypoint_scale(hs.feats.cx2_kpts[qcx]) fx = fx2_scale.argsort()[::-1][40] rchip = hs.get_chip(qcx) kp = hs.feats.cx2_kpts[qcx][fx] # Show full image and keypoint df2.figure(fignum=9000, doclf=True) df2.imshow(rchip, plotnum=(1,3,1)) df2.draw_kpts2([kp], ell_color=(1,0,0), pts=True) # Show cropped image and keypoint patch, subkp = get_patch(rchip, kp) df2.imshow(patch, plotnum=(1,3,2)) df2.draw_kpts2([subkp], ell_color=(1,0,0), pts=True) # Show warped image and keypoint wpatch, wkp = get_warped_patch(rchip, kp) df2.imshow(wpatch, plotnum=(1,3,3)) df2.draw_kpts2([wkp], ell_color=(1,0,0), pts=True) # df2.set_figtitle('warp test')
def _kpts_helper(kpts_, color, alpha, label): # helper function taking into acount phantom labels df2.draw_kpts2(kpts_, ell_color=color, ell_alpha=alpha) df2.phantom_legend_label(label, color)
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 draw_one_kp(patch, kp, plotx, color, desc=None): fig, ax = df2.imshow(patch, plotnum=(num_rows, num_cols, plotx)) df2.draw_kpts2([kp], ell_color=color, pts=True) if not desc is None and not '--nodesc' in sys.argv: df2.draw_sift(desc, [kp]) df2.draw_border(ax, color, 1)
def viz_top_features(hs, res, low, high, fignum=0, draw_chips=True): from collections import defaultdict qcx = res.qcx cx2_nx = hs.tables.cx2_nx top_patches_list = get_top_scoring_patches(hs, res, low, high) num_rows = high-low num_cols = 4 if params.__MATCH_TYPE__ == 'vsmany': num_cols = 6 # Initialize Figure fig = df2.figure(fignum+1, plotnum=(num_rows, num_cols,1)) cx2_rchip = defaultdict(int) cx2_kplist = defaultdict(list) def draw_one_kp(patch, kp, plotx, color, desc=None): fig, ax = df2.imshow(patch, plotnum=(num_rows, num_cols, plotx)) df2.draw_kpts2([kp], ell_color=color, pts=True) if not desc is None and not '--nodesc' in sys.argv: df2.draw_sift(desc, [kp]) df2.draw_border(ax, color, 1) for tx, (patches1, patches2, patchesN, cx, feat_score) in enumerate(top_patches_list): (kp1, subkp1, wkp1, patch1, wpatch1, cx1, desc1) = patches1 (kp2, subkp2, wkp2, patch2, wpatch2, cx2, desc2) = patches2 # draw on table # Draw Query Keypoint plotx = (tx*num_cols) draw_one_kp(patch1, subkp1, plotx+1, df2.GREEN, desc1) qnx = cx2_nx[qcx] df2.plt.gca().set_xlabel('qcx=%r; qnx=%r' % (qcx, qnx)) draw_one_kp(wpatch1, wkp1, plotx+2, df2.GREEN, desc1) # Draw ith < k match draw_one_kp(patch2, subkp2, plotx+3, df2.BLUE, desc2) nx = cx2_nx[cx] df2.plt.gca().set_xlabel('cx=%r; nx=%r' % (cx, nx)) draw_one_kp(wpatch2, wkp2, plotx+4, df2.BLUE, desc2) df2.plt.gca().set_xlabel('score=%r' % (feat_score)) # Draw k+1th match if params.__MATCH_TYPE__ == 'vsmany': (kpN, subkpN, wkpN, patchN, wpatchN, cxN, descN) = patchesN draw_one_kp(patchN, subkpN, plotx+5, df2.ORANGE, descN) nxN = cx2_nx[qcx] df2.plt.gca().set_xlabel('cxN=%r; nxN=%r' % (cxN, nxN)) draw_one_kp(wpatchN, wkpN, plotx+6, df2.ORANGE, descN) # Get other info cx2_rchip[cx] = hs.get_chip(cx) cx2_kplist[qcx].append(kp1) cx2_kplist[cx].append(kp2) # Draw annotations on df2.figure(plotnum=(num_rows, num_cols,1), title='Query Patch') df2.figure(plotnum=(num_rows, num_cols,2), title='Query Patch') df2.figure(plotnum=(num_rows, num_cols,3), title='Result Patch') df2.figure(plotnum=(num_rows, num_cols,4), title='Result Warped') if params.__MATCH_TYPE__ == 'vsmany': df2.figure(plotnum=(num_rows, num_cols,5), title='Normalizer Patch') df2.figure(plotnum=(num_rows, num_cols,6), title='Normalizer Warped') df2.set_figtitle('Top '+str(low)+' to '+str(high)+' scoring matches') if not draw_chips: return # # Draw on full images cx2_rchip[qcx] = hs.get_chip(qcx) cx_keys = cx2_kplist.keys() cx_vals = map(len, cx2_kplist.values()) cx_list = [x for (y,x) in sorted(zip(cx_vals, cx_keys))][::-1] num_chips = len(cx_list) pltnum_fn = lambda ix: (int(np.ceil(num_chips/2)), 2, ix) plotnum = pltnum_fn(1) fig2 = df2.figure(fignum-1, plotnum=plotnum) for ix, cx in enumerate(cx_list): plotnum = pltnum_fn(ix+1) fig2 = df2.figure(fignum-1, plotnum=plotnum) rchip = cx2_rchip[cx] fig, ax = df2.imshow(rchip) title_pref = '' color = df2.BLUE if res.qcx == cx: title_pref = 'q' color = df2.GREEN df2.draw_kpts2(cx2_kplist[cx], ell_color=color, ell_alpha=1) df2.draw_border(ax, color, 2) nx = cx2_nx[cx] ax.set_title(title_pref+'cx = %r; nx=%r' % (cx, nx)) gname = hs.get_gname(cx) ax.set_xlabel(gname)
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()