kwimage.structs.heatmap
¶
[ ] Remove doctest dependency on ndsampler?
- [ ] Remove the datakeys that tries to define what heatmap should represent
(e.g. class_probs, keypoints, etc…) and instead just focus on a data structure that stores a [C, H, W] or [H, W] tensor?
- CommandLine:
xdoctest -m ~/code/kwimage/kwimage/structs/heatmap.py __doc__
Example
>>> # xdoctest: +REQUIRES(module:ndsampler)
>>> # xdoctest: +REQUIRES(--mask)
>>> from kwimage.structs.heatmap import * # NOQA
>>> import kwimage
>>> import ndsampler
>>> sampler = ndsampler.CocoSampler.demo('shapes')
>>> iminfo, anns = sampler.load_image_with_annots(1)
>>> image = iminfo['imdata']
>>> input_dims = image.shape[0:2]
>>> kp_classes = sampler.dset.keypoint_categories()
>>> dets = kwimage.Detections.from_coco_annots(
>>> anns, sampler.dset.dataset['categories'],
>>> sampler.catgraph, kp_classes, shape=input_dims)
>>> bg_size = [100, 100]
>>> heatmap = dets.rasterize(bg_size, input_dims, soften=2)
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> kwplot.figure(fnum=1, doclf=True)
>>> kwplot.imshow(image)
>>> heatmap.draw(invert=True, kpts=[0, 1, 2, 3, 4])
Example
>>> # xdoctest: +REQUIRES(module:ndsampler)
>>> # xdoctest: +REQUIRES(--mask)
>>> from kwimage.structs.heatmap import * # NOQA
>>> from kwimage.structs.detections import _dets_to_fcmaps
>>> import kwimage
>>> import ndsampler
>>> sampler = ndsampler.CocoSampler.demo('shapes')
>>> iminfo, anns = sampler.load_image_with_annots(1)
>>> image = iminfo['imdata']
>>> input_dims = image.shape[0:2]
>>> kp_classes = sampler.dset.keypoint_categories()
>>> dets = kwimage.Detections.from_coco_annots(
>>> anns, sampler.dset.dataset['categories'],
>>> sampler.catgraph, kp_classes, shape=input_dims)
>>> bg_size = [100, 100]
>>> bg_idxs = sampler.catgraph.index('background')
>>> fcn_target = _dets_to_fcmaps(dets, bg_size, input_dims, bg_idxs)
>>> fcn_target.keys()
>>> print('fcn_target: ' + ub.repr2(ub.map_vals(lambda x: x.shape, fcn_target), nl=1))
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> size_mask = fcn_target['size']
>>> dxdy_mask = fcn_target['dxdy']
>>> cidx_mask = fcn_target['cidx']
>>> kpts_mask = fcn_target['kpts']
>>> def _vizmask(dxdy_mask):
>>> dx, dy = dxdy_mask
>>> mag = np.sqrt(dx ** 2 + dy ** 2)
>>> mag /= (mag.max() + 1e-9)
>>> mask = (cidx_mask != 0).astype(np.float32)
>>> angle = np.arctan2(dy, dx)
>>> orimask = kwplot.make_orimask(angle, mask, alpha=mag)
>>> vecmask = kwplot.make_vector_field(
>>> dx, dy, stride=4, scale=0.1, thickness=1, tipLength=.2,
>>> line_type=16)
>>> return [vecmask, orimask]
>>> vecmask, orimask = _vizmask(dxdy_mask)
>>> raster = kwimage.overlay_alpha_layers(
>>> [vecmask, orimask, image], keepalpha=False)
>>> raster = dets.draw_on((raster * 255).astype(np.uint8),
>>> labels=True, alpha=None)
>>> kwplot.imshow(raster)
>>> kwplot.show_if_requested()
Module Contents¶
Classes¶
mixin methods for drawing heatmap details |
|
mixin method having to do with warping and aligning heatmaps |
|
Algorithmic operations on heatmaps |
|
Keeps track of a downscaled heatmap and how to transform it to overlay the |
Functions¶
|
Directly convert a one-channel probability map into a Detections object. |
|
Smooths the probability map, but preserves the magnitude of the peaks. |
Removes the translation component of a transform |
|
|
Compute the geometric mean along the specified axis. |
Attributes¶
- class kwimage.structs.heatmap._HeatmapDrawMixin[source]¶
Bases:
object
mixin methods for drawing heatmap details
- colorize(self, channel=None, invert=False, with_alpha=1.0, interpolation='linear', imgspace=False, cmap=None)[source]¶
Creates a colorized version of a heatmap channel suitable for visualization
- Parameters
channel (int | str) – index of category to visualize, or a special code indicating how to visualize multiple classes.
imgspace (bool, default=False) – colorize the image after warping into the image space.
- CommandLine:
xdoctest -m ~/code/kwimage/kwimage/structs/heatmap.py _HeatmapDrawMixin.colorize –show
Example
>>> # xdoctest: +REQUIRES(module:kwplot) >>> self = Heatmap.random(rng=0, dims=(32, 32)) >>> colormask1 = self.colorize(0, imgspace=False) >>> colormask2 = self.colorize(0, imgspace=True) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(colormask1, pnum=(1, 2, 1), fnum=1, title='output space') >>> kwplot.imshow(colormask2, pnum=(1, 2, 2), fnum=1, title='image space') >>> kwplot.show_if_requested()
Example
>>> # xdoctest: +REQUIRES(module:kwplot) >>> self = Heatmap.random(rng=0, dims=(32, 32)) >>> colormask1 = self.colorize('diameter', imgspace=False) >>> colormask2 = self.colorize('diameter', imgspace=True) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(colormask1, pnum=(1, 2, 1), fnum=1, title='output space') >>> kwplot.imshow(colormask2, pnum=(1, 2, 2), fnum=1, title='image space') >>> kwplot.show_if_requested()
- Ignore:
>>> # xdoctest: +REQUIRES(module:kwplot) >>> self = Heatmap.random(rng=0, dims=(32, 32)) >>> self.data['class_energy'] = (self.data['class_probs'] - .5) * 10 >>> colormask1 = self.colorize('class_energy_color', imgspace=False) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(colormask1, fnum=1, title='output space') >>> kwplot.show_if_requested()
- draw_stacked(self, image=None, dsize=(224, 224), ignore_class_idxs={}, top=None, chosen_cxs=None)[source]¶
Draws per-class probabilities and stacks them into a single image
Example
>>> # xdoctest: +REQUIRES(module:kwplot) >>> self = Heatmap.random(rng=0, dims=(32, 32)) >>> stacked = self.draw_stacked() >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(stacked)
- draw(self, channel=None, image=None, imgspace=None, **kwargs)[source]¶
Accepts same args as draw_on, but uses maplotlib
- Parameters
channel (int | str) – category index to visualize, or special key
- draw_on(self, image=None, channel=None, invert=False, with_alpha=1.0, interpolation='linear', vecs=False, kpts=None, imgspace=None)[source]¶
Overlays a heatmap channel on top of an image
- Parameters
image (ndarray) – image to draw on, if unspecified one is created.
channel (int | str) – category index to visualize, or special key. special keys are: class_idx, class_probs, class_idx
imgspace (bool, default=False) – colorize the image after warping into the image space.
Todo
- [ ] Find a way to visualize offset, diameter, and class_probs
either individually or all at the same time
Example
>>> # xdoctest: +REQUIRES(module:kwplot) >>> import kwarray >>> import kwimage >>> image = kwimage.grab_test_image('astro') >>> probs = kwimage.gaussian_patch(image.shape[0:2])[None, :] >>> probs = probs / probs.max() >>> class_probs = kwarray.ArrayAPI.cat([probs, 1 - probs], axis=0) >>> self = kwimage.Heatmap(class_probs=class_probs, offset=5 * np.random.randn(2, *probs.shape[1:])) >>> toshow = self.draw_on(image, 0, vecs=True, with_alpha=0.85) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(toshow)
Example
>>> # xdoctest: +REQUIRES(module:kwplot) >>> # xdoctest: +REQUIRES(module:ndsampler) >>> import kwimage >>> self = kwimage.Heatmap.random(dims=(200, 200), dets='coco', keypoints=True) >>> image = kwimage.grab_test_image('astro') >>> toshow = self.draw_on(image, 0, vecs=False, with_alpha=0.85) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(toshow)
Example
>>> # xdoctest: +REQUIRES(module:kwplot) >>> # xdoctest: +REQUIRES(module:ndsampler) >>> import kwimage >>> self = kwimage.Heatmap.random(dims=(200, 200), dets='coco', keypoints=True) >>> kpts = [6] >>> self = self.warp(self.tf_data_to_img.params) >>> image = kwimage.grab_test_image('astro') >>> image = kwimage.ensure_alpha_channel(image) >>> toshow = self.draw_on(image, 0, with_alpha=0.85, kpts=kpts) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(toshow)
Example
>>> # xdoctest: +REQUIRES(module:kwplot) >>> # xdoctest: +REQUIRES(module:ndsampler) >>> import kwimage >>> mask = np.random.rand(32, 32) >>> self = kwimage.Heatmap( >>> class_probs=mask, >>> img_dims=mask.shape[0:2], >>> tf_data_to_img=np.eye(3), >>> ) >>> canvas = self.draw_on() >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(canvas)
import xdev globals().update(xdev.get_func_kwargs(Heatmap.draw_on))
- class kwimage.structs.heatmap._HeatmapWarpMixin[source]¶
Bases:
object
mixin method having to do with warping and aligning heatmaps
- _align_other(self, other)[source]¶
Warp another Heatmap (with the same underlying imgdims) into the same space as this heatmap. This lets us perform elementwise operations on the two heatmaps (like geometric mean).
- Parameters
other (Heatmap) – the heatmap to align with self
- Returns
warped version of other that aligns with self.
- Return type
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> self = Heatmap.random((120, 130), img_dims=(200, 210), classes=2, nblips=10, rng=0) >>> other = Heatmap.random((60, 70), img_dims=(200, 210), classes=2, nblips=10, rng=1) >>> other2 = self._align_other(other) >>> assert self.shape != other.shape >>> assert self.shape == other2.shape >>> # xdoctest: +REQUIRES(--show) >>> kwplot.autompl() >>> kwplot.imshow(self.colorize(0, imgspace=False), fnum=1, pnum=(3, 2, 1)) >>> kwplot.imshow(self.colorize(1, imgspace=False), fnum=1, pnum=(3, 2, 2)) >>> kwplot.imshow(other.colorize(0, imgspace=False), fnum=1, pnum=(3, 2, 3)) >>> kwplot.imshow(other.colorize(1, imgspace=False), fnum=1, pnum=(3, 2, 4))
- _align(self, mask, interpolation='linear')[source]¶
Align a linear combination of heatmap channels with the original image
DEPRICATE
- upscale(self, channel=None, interpolation='linear')[source]¶
Warp the heatmap with the image dimensions
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> self = Heatmap.random(rng=0, dims=(32, 32)) >>> colormask = self.upscale()
- warp(self, mat=None, input_dims=None, output_dims=None, interpolation='linear', modify_spatial_coords=True, int_interpolation='nearest', mat_is_xy=True, version=None)[source]¶
Warp all spatial maps. If the map contains spatial data, that data is also warped (ignoring the translation component).
- Parameters
mat (ArrayLike) – transformation matrix
input_dims (tuple) – unused, only exists for compatibility
output_dims (tuple) – size of the output heatmap
interpolation (str) – see kwimage.warp_tensor
int_interpolation (str) – interpolation used for interger types (should be nearest)
mat_is_xy (bool, default=True) – set to false if the matrix is in yx space instead of xy space
- Returns
this heatmap warped into a new spatial dimension
- Return type
- Ignore:
# Verify swapping rows 0 and 1 and then swapping columns 0 and 1 # Produces a matrix that works with permuted coordinates # It does. import sympy a, b, c, d, e, f, g, h, i, x, y, z = sympy.symbols(‘a, b, c, d, e, f, g, h, i, x, y, z’) M1 = sympy.Matrix([[a, b, c], [d, e, f], [g, h, i]]) M2 = sympy.Matrix([[e, d, f], [b, a, c], [h, g, i]]) xy = sympy.Matrix([[x], [y], [z]]) yx = sympy.Matrix([[y], [x], [z]])
R1 = M1.multiply(xy) R2 = M2.multiply(yx) R3 = sympy.Matrix([[R1[1]], [R1[0]], [R1[2]],]) assert R2 == R3
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> from kwimage.structs.heatmap import * # NOQA >>> self = Heatmap.random(rng=0, keypoints=True) >>> S = 3.0 >>> mat = np.eye(3) * S >>> mat[-1, -1] = 1 >>> newself = self.warp(mat, np.array(self.dims) * S).numpy() >>> assert newself.offset.shape[0] == 2 >>> assert newself.diameter.shape[0] == 2 >>> f1 = newself.offset.max() / self.offset.max() >>> assert f1 == S >>> f2 = newself.diameter.max() / self.diameter.max() >>> assert f2 == S
Example
>>> import kwimage >>> # xdoctest: +REQUIRES(module:ndsampler) >>> self = kwimage.Heatmap.random(dims=(100, 100), dets='coco', keypoints=True) >>> image = np.zeros(self.img_dims) >>> # xdoctest: +REQUIRES(module:kwplot) >>> toshow = self.draw_on(image, 1, vecs=True, with_alpha=0.85) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.figure(fnum=1, doclf=True) >>> kwplot.imshow(toshow)
- class kwimage.structs.heatmap._HeatmapAlgoMixin[source]¶
Bases:
object
Algorithmic operations on heatmaps
- classmethod combine(cls, heatmaps, root_index=None, dtype=np.float32)[source]¶
Combine multiple heatmaps into a single heatmap.
- Parameters
heatmaps (Sequence[Heatmap]) – multiple heatmaps to combine into one
root_index (int) – which heatmap in the sequence to align other heatmaps with
- Returns
the combined heatmap
- Return type
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> from kwimage.structs.heatmap import * # NOQA >>> a = Heatmap.random((120, 130), img_dims=(200, 210), classes=2, nblips=10, rng=0) >>> b = Heatmap.random((60, 70), img_dims=(200, 210), classes=2, nblips=10, rng=1) >>> c = Heatmap.random((40, 30), img_dims=(200, 210), classes=2, nblips=10, rng=1) >>> heatmaps = [a, b, c] >>> newself = Heatmap.combine(heatmaps, root_index=2) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(a.colorize(0, imgspace=1), fnum=1, pnum=(4, 2, 1)) >>> kwplot.imshow(a.colorize(1, imgspace=1), fnum=1, pnum=(4, 2, 2)) >>> kwplot.imshow(b.colorize(0, imgspace=1), fnum=1, pnum=(4, 2, 3)) >>> kwplot.imshow(b.colorize(1, imgspace=1), fnum=1, pnum=(4, 2, 4)) >>> kwplot.imshow(c.colorize(0, imgspace=1), fnum=1, pnum=(4, 2, 5)) >>> kwplot.imshow(c.colorize(1, imgspace=1), fnum=1, pnum=(4, 2, 6)) >>> kwplot.imshow(newself.colorize(0, imgspace=1), fnum=1, pnum=(4, 2, 7)) >>> kwplot.imshow(newself.colorize(1, imgspace=1), fnum=1, pnum=(4, 2, 8)) >>> # xdoctest: +REQUIRES(--show) >>> kwplot.imshow(a.colorize('offset', imgspace=1), fnum=2, pnum=(4, 1, 1)) >>> kwplot.imshow(b.colorize('offset', imgspace=1), fnum=2, pnum=(4, 1, 2)) >>> kwplot.imshow(c.colorize('offset', imgspace=1), fnum=2, pnum=(4, 1, 3)) >>> kwplot.imshow(newself.colorize('offset', imgspace=1), fnum=2, pnum=(4, 1, 4)) >>> # xdoctest: +REQUIRES(--show) >>> kwplot.imshow(a.colorize('diameter', imgspace=1), fnum=3, pnum=(4, 1, 1)) >>> kwplot.imshow(b.colorize('diameter', imgspace=1), fnum=3, pnum=(4, 1, 2)) >>> kwplot.imshow(c.colorize('diameter', imgspace=1), fnum=3, pnum=(4, 1, 3)) >>> kwplot.imshow(newself.colorize('diameter', imgspace=1), fnum=3, pnum=(4, 1, 4))
- detect(self, channel, invert=False, min_score=0.01, num_min=10, max_dims=None, min_dims=None, dim_thresh_space='image')[source]¶
Lossy conversion from a Heatmap to a Detections object.
For efficiency, the detections are returned in the same space as the heatmap, which usually some downsampled version of the image space. This is because it is more efficient to transform the detections into image-space after non-max supression is applied.
- Parameters
channel (int | ArrayLike[*DIMS]) – class index to detect objects in. Alternatively, channel can be a custom probability map as long as its dimension agree with the heatmap.
invert (bool, default=False) – if True, inverts the probabilities in the chosen channel. (Useful if you have a background channel but want to detect foreground objects).
min_score (float, default=0.1) – probability threshold required for a pixel to be converted into a detection.
num_min (int, default=10) – always return at least nmin of the highest scoring detections even if they aren’t above the min_score threshold.
max_dims (Tuple[int, int]) – maximum height / width of detections By default these are expected to be in image-space.
min_dims (Tuple[int, int]) – minimum height / width of detections By default these are expected to be in image-space.
dim_thresh_space (str, default=’image’) – When dim_thresh_space==’native’, dimension thresholds (e.g. min_dims and max_dims) are specified in the native heatmap space (i.e. usually a downsampled space). If dim_thresh_space==’image’, then dimension thresholds are interpreted in the original image space.
- Returns
raw detections.
Note that these detections will not have class_idx populated
It is the users responsbility to run non-max suppression on these results to remove duplicate detections.
- Return type
- SeeAlso:
Detections.rasterize
Example
>>> # xdoctest: +REQUIRES(module:ndsampler) >>> from kwimage.structs.heatmap import * # NOQA >>> import ndsampler >>> self = Heatmap.random(rng=2, dims=(32, 32)) >>> dets = self.detect(channel=0, max_dims=7, num_min=None) >>> img_dets = dets.warp(self.tf_data_to_img) >>> assert img_dets.boxes.to_xywh().width.max() <= 7 >>> assert img_dets.boxes.to_xywh().height.max() <= 7 >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> dets1 = dets.sort().take(range(30)) >>> colormask1 = self.colorize(0, imgspace=False) >>> kwplot.imshow(colormask1, pnum=(1, 2, 1), fnum=1, title='output space') >>> dets1.draw() >>> # Transform heatmap and detections into image space. >>> dets2 = dets1.warp(self.tf_data_to_img) >>> colormask2 = self.colorize(0, imgspace=True) >>> kwplot.imshow(colormask2, pnum=(1, 2, 2), fnum=1, title='image space') >>> dets2.draw()
Example
>>> # xdoctest: +REQUIRES(module:ndsampler) >>> from kwimage.structs.heatmap import * # NOQA >>> import ndsampler >>> catgraph = ndsampler.CategoryTree.demo() >>> class_energy = torch.rand(len(catgraph), 32, 32) >>> class_probs = catgraph.hierarchical_softmax(class_energy, dim=0) >>> self = Heatmap.random(rng=0, dims=(32, 32), classes=catgraph, keypoints=True) >>> print(ub.repr2(ub.map_vals(lambda x: x.shape, self.data), nl=1)) >>> self.data['class_probs'] = class_probs.numpy() >>> channel = catgraph.index('background') >>> dets = self.detect(channel, invert=True) >>> class_idx, scores = catgraph.decision(dets.probs, dim=1) >>> dets.data['class_idx'] = class_idx >>> dets.data['scores'] = scores >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> dets1 = dets.sort().take(range(10)) >>> colormask1 = self.colorize(0, imgspace=False) >>> kwplot.imshow(colormask1, pnum=(1, 2, 1), fnum=1, title='output space') >>> dets1.draw(radius=1.0) >>> # Transform heatmap and detections into image space. >>> colormask2 = self.colorize(0, imgspace=True) >>> dets2 = dets1.warp(self.tf_data_to_img) >>> kwplot.imshow(colormask2, pnum=(1, 2, 2), fnum=1, title='image space') >>> dets2.draw(radius=1.0)
- class kwimage.structs.heatmap.Heatmap(data=None, meta=None, **kwargs)[source]¶
Bases:
kwimage.structs._generic.Spatial
,_HeatmapDrawMixin
,_HeatmapWarpMixin
,_HeatmapAlgoMixin
Keeps track of a downscaled heatmap and how to transform it to overlay the original input image. Heatmaps generally are used to estimate class probabilites at each pixel. This data struction additionally contains logic to augment pixel with offset (dydx) and scale (diamter) information.
- Variables
data (Dict[str, ArrayLike]) –
dictionary containing spatially aligned heatmap data. Valid keys are as follows.
- class_probs (ArrayLike[C, H, W] | ArrayLike[C, D, H, W]):
A probability map for each class. C is the number of classes.
- offset (ArrayLike[2, H, W] | ArrayLike[3, D, H, W], optional):
object center position offset in y,x / t,y,x coordinates
- diamter (ArrayLike[2, H, W] | ArrayLike[3, D, H, W], optional):
object bounding box sizes in h,w / d,h,w coordinates
- keypoints (ArrayLike[2, K, H, W] | ArrayLike[3, K, D, H, W], optional):
y/x offsets for K different keypoint classes
dictionary containing miscellanious metadata about the heatmap data. Valid keys are as follows.
- img_dims (Tuple[H, W] | Tuple[D, H, W]):
original image dimension
- tf_data_to_image (skimage.transform._geometric.GeometricTransform):
transformation matrix (typically similarity or affine) that projects the given, heatmap onto the image dimensions such that the image and heatmap are spatially aligned.
- classes (List[str] | ndsampler.CategoryTree):
information about which index in data[‘class_probs’] corresponds to which semantic class.
dims (Tuple) – dimensions of the heatmap (See `image_dims) for the original image dimensions.
**kwargs – any key that is accepted by the data or meta dictionaries can be specified as a keyword argument to this class and it will be properly placed in the appropriate internal dictionary.
- CommandLine:
xdoctest -m ~/code/kwimage/kwimage/structs/heatmap.py Heatmap –show
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> from kwimage.structs.heatmap import * # NOQA >>> import kwimage >>> class_probs = kwimage.grab_test_image(dsize=(32, 32), space='gray')[None, ] / 255.0 >>> img_dims = (220, 220) >>> tf_data_to_img = skimage.transform.AffineTransform(translation=(-18, -18), scale=(8, 8)) >>> self = Heatmap(class_probs=class_probs, img_dims=img_dims, >>> tf_data_to_img=tf_data_to_img) >>> aligned = self.upscale() >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(aligned[0]) >>> kwplot.show_if_requested()
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> import kwimage >>> self = Heatmap.random() >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> self.draw()
- __datakeys__ = ['class_probs', 'offset', 'diameter', 'keypoints', 'class_idx', 'class_energy'][source]¶
- property _impl(self)[source]¶
Returns the internal tensor/numpy ArrayAPI implementation
- Returns
kwarray.ArrayAPI
- classmethod random(cls, dims=(10, 10), classes=3, diameter=True, offset=True, keypoints=False, img_dims=None, dets=None, nblips=10, noise=0.0, rng=None)[source]¶
Creates dummy data, suitable for use in tests and benchmarks
- Parameters
dims (Tuple) – dimensions of the heatmap
img_dims (Tuple) – dimensions of the image the heatmap corresponds to
Example
>>> from kwimage.structs.heatmap import * # NOQA >>> self = Heatmap.random((128, 128), img_dims=(200, 200), >>> classes=3, nblips=10, rng=0, noise=0.1) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.imshow(self.colorize(0, imgspace=0), fnum=1, pnum=(1, 4, 1), doclf=1) >>> kwplot.imshow(self.colorize(1, imgspace=0), fnum=1, pnum=(1, 4, 2)) >>> kwplot.imshow(self.colorize(2, imgspace=0), fnum=1, pnum=(1, 4, 3)) >>> kwplot.imshow(self.colorize(3, imgspace=0), fnum=1, pnum=(1, 4, 4))
- Ignore:
self.detect(0).sort().non_max_supress()[-np.arange(1, 4)].draw() from kwimage.structs.heatmap import * # NOQA import xdev globals().update(xdev.get_func_kwargs(Heatmap.random))
Example
>>> # xdoctest: +REQUIRES(module:ndsampler) >>> import kwimage >>> self = kwimage.Heatmap.random(dims=(50, 200), dets='coco', >>> keypoints=True) >>> image = np.zeros(self.img_dims) >>> # xdoctest: +REQUIRES(module:kwplot) >>> toshow = self.draw_on(image, 1, vecs=True, kpts=0, with_alpha=0.85) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.figure(fnum=1, doclf=True) >>> kwplot.imshow(toshow)
- Ignore:
>>> kwplot.figure(fnum=1, doclf=True) >>> kwplot.imshow(image) >>> dets.draw() >>> dets.data['keypoints'].draw(radius=6) >>> dets.data['segmentations'].draw()
>>> self.draw()
- kwimage.structs.heatmap._prob_to_dets(probs, diameter=None, offset=None, class_probs=None, keypoints=None, min_score=0.01, num_min=10, max_dims=None, min_dims=None)[source]¶
Directly convert a one-channel probability map into a Detections object.
Helper for Heatmap.detect
It does this by converting each pixel above a threshold in a probability map to a detection with a specified diameter.
- Parameters
probs (ArrayLike[H, W]) – liklihood that each particular pixel should be detected as an object.
diameter (ArrayLike[2, H, W] | Tuple) – H, W sizes for the bounding box at each pixel location. If passed as a tuple, then all boxes receive that diameter.
offset (Tuple | ArrayLike[2, H, W], default=0) – Y, X offsets from the pixel location to the bounding box center. If passed as a tuple, then all boxes receive that offset.
class_probs (ArrayLike[C, H, W], optional) – probabilities for each class at each pixel location. If specified, this will populate the probs attribute of the returned Detections object.
keypoints (ArrayLike[2, K, H, W], optional) – Keypoint predictions for all keypoint classes
min_score (float, default=0.1) – probability threshold required for a pixel to be converted into a detection.
num_min (int, default=10) – always return at least nmin of the highest scoring detections even if they aren’t above the min_score threshold.
- Returns
- raw detections. It is the users responsbility to
run non-max suppression on these results to remove duplicate detections.
- Return type
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> rng = np.random.RandomState(0) >>> probs = rng.rand(3, 3).astype(np.float32) >>> min_score = .5 >>> diameter = [10, 10] >>> dets = _prob_to_dets(probs, diameter, min_score=min_score) >>> assert dets.boxes.data.dtype.kind == 'f' >>> assert len(dets) == 9 >>> dets = _prob_to_dets(torch.FloatTensor(probs), diameter, min_score=min_score) >>> assert dets.boxes.data.dtype.is_floating_point >>> assert len(dets) == 9
Example
>>> # xdoctest: +REQUIRES(module:torch) >>> import kwimage >>> from kwimage.structs.heatmap import * >>> from kwimage.structs.heatmap import _prob_to_dets >>> heatmap = kwimage.Heatmap.random(rng=0, dims=(3, 3), keypoints=True) >>> # Try with numpy >>> min_score = .5 >>> dets = _prob_to_dets(heatmap.class_probs[0], heatmap.diameter, >>> heatmap.offset, heatmap.class_probs, >>> heatmap.data['keypoints'], >>> min_score) >>> assert dets.boxes.data.dtype.kind == 'f' >>> assert 'keypoints' in dets.data >>> dets_np = dets >>> # Try with torch >>> heatmap = heatmap.tensor() >>> dets = _prob_to_dets(heatmap.class_probs[0], heatmap.diameter, >>> heatmap.offset, heatmap.class_probs, >>> heatmap.data['keypoints'], >>> min_score) >>> assert dets.boxes.data.dtype.is_floating_point >>> assert len(dets) == len(dets_np) >>> dets_torch = dets >>> assert np.all(dets_torch.numpy().boxes.data == dets_np.boxes.data)
- Ignore:
import kwil kwil.autompl() dets.draw(setlim=True, radius=.1)
Example
>>> heatmap = Heatmap.random(rng=0, dims=(3, 3), diameter=1) >>> probs = heatmap.class_probs[0] >>> diameter = heatmap.diameter >>> offset = heatmap.offset >>> class_probs = heatmap.class_probs >>> min_score = 0.5 >>> dets = _prob_to_dets(probs, diameter, offset, class_probs, None, min_score)
- kwimage.structs.heatmap.smooth_prob(prob, k=3, inplace=False, eps=1e-09)[source]¶
Smooths the probability map, but preserves the magnitude of the peaks.
Notes
even if inplace is true, we still need to make a copy of the input array, however, we do ensure that it is cleaned up before we leave the function scope.
sigma=0.8 @ k=3, sigma=1.1 @ k=5, sigma=1.4 @ k=7
- kwimage.structs.heatmap._remove_translation(tf)[source]¶
Removes the translation component of a transform
Todo
[ ] Is this possible in more general cases? E.g. projective transforms?
- kwimage.structs.heatmap._gmean(a, axis=0, clobber=False)[source]¶
Compute the geometric mean along the specified axis.
Modification of the scipy.mstats method to be more memory efficient
- Example
>>> rng = np.random.RandomState(0) >>> C, H, W = 8, 32, 32 >>> axis = 0 >>> a = rng.rand(2, C, H, W) >>> _gmean(a)