def show_transform_quantiles(img, transform, fraction=1.0, area_mask=None, ax=None): """ Show a plot of the quantiles of the transform coefficients. The `fraction` of `transform` coefficients holding the most energy for the image `img` is considered. The four quantiles within this fraction of coefficients are illustrated in the `transform` domain by showing coefficients between the different quantiles in different colours. If an `area_mask` is specified, only this area in the plot is higlighted whereas the rest is darkened. Parameters ---------- img : ndarray The image to show the transform quantiles for. transform : str The transform to use. fraction : float The fraction of coefficients used in the quantiles calculation (the default value is 1.0, which implies that all coefficients are used). area_mask : ndarray Bool array of the same shape as `img` which indicates the area of the image to highlight (the default value is None, which implies that no particular part of the image is highlighted). ax : matplotlib.axes.Axes The axes on which the image is displayed (the default is None, which implies that a separate figure is created). Returns ------- coef_count : dict Different counts of coeffcients within the `area_mask` (only returned if `area_mask` is not None). Notes ----- The ticks on the colorbar shown below the figure are the percentiles of the entire set of coefficients corresponding to the quantiles with fraction of coefficients. For instance, if fraction is 0.10, then the percentiles are 92.5, 95.0, 97.5, 100.0, corresponding to the four quantiles within the 10 percent coefficients holding the most energy. The `coef_count` dictionary holds the following keys: * C_total : Total number of considered coefficients. * Q_potential : Number of potential coefficients within `mask_area`. * P_fraction : The fraction of Q_potential to the pixel count in `img`. * Q_total : Total number of (considered) coefficients within `mask_area`. * Q_fraction : The fraction of Q_total to Q_potential * QC_fraction : The fraction of Q_total to C_total. * Q0-Q1 : Number of coefficients smaller than the first quantile. * Q1-Q2 : Number of coefficients between the first and second quantile. * Q2-Q3 : Number of coefficients between the second and third quantile. * Q3-Q4 : Number of coefficients between the third and fourth quantile. Each of the QX-QY holds a tuple containing two values: 1. The number of coefficients. 2. The fraction of the number of coefficients to Q_total. Examples -------- For example, show quantiles for a fraction of 0.2 of the DCT coefficients: >>> import numpy as np >>> from magni.imaging.dictionaries import analysis as _a >>> img = np.arange(64).astype(np.float).reshape(8, 8) >>> transforms = 'DCT' >>> fraction = 0.2 >>> _a.show_transform_quantiles(img, transform, fraction=fraction) """ @_decorate_validation def validate_input(): _numeric('img', ('integer', 'floating', 'complex'), shape=(-1, -1)) _generic('transform', 'string', value_in=_utils.get_transform_names()) _numeric('fraction', 'floating', range_='[0;1]') _numeric('area_mask', 'boolean', shape=img.shape, ignore_none=True) _generic('ax', mpl.axes.Axes, ignore_none=True) @_decorate_validation def validate_output(): _generic('coef_counts', 'mapping', has_keys=('Q_total', 'Q_potential', 'Q0_Q1', 'Q_fraction', 'Q3_Q4', 'Q2_Q3', 'Q1_Q2', 'C_total', 'QC_fraction')) validate_input() # Colorbrewer qualitative 5-class Set 1 as colormap colours = [(228, 26, 28), (55, 126, 184), (77, 175, 74), (152, 78, 163), (255, 127, 0)] norm_colours = [ tuple([round(val / 255, 4) for val in colour]) for colour in colours[::-1] ] norm_colours = [norm_colours[0]] * 2 + norm_colours quantile_cmap = mpl.colors.ListedColormap(norm_colours) # Transform transform_matrix = _utils.get_function_handle('matrix', transform)(img.shape) all_coefficients = _vec2mat(transform_matrix.conj().T.dot(_mat2vec(img)), img.shape) # Force very low values to zero to avoid false visualisations all_coefficients[all_coefficients < np.finfo(np.float).eps * 10] = 0 # Masked coefficients sorted_coefficients = np.sort(np.abs(all_coefficients), axis=None)[::-1] mask = np.abs(all_coefficients) > sorted_coefficients[ int(np.round(fraction * all_coefficients.size)) - 1] used_coefficients = np.zeros_like(all_coefficients, dtype=np.float) used_coefficients[mask] = np.abs(all_coefficients[mask]) # Quantiles q_linspace = np.linspace((1 - fraction) * 100, 100, 5) q_percentiles = tuple(q_linspace[1:4]) quantiles = np.percentile(used_coefficients, q_percentiles) disp_coefficients = np.zeros_like(used_coefficients) disp_coefficients[(0 < used_coefficients) & (used_coefficients <= quantiles[0])] = 1 disp_coefficients[(quantiles[0] < used_coefficients) & (used_coefficients <= quantiles[1])] = 2 disp_coefficients[(quantiles[1] < used_coefficients) & (used_coefficients <= quantiles[2])] = 3 disp_coefficients[quantiles[2] < used_coefficients] = 4 # Quantile figure disp, axes_extent = _utils.get_function_handle('visualisation', transform)(img.shape) if ax is None: fig, axes = plt.subplots(1, 1) else: fig = ax.get_figure() axes = ax im = _imshow( disp(_mat2vec(10**disp_coefficients)), ax=axes, # anti-log10 cmap=quantile_cmap, show_axis='top', interpolation='none', extent=axes_extent) divider = _make_axes_locatable(axes) c_bar_ax = divider.append_axes('bottom', '5%', pad='3%') cbar = fig.colorbar(im, c_bar_ax, orientation='horizontal') cbar.solids.set_edgecolor("face") cbar.set_ticks([0.85, 1.705, 2.278, 2.85, 3.419, 4.0]) cbar.set_ticklabels(['Excluded'] + [str(q) for q in q_linspace]) plt.tight_layout(rect=(0, 0, 1, 0.95)) # Area mask if area_mask is not None: _imshow(np.ma.array(np.ones_like(disp_coefficients), mask=area_mask), ax=axes, cmap='gray', show_axis='top', interpolation='none', extent=axes_extent, alpha=0.15) # Count of coefficients Q_total = np.sum(disp(_mat2vec(10**disp_coefficients))[area_mask] != 0) Qs = [ np.sum(disp(_mat2vec(10**disp_coefficients))[area_mask] == k) for k in [1, 2, 3, 4] ] coef_counts = { 'Q' + str(k - 1) + '_Q' + str(k): (Qs[k - 1], round(Qs[k - 1] / Q_total, 2)) for k in [1, 2, 3, 4] } coef_counts['Q_total'] = Q_total coef_counts['Q_potential'] = np.sum(area_mask) coef_counts['Q_fraction'] = round(Q_total / coef_counts['Q_potential'], 2) coef_counts['C_total'] = np.sum(used_coefficients != 0) coef_counts['P_fraction'] = round( coef_counts['Q_potential'] / img.size, 2) coef_counts['QC_fraction'] = round(Q_total / coef_counts['C_total'], 2) validate_output() return coef_counts
def display_coefficients(x): return np.log10(np.abs(_vec2mat(x, (h, w))))
def get_reconstructions(img, transform, fractions): """ Return transform reconstructions with different fractions of coefficents. The image `img` is transform coded using the specified `transform`. Reconstructions for the `fractions` of transform coefficients kept are returned along with the coefficients used in the reconstructions. Parameters ---------- img : ndarray The image to get reconstructions of. transform : str The transform to use to obtain the reconstructions. fractions : list or tuple The fractions of coefficents to be used in the reconstructions. Returns ------- coefficients : list The list of coefficients (each an ndarray) used in the reconstructions. reconstructions : list The list of reconstructions. Examples -------- Get reconstructions from DCT based on 20% and 40% of the coefficients: >>> import numpy as np >>> from magni.imaging.dictionaries.analysis import get_reconstructions >>> img = np.arange(64).astype(np.float).reshape(8, 8) >>> transform = 'DCT' >>> fractions = (0.2, 0.4) >>> coefs, recons = get_reconstructions(img, transform, fractions) >>> len(recons) 2 >>> tuple(int(s) for s in coefs[0].shape) (8, 8) >>> tuple(int(s) for s in recons[0].shape) (8, 8) """ @_decorate_validation def validate_input(): _numeric('img', ('integer', 'floating', 'complex'), shape=(-1, -1)) _generic('transform', 'string', value_in=_utils.get_transform_names()) _levels('fractions', (_generic(None, 'explicit collection'), _numeric(None, 'floating', range_='[0;1]'))) @_decorate_validation def validate_output(): _levels('coefficients', (_generic(None, 'explicit collection'), _numeric(None, ('integer', 'floating', 'complex'), shape=img.shape))) _levels('reconstructions', (_generic(None, 'explicit collection'), _numeric(None, ('integer', 'floating', 'complex'), shape=img.shape))) validate_input() coefficients = [] reconstructions = [] transform_matrix = _utils.get_function_handle('matrix', transform)(img.shape) all_coefficients = _vec2mat(transform_matrix.conj().T.dot(_mat2vec(img)), img.shape) sorted_coefficients = np.sort(np.abs(all_coefficients), axis=None)[::-1] for fraction in fractions: if int(fraction) == 1: used_coefficients = all_coefficients else: used_coefficients = np.zeros_like(all_coefficients) mask = np.abs(all_coefficients) > sorted_coefficients[ int(np.round(fraction * all_coefficients.size)) - 1] used_coefficients[mask] = all_coefficients[mask] reconstruction = _vec2mat( transform_matrix.dot(_mat2vec(used_coefficients)).real, img.shape) coefficients.append(used_coefficients) reconstructions.append(reconstruction) validate_output() return coefficients, reconstructions
def display_coefficients(x): return np.flipud( np.fft.fftshift(np.log10(np.abs(_vec2mat(x, (h, w))))))