Source code for menpo.feature.visualize

import numpy as np
from scipy.misc import imrotate

from .base import ndfeature


@ndfeature
[docs]def sum_channels(pixels, channels=None): r""" Create the sum of the channels of an image that can be used for visualization. Parameters ---------- pixels : :map:`Image` or subclass or ``(C, X, Y, ..., Z)`` `ndarray` Either the image object itself or an array with the pixels. The first dimension is interpreted as channels. channels : `list` of `int` or ``None`` The list of channels to be used. If ``None``, then all the channels are employed. """ # if channels is None, then all channels are used if channels is None: # Not indexing is twice as fast sum_image = np.sum(pixels, axis=0) else: sum_image = np.sum(pixels[channels], axis=0) return sum_image.reshape((1,) + sum_image.shape) # add a channel axis # TODO: Needs fixing ...
@ndfeature
[docs]def glyph(pixels, vectors_block_size=10, use_negative=False, channels=None): r""" Create the glyph of a feature image that can be used for visualization. If `pixels` have negative values, the `use_negative` flag controls whether there will be created a glyph of both positive and negative values concatenated the one on top of the other. Parameters ---------- pixels : :map:`Image` or subclass or ``(C, X, Y, ..., Z)`` `ndarray` Either the image object itself or an array with the pixels. The first dimension is interpreted as channels. vectors_block_size : `int` Defines the size of each block with vectors of the glyph image. use_negative : `bool` Defines whether to take into account possible negative values of feature_data. channels : `list` of `int` or ``None`` The list of channels to be used. If ``None``, then all the channels are employed. """ # first, choose the appropriate channels if channels is None: pixels = pixels[:4] elif channels != 'all': pixels = pixels[channels] else: pixels = pixels # TODO: This is a temporal fix # flip axis pixels = np.rollaxis(pixels, 0, len(pixels.shape)) # compute the glyph negative_weights = -pixels scale = np.maximum(pixels.max(), negative_weights.max()) pos = _create_feature_glyph(pixels, vectors_block_size) pos = pos * 255 / scale glyph_image = pos if use_negative and pixels.min() < 0: neg = _create_feature_glyph(negative_weights, vectors_block_size) neg = neg * 255 / scale glyph_image = np.concatenate((pos, neg)) # return as c-contiguous return np.ascontiguousarray(glyph_image[None, ...]) # add a channel axis
def _create_feature_glyph(feature, vbs): r""" Create glyph of feature pixels. Parameters ---------- feature : ``(N, D)`` `ndarray` The feature pixels to use. vbs : `int` Defines the size of each block with vectors of the glyph image. """ # vbs = Vector block size num_bins = feature.shape[2] # construct a "glyph" for each orientation block_image_temp = np.zeros((vbs, vbs)) # Create a vertical line of ones, to be the first vector block_image_temp[:, np.round(vbs / 2) - 1:np.round(vbs / 2) + 1] = 1 block_im = np.zeros((block_image_temp.shape[0], block_image_temp.shape[1], num_bins)) # First vector as calculated above block_im[:, :, 0] = block_image_temp # Number of bins rotations to create an 'asterisk' shape for i in range(1, num_bins): block_im[:, :, i] = imrotate(block_image_temp, -i * vbs) # make pictures of positive feature_data by adding up weighted glyphs feature[feature < 0] = 0 glyph_im = np.sum(block_im[None, None, :, :, :] * feature[:, :, None, None, :], axis=-1) glyph_im = np.bmat(glyph_im.tolist()) return glyph_im