kwimage.structs.points

Module Contents

Classes

_PointsWarpMixin

Points

Stores multiple keypoints for a single object.

PointsList

Stores a list of Points, each item usually corresponds to a different object.

class kwimage.structs.points._PointsWarpMixin[source]
_warp_imgaug(self, augmenter, input_dims, inplace=False)[source]

Warps by applying an augmenter from the imgaug library

Parameters
  • augmenter (imgaug.augmenters.Augmenter)

  • input_dims (Tuple) – h/w of the input image

  • inplace (bool, default=False) – if True, modifies data inplace

Example

>>> # xdoctest: +REQUIRES(module:imgaug)
>>> from kwimage.structs.points import *  # NOQA
>>> import imgaug
>>> input_dims = (10, 10)
>>> self = Points.random(10).scale(input_dims)
>>> augmenter = imgaug.augmenters.Fliplr(p=1)
>>> new = self._warp_imgaug(augmenter, input_dims)
>>> self = Points(xy=(np.random.rand(10, 2) * 10).astype(int))
>>> augmenter = imgaug.augmenters.Fliplr(p=1)
>>> new = self._warp_imgaug(augmenter, input_dims)
>>> # xdoc: +REQUIRES(--show)
>>> import kwplot
>>> plt = kwplot.autoplt()
>>> kwplot.figure(fnum=1, doclf=True)
>>> ax = plt.gca()
>>> ax.set_xlim(0, 10)
>>> ax.set_ylim(0, 10)
>>> self.draw(color='red', alpha=.4, radius=0.1)
>>> new.draw(color='blue', alpha=.4, radius=0.1)
to_imgaug(self, input_dims)[source]

Example

>>> # xdoctest: +REQUIRES(module:imgaug)
>>> from kwimage.structs.points import *  # NOQA
>>> pts = Points.random(10)
>>> input_dims = (10, 10)
>>> kpoi = pts.to_imgaug(input_dims)
classmethod from_imgaug(cls, kpoi)[source]
property dtype(self)[source]
warp(self, transform, input_dims=None, output_dims=None, inplace=False)[source]

Generalized coordinate transform.

Parameters
  • transform (GeometricTransform | ArrayLike | Augmenter | callable) – scikit-image tranform, a 3x3 transformation matrix, an imgaug Augmenter, or generic callable which transforms an NxD ndarray.

  • input_dims (Tuple) – shape of the image these objects correspond to (only needed / used when transform is an imgaug augmenter)

  • output_dims (Tuple) – unused, only exists for compatibility

  • inplace (bool, default=False) – if True, modifies data inplace

Example

>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(10, rng=0)
>>> transform = skimage.transform.AffineTransform(scale=(2, 2))
>>> new = self.warp(transform)
>>> assert np.all(new.xy == self.scale(2).xy)
Doctest:
>>> self = Points.random(10, rng=0)
>>> assert np.all(self.warp(np.eye(3)).xy == self.xy)
>>> assert np.all(self.warp(np.eye(2)).xy == self.xy)
scale(self, factor, output_dims=None, inplace=False)[source]

Scale a points by a factor

Parameters
  • factor (float or Tuple[float, float]) – scale factor as either a scalar or a (sf_x, sf_y) tuple.

  • output_dims (Tuple) – unused in non-raster spatial structures

Example

>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(10, rng=0)
>>> new = self.scale(10)
>>> assert new.xy.max() <= 10
translate(self, offset, output_dims=None, inplace=False)[source]

Shift the points

Parameters
  • factor (float or Tuple[float]) – transation amount as either a scalar or a (t_x, t_y) tuple.

  • output_dims (Tuple) – unused in non-raster spatial structures

Example

>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(10, rng=0)
>>> new = self.translate(10)
>>> assert new.xy.min() >= 10
>>> assert new.xy.max() <= 11
class kwimage.structs.points.Points(data=None, meta=None, datakeys=None, metakeys=None, **kwargs)[source]

Bases: kwimage.structs._generic.Spatial, _PointsWarpMixin

Stores multiple keypoints for a single object.

This stores both the geometry and the class metadata if available

Ignore:
meta = {

“names” = [‘head’, ‘nose’, ‘tail’], “skeleton” = [(0, 1), (0, 2)],

}

Example

>>> from kwimage.structs.points import *  # NOQA
>>> xy = np.random.rand(10, 2)
>>> pts = Points(xy=xy)
>>> print('pts = {!r}'.format(pts))
__datakeys__ = ['xy', 'class_idxs', 'visible'][source]
__metakeys__ = ['classes'][source]
__repr__[source]
__nice__(self)[source]
__len__(self)[source]
property shape(self)[source]
property xy(self)[source]
classmethod random(Points, num=1, classes=None, rng=None)[source]

Makes random points; typically for testing purposes

Example

>>> import kwimage
>>> self = kwimage.Points.random(classes=[1, 2, 3])
>>> self.data
>>> print('self.data = {!r}'.format(self.data))
is_numpy(self)[source]
is_tensor(self)[source]
_impl(self)[source]
tensor(self, device=ub.NoParam)[source]

Example

>>> # xdoctest: +REQUIRES(module:torch)
>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(10)
>>> self.tensor()
round(self, inplace=False)[source]

Rounds data to the nearest integer

Parameters

inplace (bool, default=False) – if True, modifies this object

Example

>>> import kwimage
>>> self = kwimage.Points.random(3).scale(10)
>>> self.round()
numpy(self)[source]

Example

>>> # xdoctest: +REQUIRES(module:torch)
>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(10)
>>> self.tensor().numpy().tensor().numpy()
draw_on(self, image, color='white', radius=None, copy=False)[source]
CommandLine:

xdoctest -m ~/code/kwimage/kwimage/structs/points.py Points.draw_on –show

Example

>>> # xdoc: +REQUIRES(module:kwplot)
>>> from kwimage.structs.points import *  # NOQA
>>> s = 128
>>> image = np.zeros((s, s))
>>> self = Points.random(10).scale(s)
>>> image = self.draw_on(image)
>>> # xdoc: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.figure(fnum=1, doclf=True)
>>> kwplot.autompl()
>>> kwplot.imshow(image)
>>> self.draw(radius=3, alpha=.5)
>>> kwplot.show_if_requested()

Example

>>> # xdoc: +REQUIRES(module:kwplot)
>>> from kwimage.structs.points import *  # NOQA
>>> s = 128
>>> image = np.zeros((s, s))
>>> self = Points.random(10).scale(s)
>>> image = self.draw_on(image, radius=3, color='distinct')
>>> # xdoc: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.figure(fnum=1, doclf=True)
>>> kwplot.autompl()
>>> kwplot.imshow(image)
>>> self.draw(radius=3, alpha=.5, color='classes')
>>> kwplot.show_if_requested()

Example

>>> import kwimage
>>> s = 32
>>> self = kwimage.Points.random(10).scale(s)
>>> color = 'blue'
>>> # Test drawong on all channel + dtype combinations
>>> im3 = np.zeros((s, s, 3), dtype=np.float32)
>>> im_chans = {
>>>     'im3': im3,
>>>     'im1': kwimage.convert_colorspace(im3, 'rgb', 'gray'),
>>>     'im4': kwimage.convert_colorspace(im3, 'rgb', 'rgba'),
>>> }
>>> inputs = {}
>>> for k, im in im_chans.items():
>>>     inputs[k + '_01'] = (kwimage.ensure_float01(im.copy()), {'radius': None})
>>>     inputs[k + '_255'] = (kwimage.ensure_uint255(im.copy()), {'radius': None})
>>> outputs = {}
>>> for k, v in inputs.items():
>>>     im, kw = v
>>>     outputs[k] = self.draw_on(im, color=color, **kw)
>>> # xdoc: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.figure(fnum=2, doclf=True)
>>> kwplot.autompl()
>>> pnum_ = kwplot.PlotNums(nCols=2, nRows=len(inputs))
>>> for k in inputs.keys():
>>>     kwplot.imshow(inputs[k][0], fnum=2, pnum=pnum_(), title=k)
>>>     kwplot.imshow(outputs[k], fnum=2, pnum=pnum_(), title=k)
>>> kwplot.show_if_requested()
draw(self, color='blue', ax=None, alpha=None, radius=1, **kwargs)[source]

TODO: can use kwplot.draw_points

Example

>>> # xdoc: +REQUIRES(module:kwplot)
>>> from kwimage.structs.points import *  # NOQA
>>> pts = Points.random(10)
>>> # xdoc: +REQUIRES(--show)
>>> pts.draw(radius=0.01)
>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(10, classes=['a', 'b', 'c'])
>>> self.draw(radius=0.01, color='classes')
compress(self, flags, axis=0, inplace=False)[source]

Filters items based on a boolean criterion

Example

>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(4)
>>> flags = [1, 0, 1, 1]
>>> other = self.compress(flags)
>>> assert len(self) == 4
>>> assert len(other) == 3
>>> # xdoctest: +REQUIRES(module:torch)
>>> other = self.tensor().compress(flags)
>>> assert len(other) == 3
take(self, indices, axis=0, inplace=False)[source]

Takes a subset of items at specific indices

Example

>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(4)
>>> indices = [1, 3]
>>> other = self.take(indices)
>>> assert len(self) == 4
>>> assert len(other) == 2
>>> # xdoctest: +REQUIRES(module:torch)
>>> other = self.tensor().take(indices)
>>> assert len(other) == 2
classmethod concatenate(cls, points, axis=0)[source]
to_coco(self, style='orig')[source]

Converts to an mscoco-like representation

Note

items that are usually id-references to other objects may need to be rectified.

Parameters

style (str) – either orig, new, new-id, or new-name

Returns

mscoco-like representation

Return type

Dict

Example

>>> from kwimage.structs.points import *  # NOQA
>>> self = Points.random(4, classes=['a', 'b'])
>>> orig = self._to_coco(style='orig')
>>> print('orig = {!r}'.format(orig))
>>> new_name = self._to_coco(style='new-name')
>>> print('new_name = {}'.format(ub.repr2(new_name, nl=-1)))
>>> # xdoctest: +REQUIRES(module:ndsampler)
>>> import ndsampler
>>> self.meta['classes'] = ndsampler.CategoryTree.coerce(self.meta['classes'])
>>> new_id = self._to_coco(style='new-id')
>>> print('new_id = {}'.format(ub.repr2(new_id, nl=-1)))
_to_coco(self, style='orig')[source]

See to_coco

classmethod coerce(cls, data)[source]

Attempt to coerce data into a Points object

classmethod _from_coco(cls, coco_kpts, class_idxs=None, classes=None)[source]
classmethod from_coco(cls, coco_kpts, class_idxs=None, classes=None, warn=False)[source]
Parameters
  • coco_kpts (list | dict) – either the original list keypoint encoding or the new dict keypoint encoding.

  • class_idxs (list) – only needed if using old style

  • classes (list | CategoryTree) – list of all keypoint category names

  • warn (bool, default=False) – if True raise warnings

Example

>>> ##
>>> classes = ['mouth', 'left-hand', 'right-hand']
>>> coco_kpts = [
>>>     {'xy': (0, 0), 'visible': 2, 'keypoint_category': 'left-hand'},
>>>     {'xy': (1, 2), 'visible': 2, 'keypoint_category': 'mouth'},
>>> ]
>>> Points.from_coco(coco_kpts, classes=classes)
>>> # Test without classes
>>> Points.from_coco(coco_kpts)
>>> # Test without any category info
>>> coco_kpts2 = [ub.dict_diff(d, {'keypoint_category'}) for d in coco_kpts]
>>> Points.from_coco(coco_kpts2)
>>> # Test without category instead of keypoint_category
>>> coco_kpts3 = [ub.map_keys(lambda x: x.replace('keypoint_', ''), d) for d in coco_kpts]
>>> Points.from_coco(coco_kpts3)
>>> #
>>> # Old style
>>> coco_kpts = [0, 0, 2, 0, 1, 2]
>>> Points.from_coco(coco_kpts)
>>> # Fail case
>>> coco_kpts4 = [{'xy': [4686.5, 1341.5], 'category': 'dot'}]
>>> Points.from_coco(coco_kpts4, classes=[])

Example

>>> # xdoctest: +REQUIRES(module:ndsampler)
>>> import ndsampler
>>> classes = ndsampler.CategoryTree.from_coco([
>>>     {'name': 'mouth', 'id': 2}, {'name': 'left-hand', 'id': 3}, {'name': 'right-hand', 'id': 5}
>>> ])
>>> coco_kpts = [
>>>     {'xy': (0, 0), 'visible': 2, 'keypoint_category_id': 5},
>>>     {'xy': (1, 2), 'visible': 2, 'keypoint_category_id': 2},
>>> ]
>>> pts = Points.from_coco(coco_kpts, classes=classes)
>>> assert pts.data['class_idxs'].tolist() == [2, 0]
class kwimage.structs.points.PointsList[source]

Bases: kwimage.structs._generic.ObjectList

Stores a list of Points, each item usually corresponds to a different object.

Notes

# TODO: when the data is homogenous we can use a more efficient # representation, otherwise we have to use heterogenous storage.