Source code for vtool.coverage_grid

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
from six.moves import zip, range, map  # NOQA
import numpy as np
import utool as ut
import ubelt as ub
from vtool import coverage_kpts


# TODO: integrate more
COVGRID_DEFAULT = ut.ParamInfoList(
    'coverage_grid',
    [
        ut.ParamInfo('pxl_per_bin', 10, 'ppb', varyvals=[20, 5, 1]),
        ut.ParamInfo('grid_steps', 3, 'stps', varyvals=[1, 3, 7]),
        ut.ParamInfo('grid_sigma', 1.6, 'sigma', varyvals=[1.0, 1.6]),
    ],
)


[docs]def make_grid_coverage_mask( kpts, chipsize, weights, pxl_per_bin=4, grid_steps=1, resize=False, out=None, grid_sigma=1.6, ): r""" Args: kpts (ndarray[float32_t, ndim=2]): keypoint chipsize (tuple): width, height weights (ndarray[float32_t, ndim=1]): pxl_per_bin (float): grid_steps (int): Returns: ndarray: weightgrid CommandLine: python -m vtool.coverage_grid --test-make_grid_coverage_mask --show Example: >>> # DISABLE_DOCTEST >>> from vtool.coverage_grid import * # NOQA >>> import vtool as vt >>> # build test data >>> kpts, chipsize, weights = coverage_kpts.testdata_coverage('easy1.png') >>> pxl_per_bin = 4 >>> grid_steps = 2 >>> # execute function >>> weightgrid = make_grid_coverage_mask(kpts, chipsize, weights, pxl_per_bin, grid_steps) >>> # verify result >>> result = str(weightgrid) >>> print(result) >>> # xdoctest: +REQUIRES(--show) >>> import wbia.plottool as pt >>> pt.imshow(weightgrid) >>> ut.show_if_requested() """ import vtool as vt import cv2 coverage_gridtup = sparse_grid_coverage( kpts, chipsize, weights, pxl_per_bin=pxl_per_bin, grid_steps=grid_steps, grid_sigma=grid_sigma, ) gridshape = coverage_gridtup[0:2] neighbor_bin_weights, neighbor_bin_indices = coverage_gridtup[-2:] oldshape_indices = neighbor_bin_indices.shape newshape_indices = (np.prod(oldshape_indices[0:2]), oldshape_indices[2]) neighbor_bin_indices = neighbor_bin_indices.reshape(newshape_indices).T neighbor_bin_weights = neighbor_bin_weights.flatten() # Get flat indexing into gridbin neighbor_bin_flat_indices = np.ravel_multi_index(neighbor_bin_indices, gridshape) # Group by bins with weight unique_flatxs, grouped_flatxs = vt.group_indices(neighbor_bin_flat_indices) grouped_weights = vt.apply_grouping(neighbor_bin_weights, grouped_flatxs) # FIXME: boundary cases are not handled right because their vote is split # into the same bin and is fighting with itself durring the max max_weights = list(map(np.max, grouped_weights)) if out is None: weightgrid = np.zeros(gridshape) else: # outvar specified weightgrid = out weightgrid[:] = 0 unique_rows, unique_cols = np.unravel_index(unique_flatxs, gridshape) weightgrid[unique_rows, unique_cols] = max_weights # flat_weightgrid = np.zeros(np.prod(gridshape)) # flat_weightgrid[unique_flatxs] = max_weight # ut.embed() # weightgrid = np.reshape(flat_weightgrid, gridshape) if resize: weightgrid = cv2.resize(weightgrid, chipsize, interpolation=cv2.INTER_NEAREST) return weightgrid
[docs]def get_subbin_xy_neighbors(subbin_index00, grid_steps, num_cols, num_rows): """Generate all neighbor of a bin subbin_index00 = left and up subbin index """ subbin_index00 = np.floor(subbin_index00).astype(np.int32) subbin_x0, subbin_y0 = subbin_index00 step_list = np.arange(1 - grid_steps, grid_steps + 1) offset_list = [ # broadcast to the shape we will add too np.array([xoff, yoff])[:, None] for xoff, yoff in list(ut.iprod(step_list, step_list)) ] neighbor_subbin_index_list = [ np.add(subbin_index00, offset) for offset in offset_list ] # Concatenate all subbin indexes into one array for faster vectorized op neighbor_bin_indices = np.dstack(neighbor_subbin_index_list).T # Clip with no wrapparound min_val = np.array([0, 0]) max_val = np.array([num_cols - 1, num_rows - 1]) np.clip( neighbor_bin_indices, min_val[None, None, :], max_val[None, None, :], out=neighbor_bin_indices, ) return neighbor_bin_indices
[docs]def compute_subbin_to_bins_dist(neighbor_bin_centers, subbin_xy_arr): _tmp = np.subtract(neighbor_bin_centers, subbin_xy_arr.T[None, :]) neighbor_subbin_sqrddist_arr = np.power(_tmp, 2, out=_tmp).sum(axis=2) return neighbor_subbin_sqrddist_arr
[docs]def weighted_gaussian_falloff(neighbor_subbin_sqrddist_arr, weights, grid_sigma): import vtool as vt _gaussweights = vt.gauss_func1d_unnormalized(neighbor_subbin_sqrddist_arr, grid_sigma) # If uncommented next line ensure each column sums to 1 # np.divide(_gaussweights, _gaussweights.sum(axis=0)[None, :], out=_gaussweights) # Scale initial weights by the gaussian falloff neighbor_bin_weights = np.multiply(_gaussweights, weights[None, :]) return neighbor_bin_weights
[docs]def sparse_grid_coverage( kpts, chipsize, weights, pxl_per_bin=0.3, grid_steps=1, grid_sigma=1.6 ): r""" Args: kpts (ndarray[float32_t, ndim=2]): keypoint chipsize (tuple): weights (ndarray): CommandLine: python -m vtool.coverage_grid --test-sparse_grid_coverage --show Example: >>> # DISABLE_DOCTEST >>> from vtool.coverage_grid import * # NOQA >>> kpts, chipsize, weights = coverage_kpts.testdata_coverage() >>> chipsize = (chipsize[0] + 50, chipsize[1]) >>> pxl_per_bin = 3 >>> grid_steps = 2 >>> grid_sigma = 1.6 >>> coverage_gridtup = sparse_grid_coverage(kpts, chipsize, weights, pxl_per_bin, grid_steps, grid_sigma) >>> # xdoctest: +REQUIRES(--show) >>> import wbia.plottool as pt >>> show_coverage_grid(*coverage_gridtup) >>> pt.show_if_requested() """ import vtool as vt # Compute grid size and stride chip_w, chip_h = chipsize # find enough rows to fit pxl_per_bin pixels into a grid dimension num_rows = max(vt.iround(chip_h / pxl_per_bin), 1) num_cols = max(vt.iround(chip_w / pxl_per_bin), 1) # stride is roughly equal in each direction, depending on rounding errors chipstride = np.array((chip_w / num_cols, chip_h / num_rows)) # Find keypoint subbin locations relative to edge xy_arr = vt.get_xys(kpts) subbin_xy_arr = np.divide(xy_arr, chipstride[:, None]) # Find subbin locations relative to center frac_subbin_index = np.subtract(subbin_xy_arr, 0.5) neighbor_bin_xy_indices = get_subbin_xy_neighbors( frac_subbin_index, grid_steps, num_cols, num_rows ) # Find center neighbor_bin_centers = np.add(neighbor_bin_xy_indices, 0.5) # compute distance to neighbor neighbor_subbin_sqrddist_arr = compute_subbin_to_bins_dist( neighbor_bin_centers, subbin_xy_arr ) # scale weights using guassia falloff neighbor_bin_weights = weighted_gaussian_falloff( neighbor_subbin_sqrddist_arr, weights, grid_sigma ) # convert to rowcol neighbor_bin_indices = neighbor_bin_xy_indices[:, :, ::-1] # NOQA coverage_gridtup = ( num_rows, num_cols, subbin_xy_arr, neighbor_bin_centers, neighbor_bin_weights, neighbor_bin_indices, ) return coverage_gridtup
# VISUALIZATION FUNCS
[docs]def show_coverage_grid( num_rows, num_cols, subbin_xy_arr, neighbor_bin_centers, neighbor_bin_weights, neighbor_bin_indices, fnum=None, pnum=None, ): """ visualizes the voting scheme on the grid. (not a mask, and no max) """ import wbia.plottool as pt import vtool as vt import matplotlib as mpl if fnum is None: fnum = pt.next_fnum() fig = pt.figure(fnum, pnum=pnum) ax = fig.gca() x_edge_indices = np.arange(num_cols) y_edge_indices = np.arange(num_rows) x_center_indices = vt.hist_edges_to_centers(x_edge_indices) y_center_indices = vt.hist_edges_to_centers(y_edge_indices) x_center_grid, y_center_grid = np.meshgrid(x_center_indices, y_center_indices) ax.set_xticks(x_edge_indices) ax.set_yticks(y_edge_indices) # Plot keypoint loc ax.scatter(subbin_xy_arr[0], subbin_xy_arr[1], marker='o') # Plot Weighted Lines to Subbin pt_colors = pt.distinct_colors(len(subbin_xy_arr.T)) segment_list = [] color_list = [] for subbin_centers, subbin_weights in zip(neighbor_bin_centers, neighbor_bin_weights): for pt_xys, center_xys, weight, color in zip( subbin_xy_arr.T, subbin_centers, subbin_weights, pt_colors ): # Adjsut weight to alpha for easier visualization alpha = weight INCRESE_ALPHA_VISIBILITY = True if INCRESE_ALPHA_VISIBILITY: min_viz_alpha = 0.05 alpha = alpha * (1.0 - min_viz_alpha) + min_viz_alpha alpha **= 1.0 # pt.plots.colorline( segment = np.vstack((pt_xys, center_xys)) segment_list.append(segment) # Alpha becomes part of the colors color_list.append(list(color) + [alpha]) # DO NOT USE PLOT VERY SLOW # ax.plot(*segment.T, color=color, alpha=alpha, lw=3) ax = pt.gca() # Plot all segments in single line collection for speed # solid | dashed | dashdot | dotted lc = mpl.collections.LineCollection( segment_list, colors=color_list, linewidth=3, linestyles='solid' ) ax.add_collection(lc) # Plot Grid Center num_cells = num_cols * num_rows grid_alpha = min(0.4, max(1 - (num_cells / 500), 0.1)) grid_color = [0.6, 0.6, 0.6, grid_alpha] # print(grid_color) # Plot grid cetner ax.scatter(x_center_grid, y_center_grid, marker='.', color=grid_color, s=grid_alpha) ax.set_xlim(0, num_cols - 1) ax.set_ylim(0, num_rows - 1) # ----- pt.dark_background() ax.grid(True, color=[0.3, 0.3, 0.3]) ax.set_xticklabels([]) ax.set_yticklabels([])
# TESTING FUNCS
[docs]def get_coverage_grid_gridsearch_configs(): # varied_dict = { # 'pxl_per_bin': [.05, .3, 1.0], # 'grid_steps': [1, 3, 7], # 'grid_sigma': [1.0, 1.6], # } # slice_dict = { # 'pxl_per_bin' : slice(0, 3), # 'grid_steps' : slice(0, 3), # 'grid_sigma' : slice(0, 3), # } cfgdict_list, cfglbl_list = COVGRID_DEFAULT.get_gridsearch_input() # Make configuration for every parameter setting # cfgdict_list, cfglbl_list = ut.make_constrained_cfg_and_lbl_list(varied_dict, slice_dict=slice_dict) return cfgdict_list, cfglbl_list
[docs]def gridsearch_coverage_grid(): """ CommandLine: python -m vtool.coverage_grid --test-gridsearch_coverage_grid --show Example: >>> # DISABLE_DOCTEST >>> from vtool.coverage_grid import * # NOQA >>> import wbia.plottool as pt >>> gridsearch_coverage_grid() >>> pt.show_if_requested() """ import wbia.plottool as pt fname = None # 'easy1.png' kpts, chipsize, weights = coverage_kpts.testdata_coverage(fname) if len(kpts) > 100: kpts = kpts[::100] weights = weights[::100] cfgdict_list, cfglbl_list = get_coverage_grid_gridsearch_configs() coverage_gridtup_list = [ sparse_grid_coverage(kpts, chipsize, weights, **cfgdict) for cfgdict in ub.ProgIter(cfgdict_list, desc='coverage grid') ] fnum = 1 with ub.Timer('plotting gridsearch'): ut.interact_gridsearch_result_images( show_coverage_grid, cfgdict_list, cfglbl_list, coverage_gridtup_list, fnum=fnum, figtitle='coverage grid', unpack=True, max_plots=25, ) pt.iup()
[docs]def gridsearch_coverage_grid_mask(): """ CommandLine: python -m vtool.coverage_grid --test-gridsearch_coverage_grid_mask --show Example: >>> # DISABLE_DOCTEST >>> from vtool.coverage_grid import * # NOQA >>> import wbia.plottool as pt >>> gridsearch_coverage_grid_mask() >>> pt.show_if_requested() """ import wbia.plottool as pt cfgdict_list, cfglbl_list = get_coverage_grid_gridsearch_configs() kpts, chipsize, weights = coverage_kpts.testdata_coverage('easy1.png') gridmask_list = [ 255 * make_grid_coverage_mask(kpts, chipsize, weights, **cfgdict) for cfgdict in ub.ProgIter(cfgdict_list, desc='coverage grid') ] NORMHACK = False if NORMHACK: gridmask_list = [255 * (gridmask / gridmask.max()) for gridmask in gridmask_list] fnum = 1 ut.interact_gridsearch_result_images( pt.imshow, cfgdict_list, cfglbl_list, gridmask_list, fnum=fnum, figtitle='coverage grid', unpack=False, max_plots=25, ) pt.iup()
# pt.show_if_requested() if __name__ == '__main__': """ CommandLine: xdoctest -m vtool.coverage_grid """ import xdoctest xdoctest.doctest_module(__file__)