def show_nearest_descriptors(hs, qcx, qfx, fnum=None): if fnum is None: fnum = df2.next_fnum() # Inspect the nearest neighbors of a descriptor dx2_cx = hs.qdat._data_index.ax2_cx dx2_fx = hs.qdat._data_index.ax2_fx K = hs.qdat.cfg.nn_cfg.K Knorm = hs.qdat.cfg.nn_cfg.Knorm checks = hs.qdat.cfg.nn_cfg.checks flann = hs.qdat._data_index.flann qfx2_desc = hs.get_desc(qcx)[qfx:qfx + 1] try: (qfx2_dx, qfx2_dist) = flann.nn_index(qfx2_desc, K + Knorm, checks=checks) qfx2_cx = dx2_cx[qfx2_dx] qfx2_fx = dx2_fx[qfx2_dx] def get_extract_tuple(cx, fx, k=-1): rchip = hs.get_chip(cx) kp = hs.get_kpts(cx)[fx] sift = hs.get_desc(cx)[fx] if k == -1: info = '\nquery %s, fx=%r' % (hs.cidstr(cx), fx) type_ = 'query' elif k < K: type_ = 'match' info = '\nmatch %s, fx=%r k=%r, dist=%r' % (hs.cidstr(cx), fx, k, qfx2_dist[0, k]) elif k < Knorm + K: type_ = 'norm' info = '\nnorm %s, fx=%r k=%r, dist=%r' % (hs.cidstr(cx), fx, k, qfx2_dist[0, k]) else: raise Exception('[viz] problem k=%r') return (rchip, kp, sift, fx, cx, info, type_) extracted_list = [] extracted_list.append(get_extract_tuple(qcx, qfx, -1)) for k in xrange(K + Knorm): tup = get_extract_tuple(qfx2_cx[0, k], qfx2_fx[0, k], k) extracted_list.append(tup) #print('[viz] K + Knorm = %r' % (K + Knorm)) # Draw the _select_ith_match plot nRows, nCols = len(extracted_list), 3 # Draw selected feature matches prevsift = None df2.figure(fnum=fnum, docla=True, doclf=True) px = 0 # plot offset for (rchip, kp, sift, fx, cx, info, type_) in extracted_list: print('[viz] ' + info.replace('\n', '')) px = draw_feat_row(rchip, fx, kp, sift, fnum, nRows, nCols, px, prevsift=prevsift, cx=cx, info=info, type_=type_) prevsift = sift df2.adjust_subplots_safe(hspace=1) except Exception as ex: print('[viz] Error in show nearest descriptors') print(ex) raise
def plot_rank_histogram(allres, orgres_type): print('[viz] plotting %r rank histogram' % orgres_type) ranks = allres.__dict__[orgres_type].ranks label = 'P(rank | ' + orgres_type + ' match)' title = orgres_type + ' match rankings histogram\n' + allres.title_suffix df2.figure(fnum=FIGNUM, doclf=True, title=title) df2.draw_histpdf(ranks, label=label) # FIXME df2.set_xlabel('ground truth ranks') df2.set_ylabel('frequency') df2.legend() __dump_or_browse(allres.hs, 'rankviz')
def _chipmatch_view(pnum=(1, 1, 1), **kwargs): mode = annote_ptr[0] draw_ell = mode >= 1 draw_lines = mode == 2 annote_ptr[0] = (annote_ptr[0] + 1) % 3 df2.figure(fnum=fnum, docla=True, doclf=True) # TODO RENAME This to remove res and rectify with show_chipres tup = viz.res_show_chipres(res, hs, cx, fnum=fnum, pnum=pnum, draw_lines=draw_lines, draw_ell=draw_ell, colorbar_=True, **kwargs) ax, xywh1, xywh2 = tup xywh2_ptr[0] = xywh2 df2.set_figtitle(figtitle + hs.vs_str(qcx, cx))
def plot_score_pdf(allres, orgres_type, colorx=0.0, variation_truncate=False): print('[viz] plotting ' + orgres_type + ' score pdf') title = orgres_type + ' match score frequencies\n' + allres.title_suffix scores = allres.__dict__[orgres_type].scores print('[viz] len(scores) = %r ' % (len(scores), )) label = 'P(score | %r)' % orgres_type df2.figure(fnum=FIGNUM, doclf=True, title=title) df2.draw_pdf(scores, label=label, colorx=colorx) if variation_truncate: df2.variation_trunctate(scores) #df2.variation_trunctate(false.scores) df2.set_xlabel('score') df2.set_ylabel('frequency') df2.legend() __dump_or_browse(allres.hs, 'scoreviz')
def plot_rank_stem(allres, orgres_type='true'): print('[viz] plotting rank stem') # Visualize rankings with the stem plot hs = allres.hs title = orgres_type + 'rankings stem plot\n' + allres.title_suffix orgres = allres.__dict__[orgres_type] df2.figure(fnum=FIGNUM, doclf=True, title=title) x_data = orgres.qcxs y_data = orgres.ranks df2.draw_stems(x_data, y_data) slice_num = int(np.ceil(np.log10(len(orgres.qcxs)))) df2.set_xticks(hs.test_sample_cx[::slice_num]) df2.set_xlabel('query chip indeX (qcx)') df2.set_ylabel('groundtruth chip ranks') #df2.set_yticks(list(seen_ranks)) __dump_or_browse(allres.hs, 'rankviz')
def plot_name(hs, nx, nx2_cxs=None, fignum=0, **kwargs): print('[viz*] plot_name nx=%r' % nx) if not 'fignum' in vars(): kwargs = {} fignum = 0 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*] plot_name %r' % hs.cxstr(cxs)) ncxs = len(cxs) nCols = int(min(np.ceil(np.sqrt(ncxs)), 5)) nRows = int(np.ceil(ncxs / nCols)) print('[viz*] r=%r, c=%r' % (nRows, nCols)) gs2 = gridspec.GridSpec(nRows, nCols) fig = df2.figure(fignum=fignum, **kwargs) fig.clf() for ss, cx in zip(gs2, cxs): ax = fig.add_subplot(ss) plot_cx(hs, cx) title = 'nx=%r -- name=%r' % (nx, name) #gs2.tight_layout(fig) #gs2.update(top=df2.TOP_SUBPLOT_ADJUST) df2.set_figtitle(title)
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 draw_splash(self): print('[back] draw_splash()') img = imread('_frontend/splash.png') fig = df2.figure() print(fig) print(fig is self.win.plotWidget.figure) df2.imshow(img) df2.update()
def _ctrlclicked_cx(cx): printDBG('ctrl+clicked cx=%r' % cx) fnum = FNUMS['special'] fig = df2.figure(fnum=fnum, docla=True, doclf=True) df2.disconnect_callback(fig, 'button_press_event') viz_spatial_verification(hs, res.qcx, cx2=cx, fnum=fnum) fig.canvas.draw() df2.bring_to_front(fig)
def _select_ith_match(mx, qcx, cx): #---------------------- # Get info for the _select_ith_match plot annote_ptr[0] = 1 # Get the mx-th feature match cx1, cx2 = qcx, cx fx1, fx2 = fm[mx] fscore2 = res.cx2_fs[cx2][mx] fk2 = res.cx2_fk[cx2][mx] kpts1, kpts2 = hs.get_kpts([cx1, cx2]) desc1, desc2 = hs.get_desc([cx1, cx2]) kp1, kp2 = kpts1[fx1], kpts2[fx2] sift1, sift2 = desc1[fx1], desc2[fx2] info1 = '\nquery' info2 = '\nk=%r fscore=%r' % (fk2, fscore2) last_state.last_fx = fx1 # Extracted keypoints to draw extracted_list = [(rchip1, kp1, sift1, fx1, cx1, info1), (rchip2, kp2, sift2, fx2, cx2, info2)] # Normalizng Keypoint if hasattr(res, 'filt2_meta') and 'lnbnn' in res.filt2_meta: qfx2_norm = res.filt2_meta['lnbnn'] # Normalizing chip and feature (cx3, fx3, normk) = qfx2_norm[fx1] rchip3 = hs.get_chip(cx3) kp3 = hs.get_kpts(cx3)[fx3] sift3 = hs.get_desc(cx3)[fx3] info3 = '\nnorm %s k=%r' % (hs.cidstr(cx3), normk) extracted_list.append((rchip3, kp3, sift3, fx3, cx3, info3)) else: print('WARNING: meta doesnt exist') #---------------------- # Draw the _select_ith_match plot nRows, nCols = len(extracted_list) + same_fig, 3 # Draw matching chips and features sel_fm = np.array([(fx1, fx2)]) pnum1 = (nRows, 1, 1) if same_fig else (1, 1, 1) _chipmatch_view(pnum1, vert=False, ell_alpha=.4, ell_linewidth=1.8, colors=df2.BLUE, sel_fm=sel_fm, **kwargs) # Draw selected feature matches px = nCols * same_fig # plot offset prevsift = None if not same_fig: fnum2 = fnum + len(viz.FNUMS) fig2 = df2.figure(fnum=fnum2, docla=True, doclf=True) else: fnum2 = fnum for (rchip, kp, sift, fx, cx, info) in extracted_list: px = viz.draw_feat_row(rchip, fx, kp, sift, fnum2, nRows, nCols, px, prevsift=prevsift, cx=cx, info=info) prevsift = sift if not same_fig: df2.connect_callback(fig2, 'button_press_event', _click_chipres_click) df2.set_figtitle(figtitle + hs.vs_str(qcx, cx))
def test3(): desc = np.random.rand(128) desc = desc / np.sqrt((desc**2).sum()) desc = np.round(desc * 255) print desc fig = df2.figure(fignum=43) ax = df2.plt.gca() ax.set_xlim(-1,1) ax.set_ylim(-1,1) df2.draw_sift(desc)
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 dump_orgres_matches(allres, orgres_type): orgres = allres.__dict__[orgres_type] hs = allres.hs qcx2_res = allres.qcx2_res # loop over each query / result of interest for qcx, cx, score, rank in orgres.iter(): query_gname, _ = os.path.splitext( hs.tables.gx2_gname[hs.tables.cx2_gx[qcx]]) result_gname, _ = os.path.splitext( hs.tables.gx2_gname[hs.tables.cx2_gx[cx]]) res = qcx2_res[qcx] df2.figure(fnum=FIGNUM, pnum=121) df2.show_matches3(res, hs, cx, SV=False, fnum=FIGNUM, pnum=121) df2.show_matches3(res, hs, cx, SV=True, fnum=FIGNUM, pnum=122) big_title = 'score=%.2f_rank=%d_q=%s_r=%s' % (score, rank, query_gname, result_gname) df2.set_figtitle(big_title) __dump_or_browse(allres.hs, orgres_type + '_matches' + allres.title_suffix)
def show_image(hs, gx, sel_cxs=[], fnum=1, figtitle='Img', annote=True, draw_lbls=True, **kwargs): # Shows an image with annotations gname = hs.tables.gx2_gname[gx] title = 'gx=%r gname=%r' % (gx, gname) img = hs.gx2_image(gx) fig = df2.figure(fnum=fnum, docla=True) fig, ax = df2.imshow(img, title=title, fnum=fnum, **kwargs) ax._hs_viewtype = 'image' _annotate_image(hs, ax, gx, sel_cxs, draw_lbls, annote) df2.set_figtitle(figtitle)
def plot_tt_bt_tf_matches(hs, allres, qcx): #print('Visualizing result: ') #res.printme() res = allres.qcx2_res[qcx] ranks = (allres.top_true_qcx_arrays[0][qcx], allres.bot_true_qcx_arrays[0][qcx], allres.top_false_qcx_arrays[0][qcx]) #scores = (allres.top_true_qcx_arrays[1][qcx], #allres.bot_true_qcx_arrays[1][qcx], #allres.top_false_qcx_arrays[1][qcx]) cxs = (allres.top_true_qcx_arrays[2][qcx], allres.bot_true_qcx_arrays[2][qcx], allres.top_false_qcx_arrays[2][qcx]) titles = ('best True rank=' + str(ranks[0]) + ' ', 'worst True rank=' + str(ranks[1]) + ' ', 'best False rank=' + str(ranks[2]) + ' ') df2.figure(fnum=1, pnum=231) res.plot_matches(res, hs, cxs[0], False, fnum=1, pnum=131, title_aug=titles[0]) res.plot_matches(res, hs, cxs[1], False, fnum=1, pnum=132, title_aug=titles[1]) res.plot_matches(res, hs, cxs[2], False, fnum=1, pnum=133, title_aug=titles[2]) fig_title = 'fig q' + hs.cidstr( qcx) + ' TT BT TF -- ' + allres.title_suffix df2.set_figtitle(fig_title)
def plot_score_matrix(allres): print('[viz] plotting score matrix') score_matrix = allres.score_matrix title = 'Score Matrix\n' + allres.title_suffix # Find inliers #inliers = helpers.find_std_inliers(score_matrix) #max_inlier = score_matrix[inliers].max() # Trunate above 255 score_img = np.copy(score_matrix) #score_img[score_img < 0] = 0 #score_img[score_img > 255] = 255 #dim = 0 #score_img = helpers.norm_zero_one(score_img, dim=dim) # Make colors scores = score_img.flatten() colors = df2.scores_to_color(scores, logscale=True) cmap = df2.scores_to_cmap(scores, colors) df2.figure(fnum=FIGNUM, doclf=True, title=title) # Show score matrix df2.imshow(score_img, fnum=FIGNUM, cmap=cmap) # Colorbar df2.colorbar(scores, colors) df2.set_xlabel('database') df2.set_ylabel('queries')
def viz_spatial_verification(hs, cx1, figtitle='Spatial Verification View', **kwargs): #kwargs = {} from hscom import helpers from hotspotter import spatial_verification2 as sv2 import cv2 print('\n======================') cx2 = ensure_cx2(hs, cx1, kwargs.pop('cx2', None)) print('[viz] viz_spatial_verification %s' % hs.vs_str(cx1, cx2)) fnum = kwargs.get('fnum', 4) fm = ensure_fm(hs, cx1, cx2, kwargs.pop('fm', None), kwargs.pop('res', 'db')) # Get keypoints rchip1 = kwargs['rchip1'] if 'rchip1' in kwargs else hs.get_chip(cx1) rchip2 = kwargs['rchip2'] if 'rchip1' in kwargs else hs.get_chip(cx2) kpts1 = kwargs['kpts1'] if 'kpts1' in kwargs else hs.get_kpts(cx1) kpts2 = kwargs['kpts2'] if 'kpts2' in kwargs else hs.get_kpts(cx2) dlen_sqrd2 = rchip2.shape[0]**2 + rchip2.shape[1]**2 # rchips are in shape = (height, width) (h1, w1) = rchip1.shape[0:2] (h2, w2) = rchip2.shape[0:2] #wh1 = (w1, h1) wh2 = (w2, h2) #print('[viz.sv] wh1 = %r' % (wh1,)) #print('[viz.sv] wh2 = %r' % (wh2,)) # Get affine and homog mapping from rchip1 to rchip2 xy_thresh = hs.prefs.query_cfg.sv_cfg.xy_thresh max_scale = hs.prefs.query_cfg.sv_cfg.scale_thresh_high min_scale = hs.prefs.query_cfg.sv_cfg.scale_thresh_low homog_args = [ kpts1, kpts2, fm, xy_thresh, max_scale, min_scale, dlen_sqrd2, 4 ] try: Aff, aff_inliers = sv2.homography_inliers(*homog_args, just_affine=True) H, inliers = sv2.homography_inliers(*homog_args, just_affine=False) except Exception as ex: print('[viz] homog_args = %r' % (homog_args)) print('[viz] ex = %r' % (ex, )) raise print(helpers.horiz_string(['H = ', str(H)])) print(helpers.horiz_string(['Aff = ', str(Aff)])) # Transform the chips print('warp homog') rchip1_Ht = cv2.warpPerspective(rchip1, H, wh2) print('warp affine') rchip1_At = cv2.warpAffine(rchip1, Aff[0:2, :], wh2) rchip2_blendA = np.zeros(rchip2.shape, dtype=rchip2.dtype) rchip2_blendH = np.zeros(rchip2.shape, dtype=rchip2.dtype) rchip2_blendA = rchip2 / 2 + rchip1_At / 2 rchip2_blendH = rchip2 / 2 + rchip1_Ht / 2 df2.figure(fnum=fnum, pnum=(3, 4, 1), docla=True, doclf=True) def _draw_chip(title, chip, px, *args, **kwargs): df2.imshow(chip, *args, title=title, fnum=fnum, pnum=(3, 4, px), **kwargs) # Draw original matches, affine inliers, and homography inliers def _draw_matches(title, fm, px): # Helper with common arguments to df2.show_chipmatch2 dmkwargs = dict(fs=None, title=title, all_kpts=False, draw_lines=True, docla=True, fnum=fnum, pnum=(3, 3, px)) df2.show_chipmatch2(rchip1, rchip2, kpts1, kpts2, fm, show_nMatches=True, **dmkwargs) # Draw the Assigned -> Affine -> Homography matches _draw_matches('Assigned matches', fm, 1) _draw_matches('Affine inliers', fm[aff_inliers], 2) _draw_matches('Homography inliers', fm[inliers], 3) # Draw the Affine Transformations _draw_chip('Source', rchip1, 5) _draw_chip('Affine', rchip1_At, 6) _draw_chip('Destination', rchip2, 7) _draw_chip('Aff Blend', rchip2_blendA, 8) # Draw the Homography Transformation _draw_chip('Source', rchip1, 9) _draw_chip('Homog', rchip1_Ht, 10) _draw_chip('Destination', rchip2, 11) _draw_chip('Homog Blend', rchip2_blendH, 12) df2.set_figtitle(figtitle)
def _show_res(hs, res, **kwargs): ''' Displays query chip, groundtruth matches, and top 5 matches''' #printDBG('[viz._show_res()] %s ' % helpers.printableVal(locals())) #printDBG = print in_image = hs.prefs.display_cfg.show_results_in_image annote = kwargs.pop('annote', 2) # this is toggled fnum = kwargs.get('fnum', 3) figtitle = kwargs.get('figtitle', '') topN_cxs = kwargs.get('topN_cxs', []) gt_cxs = kwargs.get('gt_cxs', []) all_kpts = kwargs.get('all_kpts', False) interact = kwargs.get('interact', True) show_query = kwargs.get('show_query', False) dosquare = kwargs.get('dosquare', False) if SHOW_QUERY_OVERRIDE is not None: show_query = SHOW_QUERY_OVERRIDE max_nCols = 5 if len(topN_cxs) in [6, 7]: max_nCols = 3 if len(topN_cxs) in [8]: max_nCols = 4 printDBG('========================') printDBG('[viz._show_res()]----------------') all_gts = hs.get_other_indexed_cxs(res.qcx) _tup = tuple(map(len, (topN_cxs, gt_cxs, all_gts))) printDBG('[viz._show_res()] #topN=%r #missed_gts=%r/%r' % _tup) printDBG('[viz._show_res()] * fnum=%r' % (fnum,)) printDBG('[viz._show_res()] * figtitle=%r' % (figtitle,)) printDBG('[viz._show_res()] * max_nCols=%r' % (max_nCols,)) printDBG('[viz._show_res()] * show_query=%r' % (show_query,)) ranked_cxs = res.topN_cxs(hs, N='all') # Build a subplot grid nQuerySubplts = 1 if show_query else 0 nGtSubplts = nQuerySubplts + (0 if gt_cxs is None else len(gt_cxs)) nTopNSubplts = 0 if topN_cxs is None else len(topN_cxs) nTopNCols = min(max_nCols, nTopNSubplts) nGTCols = min(max_nCols, nGtSubplts) nGTCols = max(nGTCols, nTopNCols) nTopNCols = nGTCols nGtRows = 0 if nGTCols == 0 else int(np.ceil(nGtSubplts / nGTCols)) nTopNRows = 0 if nTopNCols == 0 else int(np.ceil(nTopNSubplts / nTopNCols)) nGtCells = nGtRows * nGTCols nRows = nTopNRows + nGtRows # HACK: _color_list = df2.distinct_colors(len(topN_cxs)) cx2_color = {cx: _color_list[ox] for ox, cx in enumerate(topN_cxs)} if IN_IMAGE_OVERRIDE is not None: in_image = IN_IMAGE_OVERRIDE # Helpers def _show_query_fn(plotx_shift, rowcols): 'helper for viz._show_res' plotx = plotx_shift + 1 pnum = (rowcols[0], rowcols[1], plotx) #print('[viz] Plotting Query: pnum=%r' % (pnum,)) _kwshow = dict(draw_kpts=annote) _kwshow.update(kwargs) _kwshow['prefix'] = 'q' _kwshow['res'] = res _kwshow['pnum'] = pnum _kwshow['cx2_color'] = cx2_color _kwshow['draw_ell'] = annote >= 1 #_kwshow['in_image'] = in_image show_chip(hs, **_kwshow) #if in_image: #roi1 = hs.cx2_roi(res.qcx) #df2.draw_roi(roi1, bbox_color=df2.ORANGE, label='q' + hs.cidstr(res.qcx)) def _plot_matches_cxs(cx_list, plotx_shift, rowcols): def _show_matches_fn(cx, orank, pnum): 'Helper function for drawing matches to one cx' aug = 'rank=%r\n' % orank #printDBG('[viz._show_res()] plotting: %r' % (pnum,)) _kwshow = dict(draw_ell=annote, draw_pts=False, draw_lines=annote, ell_alpha=.5, all_kpts=all_kpts) _kwshow.update(kwargs) _kwshow['fnum'] = fnum _kwshow['pnum'] = pnum _kwshow['title_aug'] = aug # If we already are showing the query dont show it here if not show_query: _kwshow['draw_ell'] = annote == 1 _kwshow['draw_lines'] = annote >= 1 res_show_chipres(res, hs, cx, in_image=in_image, **_kwshow) else: _kwshow['draw_ell'] = annote >= 1 if annote == 2: # TODO Find a better name _kwshow['color'] = cx2_color[cx] _kwshow['sel_fx2'] = res.cx2_fm[cx][:, 1] show_chip(hs, cx, in_image=in_image, **_kwshow) annotate_chipres(hs, res, cx, in_image=in_image, show_query=not show_query) 'helper for viz._show_res to draw many cxs' #printDBG('[viz._show_res()] Plotting Chips %s:' % hs.cidstr(cx_list)) if cx_list is None: return for ox, cx in enumerate(cx_list): plotx = ox + plotx_shift + 1 pnum = (rowcols[0], rowcols[1], plotx) oranks = np.where(ranked_cxs == cx)[0] if len(oranks) == 0: orank = -1 continue orank = oranks[0] + 1 _show_matches_fn(cx, orank, pnum) if dosquare: # HACK nSubplots = nGtSubplts + nTopNSubplts nRows, nCols = get_square_row_cols(nSubplots, 3) nTopNCols = nGTCols = nCols shift_topN = 1 printDBG('nRows, nCols = (%r, %r)' % (nRows, nCols)) else: shift_topN = nGtCells if nGtSubplts == 1: nGTCols = 1 fig = df2.figure(fnum=fnum, pnum=(nRows, nGTCols, 1), docla=True, doclf=True) df2.disconnect_callback(fig, 'button_press_event') df2.plt.subplot(nRows, nGTCols, 1) # Plot Query if show_query: _show_query_fn(0, (nRows, nGTCols)) # Plot Ground Truth _plot_matches_cxs(gt_cxs, nQuerySubplts, (nRows, nGTCols)) _plot_matches_cxs(topN_cxs, shift_topN, (nRows, nTopNCols)) figtitle += ' q%s name=%s' % (hs.cidstr(res.qcx), hs.cx2_name(res.qcx)) df2.set_figtitle(figtitle, incanvas=not NO_LABEL_OVERRIDE) # Result Interaction if interact: printDBG('[viz._show_res()] starting interaction') def _ctrlclicked_cx(cx): printDBG('ctrl+clicked cx=%r' % cx) fnum = FNUMS['special'] fig = df2.figure(fnum=fnum, docla=True, doclf=True) df2.disconnect_callback(fig, 'button_press_event') viz_spatial_verification(hs, res.qcx, cx2=cx, fnum=fnum) fig.canvas.draw() df2.bring_to_front(fig) def _clicked_cx(cx): printDBG('clicked cx=%r' % cx) fnum = FNUMS['inspect'] res.interact_chipres(hs, cx, fnum=fnum) fig = df2.gcf() fig.canvas.draw() df2.bring_to_front(fig) def _clicked_none(): # Toggle if the click is not in any axis printDBG('clicked none') #print(kwargs) _show_res(hs, res, annote=(annote + 1) % 3, **kwargs) fig.canvas.draw() def _on_res_click(event): 'result interaction mpl event callback slot' print('[viz] clicked result') if event.xdata is None or event.inaxes is None: #print('clicked outside axes') return _clicked_none() ax = event.inaxes hs_viewtype = ax.__dict__.get('_hs_viewtype', '') printDBG(event.__dict__) printDBG('hs_viewtype=%r' % hs_viewtype) # Clicked a specific chipres if hs_viewtype.find('chipres') == 0: cx = ax.__dict__.get('_hs_cx') # Ctrl-Click key = '' if event.key is None else event.key print('key = %r' % key) if key.find('control') == 0: print('[viz] result control clicked') return _ctrlclicked_cx(cx) # Left-Click else: print('[viz] result clicked') return _clicked_cx(cx) df2.connect_callback(fig, 'button_press_event', _on_res_click) df2.adjust_subplots_safe() printDBG('[viz._show_res()] Finished') return fig
ax.add_collection(ellipse_collection) rchip_fpath = 'tpl/extern_feat/lena.png' rchip_fpath = 'tpl/extern_feat/zebra.jpg' rchip_fpath = os.path.realpath(rchip_fpath) rchip = cv2.cvtColor(cv2.imread(rchip_fpath, flags=cv2.IMREAD_COLOR), cv2.COLOR_BGR2RGB) outname = extern_feat.compute_perdoch_text_feats(rchip_fpath) #outname = compute_inria_text_feats(rchip_fpath, 'harris', 'sift') # Keep the wrong way to compare kpts0, desc = extern_feat.read_text_feat_file(outname) invE = extern_feat.expand_invET(kpts0[:,2:5].T)[0] kpts1 = extern_feat.fix_kpts_hack(kpts0[:], method=1) A1 = extern_feat.expand_acd(kpts1[:,2:5])[0] #kpts, desc = filter_kpts_scale(kpts, desc) df2.figure(1, doclf=True) df2.DARKEN = .5 #---- df2.imshow(rchip, plotnum=(2,3,1), title='0 before (inverse square root)') draw_kpts3(kpts0.copy(),0) #---- df2.imshow(rchip, plotnum=(2,3,2), title='1 just inverse') draw_kpts3(kpts1.copy(),1) #---- df2.imshow(rchip, plotnum=(2,3,3), title='2 identity') draw_kpts3(kpts1.copy(), 2) df2.update() #----
def viz_spatial_verification(hs, cx1, figtitle='Spatial Verification View', **kwargs): #kwargs = {} from hscom import helpers from hotspotter import spatial_verification2 as sv2 import cv2 print('\n======================') cx2 = ensure_cx2(hs, cx1, kwargs.pop('cx2', None)) print('[viz] viz_spatial_verification %s' % hs.vs_str(cx1, cx2)) fnum = kwargs.get('fnum', 4) fm = ensure_fm(hs, cx1, cx2, kwargs.pop('fm', None), kwargs.pop('res', 'db')) # Get keypoints rchip1 = kwargs['rchip1'] if 'rchip1' in kwargs else hs.get_chip(cx1) rchip2 = kwargs['rchip2'] if 'rchip1' in kwargs else hs.get_chip(cx2) kpts1 = kwargs['kpts1'] if 'kpts1' in kwargs else hs.get_kpts(cx1) kpts2 = kwargs['kpts2'] if 'kpts2' in kwargs else hs.get_kpts(cx2) dlen_sqrd2 = rchip2.shape[0] ** 2 + rchip2.shape[1] ** 2 # rchips are in shape = (height, width) (h1, w1) = rchip1.shape[0:2] (h2, w2) = rchip2.shape[0:2] #wh1 = (w1, h1) wh2 = (w2, h2) #print('[viz.sv] wh1 = %r' % (wh1,)) #print('[viz.sv] wh2 = %r' % (wh2,)) # Get affine and homog mapping from rchip1 to rchip2 xy_thresh = hs.prefs.query_cfg.sv_cfg.xy_thresh max_scale = hs.prefs.query_cfg.sv_cfg.scale_thresh_high min_scale = hs.prefs.query_cfg.sv_cfg.scale_thresh_low homog_args = [kpts1, kpts2, fm, xy_thresh, max_scale, min_scale, dlen_sqrd2, 4] try: Aff, aff_inliers = sv2.homography_inliers(*homog_args, just_affine=True) H, inliers = sv2.homography_inliers(*homog_args, just_affine=False) except Exception as ex: print('[viz] homog_args = %r' % (homog_args)) print('[viz] ex = %r' % (ex,)) raise print(helpers.horiz_string(['H = ', str(H)])) print(helpers.horiz_string(['Aff = ', str(Aff)])) # Transform the chips print('warp homog') rchip1_Ht = cv2.warpPerspective(rchip1, H, wh2) print('warp affine') rchip1_At = cv2.warpAffine(rchip1, Aff[0:2, :], wh2) rchip2_blendA = np.zeros(rchip2.shape, dtype=rchip2.dtype) rchip2_blendH = np.zeros(rchip2.shape, dtype=rchip2.dtype) rchip2_blendA = rchip2 / 2 + rchip1_At / 2 rchip2_blendH = rchip2 / 2 + rchip1_Ht / 2 df2.figure(fnum=fnum, pnum=(3, 4, 1), docla=True, doclf=True) def _draw_chip(title, chip, px, *args, **kwargs): df2.imshow(chip, *args, title=title, fnum=fnum, pnum=(3, 4, px), **kwargs) # Draw original matches, affine inliers, and homography inliers def _draw_matches(title, fm, px): # Helper with common arguments to df2.show_chipmatch2 dmkwargs = dict(fs=None, title=title, all_kpts=False, draw_lines=True, docla=True, fnum=fnum, pnum=(3, 3, px)) df2.show_chipmatch2(rchip1, rchip2, kpts1, kpts2, fm, show_nMatches=True, **dmkwargs) # Draw the Assigned -> Affine -> Homography matches _draw_matches('Assigned matches', fm, 1) _draw_matches('Affine inliers', fm[aff_inliers], 2) _draw_matches('Homography inliers', fm[inliers], 3) # Draw the Affine Transformations _draw_chip('Source', rchip1, 5) _draw_chip('Affine', rchip1_At, 6) _draw_chip('Destination', rchip2, 7) _draw_chip('Aff Blend', rchip2_blendA, 8) # Draw the Homography Transformation _draw_chip('Source', rchip1, 9) _draw_chip('Homog', rchip1_Ht, 10) _draw_chip('Destination', rchip2, 11) _draw_chip('Homog Blend', rchip2_blendH, 12) df2.set_figtitle(figtitle)
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 _plot(data, px, title=''): df2.figure(9003, docla=True, pnum=(2, 4, px)) df2.plot2(data.T[0], data.T[1], '.', title)
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 _viz_keypoints(fnum, pnum=(1, 1, 1), **kwargs): df2.figure(fnum=fnum, docla=True, doclf=True) viz.show_keypoints(rchip, kpts, fnum=fnum, pnum=pnum, **kwargs) if figtitle is not None: df2.set_figtitle(figtitle)
def _show_res(hs, res, **kwargs): ''' Displays query chip, groundtruth matches, and top 5 matches''' #printDBG('[viz._show_res()] %s ' % helpers.printableVal(locals())) #printDBG = print in_image = hs.prefs.display_cfg.show_results_in_image annote = kwargs.pop('annote', 2) # this is toggled fnum = kwargs.get('fnum', 3) figtitle = kwargs.get('figtitle', '') topN_cxs = kwargs.get('topN_cxs', []) gt_cxs = kwargs.get('gt_cxs', []) all_kpts = kwargs.get('all_kpts', False) interact = kwargs.get('interact', True) show_query = kwargs.get('show_query', False) dosquare = kwargs.get('dosquare', False) if SHOW_QUERY_OVERRIDE is not None: show_query = SHOW_QUERY_OVERRIDE max_nCols = 5 if len(topN_cxs) in [6, 7]: max_nCols = 3 if len(topN_cxs) in [8]: max_nCols = 4 printDBG('========================') printDBG('[viz._show_res()]----------------') all_gts = hs.get_other_indexed_cxs(res.qcx) _tup = tuple(map(len, (topN_cxs, gt_cxs, all_gts))) printDBG('[viz._show_res()] #topN=%r #missed_gts=%r/%r' % _tup) printDBG('[viz._show_res()] * fnum=%r' % (fnum, )) printDBG('[viz._show_res()] * figtitle=%r' % (figtitle, )) printDBG('[viz._show_res()] * max_nCols=%r' % (max_nCols, )) printDBG('[viz._show_res()] * show_query=%r' % (show_query, )) ranked_cxs = res.topN_cxs(hs, N='all') # Build a subplot grid nQuerySubplts = 1 if show_query else 0 nGtSubplts = nQuerySubplts + (0 if gt_cxs is None else len(gt_cxs)) nTopNSubplts = 0 if topN_cxs is None else len(topN_cxs) nTopNCols = min(max_nCols, nTopNSubplts) nGTCols = min(max_nCols, nGtSubplts) nGTCols = max(nGTCols, nTopNCols) nTopNCols = nGTCols nGtRows = 0 if nGTCols == 0 else int(np.ceil(nGtSubplts / nGTCols)) nTopNRows = 0 if nTopNCols == 0 else int(np.ceil(nTopNSubplts / nTopNCols)) nGtCells = nGtRows * nGTCols nRows = nTopNRows + nGtRows # HACK: _color_list = df2.distinct_colors(len(topN_cxs)) cx2_color = {cx: _color_list[ox] for ox, cx in enumerate(topN_cxs)} if IN_IMAGE_OVERRIDE is not None: in_image = IN_IMAGE_OVERRIDE # Helpers def _show_query_fn(plotx_shift, rowcols): 'helper for viz._show_res' plotx = plotx_shift + 1 pnum = (rowcols[0], rowcols[1], plotx) #print('[viz] Plotting Query: pnum=%r' % (pnum,)) _kwshow = dict(draw_kpts=annote) _kwshow.update(kwargs) _kwshow['prefix'] = 'q' _kwshow['res'] = res _kwshow['pnum'] = pnum _kwshow['cx2_color'] = cx2_color _kwshow['draw_ell'] = annote >= 1 #_kwshow['in_image'] = in_image show_chip(hs, **_kwshow) #if in_image: #roi1 = hs.cx2_roi(res.qcx) #df2.draw_roi(roi1, bbox_color=df2.ORANGE, label='q' + hs.cidstr(res.qcx)) def _plot_matches_cxs(cx_list, plotx_shift, rowcols): def _show_matches_fn(cx, orank, pnum): 'Helper function for drawing matches to one cx' aug = 'rank=%r\n' % orank #printDBG('[viz._show_res()] plotting: %r' % (pnum,)) _kwshow = dict(draw_ell=annote, draw_pts=False, draw_lines=annote, ell_alpha=.5, all_kpts=all_kpts) _kwshow.update(kwargs) _kwshow['fnum'] = fnum _kwshow['pnum'] = pnum _kwshow['title_aug'] = aug # If we already are showing the query dont show it here if not show_query: _kwshow['draw_ell'] = annote == 1 _kwshow['draw_lines'] = annote >= 1 res_show_chipres(res, hs, cx, in_image=in_image, **_kwshow) else: _kwshow['draw_ell'] = annote >= 1 if annote == 2: # TODO Find a better name _kwshow['color'] = cx2_color[cx] _kwshow['sel_fx2'] = res.cx2_fm[cx][:, 1] show_chip(hs, cx, in_image=in_image, **_kwshow) annotate_chipres(hs, res, cx, in_image=in_image, show_query=not show_query) 'helper for viz._show_res to draw many cxs' #printDBG('[viz._show_res()] Plotting Chips %s:' % hs.cidstr(cx_list)) if cx_list is None: return for ox, cx in enumerate(cx_list): plotx = ox + plotx_shift + 1 pnum = (rowcols[0], rowcols[1], plotx) oranks = np.where(ranked_cxs == cx)[0] if len(oranks) == 0: orank = -1 continue orank = oranks[0] + 1 _show_matches_fn(cx, orank, pnum) if dosquare: # HACK nSubplots = nGtSubplts + nTopNSubplts nRows, nCols = get_square_row_cols(nSubplots, 3) nTopNCols = nGTCols = nCols shift_topN = 1 printDBG('nRows, nCols = (%r, %r)' % (nRows, nCols)) else: shift_topN = nGtCells if nGtSubplts == 1: nGTCols = 1 fig = df2.figure(fnum=fnum, pnum=(nRows, nGTCols, 1), docla=True, doclf=True) df2.disconnect_callback(fig, 'button_press_event') df2.plt.subplot(nRows, nGTCols, 1) # Plot Query if show_query: _show_query_fn(0, (nRows, nGTCols)) # Plot Ground Truth _plot_matches_cxs(gt_cxs, nQuerySubplts, (nRows, nGTCols)) _plot_matches_cxs(topN_cxs, shift_topN, (nRows, nTopNCols)) figtitle += ' q%s name=%s' % (hs.cidstr(res.qcx), hs.cx2_name(res.qcx)) df2.set_figtitle(figtitle, incanvas=not NO_LABEL_OVERRIDE) # Result Interaction if interact: printDBG('[viz._show_res()] starting interaction') def _ctrlclicked_cx(cx): printDBG('ctrl+clicked cx=%r' % cx) fnum = FNUMS['special'] fig = df2.figure(fnum=fnum, docla=True, doclf=True) df2.disconnect_callback(fig, 'button_press_event') viz_spatial_verification(hs, res.qcx, cx2=cx, fnum=fnum) fig.canvas.draw() df2.bring_to_front(fig) def _clicked_cx(cx): printDBG('clicked cx=%r' % cx) fnum = FNUMS['inspect'] res.interact_chipres(hs, cx, fnum=fnum) fig = df2.gcf() fig.canvas.draw() df2.bring_to_front(fig) def _clicked_none(): # Toggle if the click is not in any axis printDBG('clicked none') #print(kwargs) _show_res(hs, res, annote=(annote + 1) % 3, **kwargs) fig.canvas.draw() def _on_res_click(event): 'result interaction mpl event callback slot' print('[viz] clicked result') if event.xdata is None or event.inaxes is None: #print('clicked outside axes') return _clicked_none() ax = event.inaxes hs_viewtype = ax.__dict__.get('_hs_viewtype', '') printDBG(event.__dict__) printDBG('hs_viewtype=%r' % hs_viewtype) # Clicked a specific chipres if hs_viewtype.find('chipres') == 0: cx = ax.__dict__.get('_hs_cx') # Ctrl-Click key = '' if event.key is None else event.key print('key = %r' % key) if key.find('control') == 0: print('[viz] result control clicked') return _ctrlclicked_cx(cx) # Left-Click else: print('[viz] result clicked') return _clicked_cx(cx) df2.connect_callback(fig, 'button_press_event', _on_res_click) df2.adjust_subplots_safe() printDBG('[viz._show_res()] Finished') return fig
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 get_kp_border(rchip, kp): np.set_printoptions(precision=8) df2.reset() df2.figure(9003, docla=True, doclf=True) 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='') 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 are given the keypoint in invA format (x, y, ia11, ia21, ia22), ia12 = kp, 0 # invA2x2 is a transformation from points on a unit circle to the ellipse invA2x2 = np.array([[ia11, ia12], [ia21, ia22]]) #----------------------- # DRAWING #----------------------- # Lets start off by drawing the ellipse that we are goign to work with # Create unit circle sample tau = 2 * np.pi theta_list = np.linspace(0, tau, 1000) cicrle_pts = np.array([(np.cos(t), np.sin(t)) for t in theta_list]) ellipse_pts = invA2x2.dot(cicrle_pts.T).T _plotpts(ellipse_pts, 0, df2.BLACK, label='invA2x2.dot(unit_circle)') l1, l2, v1, v2 = _2x2_eig(invA2x2) dx1, dy1 = (v1 * l1) dx2, dy2 = (v2 * l2) _plotarrow(0, 0, dx1, dy1, color=df2.ORANGE, label='invA2x2 e1') _plotarrow(0, 0, dx2, dy2, color=df2.RED, label='invA2x2 e2') #----------------------- # REPRESENTATION #----------------------- # A2x2 is a transformation from points on the ellipse to a unit circle A2x2 = np.linalg.inv(invA2x2) # Points on a matrix satisfy (x).T.dot(E2x2).dot(x) = 1 E2x2 = A2x2.T.dot(A2x2) #Lets check our assertion: (x).T.dot(E2x2).dot(x) = 1 checks = [pt.T.dot(E2x2).dot(pt) for pt in ellipse_pts] assert all([abs(1 - check) < 1E-11 for check in checks]) #----------------------- # CONIC SECTIONS #----------------------- # 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 # The matrix representation of a conic is: ((A, B, B_, C), (D, E, F)) = (E2x2.flatten(), (0, 0, 1)) assert B == B_, 'matrix should by symmetric' # 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))) assert np.linalg.det(A_Q) != 0, 'degenerate conic' # As long as det(A_Q) is not 0 it is not degenerate and we can work with the # minor 2x2 matrix A_33 = np.array(((A, B / 2), (B / 2, C))) # (det == 0)->parabola, (det < 0)->hyperbola, (det > 0)->ellipse assert np.linalg.det(A_33) > 0, 'conic is not an ellipse' # 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) #================= # DRAWING #================= # Now we are going to determine the major and minor axis # of this beast. It just the center augmented by the eigenvecs l1, l2, v1, v2 = _2x2_eig(A_33) dx1, dy1 = 0 - (v1 / np.sqrt(l1)) dx2, dy2 = 0 - (v2 / np.sqrt(l2)) _plotarrow(0, 0, dx1, dy1, color=df2.BLUE) _plotarrow(0, 0, dx2, dy2, color=df2.BLUE) # The angle between the major axis and our x axis is: x_axis = np.array([1, 0]) theta = np.arccos(x_axis.dot(evec1)) # 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 # Algebraic form of connic #assert (a * (x ** 2)) + (b * (x * y)) + (c * (y ** 2)) + (d * x) + (e * y) + (f) == 0 #--------------------- invA = np.array([[a, 0], [c, d]]) Ashape = np.linalg.inv(np.array([[a, 0], [c, d]])) Ashape /= np.sqrt(np.linalg.det(Ashape)) tau = 2 * np.pi nSamples = 100 theta_list = np.linspace(0, tau, nSamples) # Create unit circle sample cicrle_pts = np.array([(np.cos(t), np.sin(t)) for t in theta_list]) circle_hpts = np.hstack([cicrle_pts, np.ones((len(cicrle_pts), 1))]) # Transform as if the unit cirle was the warped patch ashape_pts = Ashape.dot(cicrle_pts.T).T inv = np.linalg.inv svd = np.linalg.svd U, S_, V = svd(Ashape) S = np.diag(S_) pxl_list3 = invA.dot(cicrle_pts[:, 0:2].T).T pxl_list4 = invA.dot(ashape_pts[:, 0:2].T).T pxl_list5 = invA.T.dot(cicrle_pts[:, 0:2].T).T pxl_list6 = invA.T.dot(ashape_pts[:, 0:2].T).T pxl_list7 = inv(V).dot(ashape_pts[:, 0:2].T).T pxl_list8 = inv(U).dot(ashape_pts[:, 0:2].T).T df2.draw() def _plot(data, px, title=''): df2.figure(9003, docla=True, pnum=(2, 4, px)) df2.plot2(data.T[0], data.T[1], '.', title) df2.figure(9003, doclf=True) _plot(cicrle_pts, 1, 'unit circle') _plot(ashape_pts, 2, 'A => circle shape') _plot(pxl_list3, 3) _plot(pxl_list4, 4) _plot(pxl_list5, 5) _plot(pxl_list6, 6) _plot(pxl_list7, 7) _plot(pxl_list8, 8) df2.draw() invA = np.array([[a, 0, x], [c, d, y], [0, 0, 1]]) pxl_list = invA.dot(circle_hpts.T).T[:, 0:2] df2.figure(9002, doclf=True) df2.imshow(rchip) df2.plot2(pxl_list.T[0], pxl_list.T[1], '.') df2.draw() vals = [cv2.getRectSubPix(rchip, (1, 1), tuple(pxl)) for pxl in pxl_list] return vals
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 _sv_view(cx): fnum = viz.FNUMS['special'] fig = df2.figure(fnum=fnum, docla=True, doclf=True) df2.disconnect_callback(fig, 'button_press_event') viz.viz_spatial_verification(hs, res.qcx, cx2=cx, fnum=fnum) viz.draw()
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) #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) 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 orgkey in orgtype_list: for distkey in disttype_list: print(((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) #ax = df2.gca() #ax.set_title(title) 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 _chip_view(pnum=(1, 1, 1), **kwargs): df2.figure(fnum=fnum, pnum=pnum, docla=True, doclf=True) # Toggle no keypoints view viz.show_chip(hs, cx=cx, rchip=rchip, fnum=fnum, pnum=pnum, **kwargs) df2.set_figtitle(figtitle)
def get_kp_border(rchip, kp): np.set_printoptions(precision=8) df2.reset() df2.figure(9003, docla=True, doclf=True) 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='') 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 are given the keypoint in invA format (x, y, ia11, ia21, ia22), ia12 = kp, 0 # invA2x2 is a transformation from points on a unit circle to the ellipse invA2x2 = np.array([[ia11, ia12], [ia21, ia22]]) #----------------------- # DRAWING #----------------------- # Lets start off by drawing the ellipse that we are goign to work with # Create unit circle sample tau = 2 * np.pi theta_list = np.linspace(0, tau, 1000) cicrle_pts = np.array([(np.cos(t), np.sin(t)) for t in theta_list]) ellipse_pts = invA2x2.dot(cicrle_pts.T).T _plotpts(ellipse_pts, 0, df2.BLACK, label='invA2x2.dot(unit_circle)') l1, l2, v1, v2 = _2x2_eig(invA2x2) dx1, dy1 = (v1 * l1) dx2, dy2 = (v2 * l2) _plotarrow(0, 0, dx1, dy1, color=df2.ORANGE, label='invA2x2 e1') _plotarrow(0, 0, dx2, dy2, color=df2.RED, label='invA2x2 e2') #----------------------- # REPRESENTATION #----------------------- # A2x2 is a transformation from points on the ellipse to a unit circle A2x2 = np.linalg.inv(invA2x2) # Points on a matrix satisfy (x).T.dot(E2x2).dot(x) = 1 E2x2 = A2x2.T.dot(A2x2) #Lets check our assertion: (x).T.dot(E2x2).dot(x) = 1 checks = [pt.T.dot(E2x2).dot(pt) for pt in ellipse_pts] assert all([abs(1 - check) < 1E-11 for check in checks]) #----------------------- # CONIC SECTIONS #----------------------- # 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 # The matrix representation of a conic is: ((A, B, B_, C), (D, E, F)) = (E2x2.flatten(), (0, 0, 1)) assert B == B_, 'matrix should by symmetric' # 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))) assert np.linalg.det(A_Q) != 0, 'degenerate conic' # As long as det(A_Q) is not 0 it is not degenerate and we can work with the # minor 2x2 matrix A_33 = np.array((( A, B / 2), (B / 2, C))) # (det == 0)->parabola, (det < 0)->hyperbola, (det > 0)->ellipse assert np.linalg.det(A_33) > 0, 'conic is not an ellipse' # 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) #================= # DRAWING #================= # Now we are going to determine the major and minor axis # of this beast. It just the center augmented by the eigenvecs l1, l2, v1, v2 = _2x2_eig(A_33) dx1, dy1 = 0 - (v1 / np.sqrt(l1)) dx2, dy2 = 0 - (v2 / np.sqrt(l2)) _plotarrow(0, 0, dx1, dy1, color=df2.BLUE) _plotarrow(0, 0, dx2, dy2, color=df2.BLUE) # The angle between the major axis and our x axis is: x_axis = np.array([1, 0]) theta = np.arccos(x_axis.dot(evec1)) # 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 # Algebraic form of connic #assert (a * (x ** 2)) + (b * (x * y)) + (c * (y ** 2)) + (d * x) + (e * y) + (f) == 0 #--------------------- invA = np.array([[a, 0], [c, d]]) Ashape = np.linalg.inv(np.array([[a, 0], [c, d]])) Ashape /= np.sqrt(np.linalg.det(Ashape)) tau = 2 * np.pi nSamples = 100 theta_list = np.linspace(0, tau, nSamples) # Create unit circle sample cicrle_pts = np.array([(np.cos(t), np.sin(t)) for t in theta_list]) circle_hpts = np.hstack([cicrle_pts, np.ones((len(cicrle_pts), 1))]) # Transform as if the unit cirle was the warped patch ashape_pts = Ashape.dot(cicrle_pts.T).T inv = np.linalg.inv svd = np.linalg.svd U, S_, V = svd(Ashape) S = np.diag(S_) pxl_list3 = invA.dot(cicrle_pts[:, 0:2].T).T pxl_list4 = invA.dot(ashape_pts[:, 0:2].T).T pxl_list5 = invA.T.dot(cicrle_pts[:, 0:2].T).T pxl_list6 = invA.T.dot(ashape_pts[:, 0:2].T).T pxl_list7 = inv(V).dot(ashape_pts[:, 0:2].T).T pxl_list8 = inv(U).dot(ashape_pts[:, 0:2].T).T df2.draw() def _plot(data, px, title=''): df2.figure(9003, docla=True, pnum=(2, 4, px)) df2.plot2(data.T[0], data.T[1], '.', title) df2.figure(9003, doclf=True) _plot(cicrle_pts, 1, 'unit circle') _plot(ashape_pts, 2, 'A => circle shape') _plot(pxl_list3, 3) _plot(pxl_list4, 4) _plot(pxl_list5, 5) _plot(pxl_list6, 6) _plot(pxl_list7, 7) _plot(pxl_list8, 8) df2.draw() invA = np.array([[a, 0, x], [c, d, y], [0, 0, 1]]) pxl_list = invA.dot(circle_hpts.T).T[:, 0:2] df2.figure(9002, doclf=True) df2.imshow(rchip) df2.plot2(pxl_list.T[0], pxl_list.T[1], '.') df2.draw() vals = [cv2.getRectSubPix(rchip, (1, 1), tuple(pxl)) for pxl in pxl_list] return vals