kwimage.im_color module

A class to make it easier to work with single colors.

class kwimage.im_color.Color(color, alpha=None, space=None, coerce=True)[source]

Bases: NiceRepr

Used for converting a single color between spaces and encodings. This should only be used when handling small numbers of colors(e.g. 1), don’t use this to represent an image.

Parameters:

space (str) – colorspace of wrapped color. Assume RGB if not specified and it cannot be inferred

CommandLine

xdoctest -m ~/code/kwimage/kwimage/im_color.py Color

Example

>>> print(Color('g'))
>>> print(Color('orangered'))
>>> print(Color('#AAAAAA').as255())
>>> print(Color([0, 255, 0]))
>>> print(Color([1, 1, 1.]))
>>> print(Color([1, 1, 1]))
>>> print(Color(Color([1, 1, 1])).as255())
>>> print(Color(Color([1., 0, 1, 0])).ashex())
>>> print(Color([1, 1, 1], alpha=255))
>>> print(Color([1, 1, 1], alpha=255, space='lab'))
Parameters:
  • color (Color | Iterable[int | float] | str) – something coercable into a color

  • alpha (float | None) – if psecified adds an alpha value

  • space (str) – The colorspace to interpret this color as. Defaults to rgb.

  • coerce (bool) – The exsting init is not lightweight. This is a design problem that will need to be fixed in future versions. Setting coerce=False will disable all magic and use imputed color and space args directly. Alpha will be ignored.

classmethod coerce(data, **kwargs)[source]
forimage(image, space='auto')[source]

Return a numeric value for this color that can be used in the given image.

Create a numeric color tuple that agrees with the format of the input image (i.e. float or int, with 3 or 4 channels).

Parameters:
  • image (ndarray) – image to return color for

  • space (str) – colorspace of the input image. Defaults to ‘auto’, which will choose rgb or rgba

Returns:

the color value

Return type:

Tuple[Number, …]

Example

>>> import kwimage
>>> img_f3 = np.zeros([8, 8, 3], dtype=np.float32)
>>> img_u3 = np.zeros([8, 8, 3], dtype=np.uint8)
>>> img_f4 = np.zeros([8, 8, 4], dtype=np.float32)
>>> img_u4 = np.zeros([8, 8, 4], dtype=np.uint8)
>>> kwimage.Color('red').forimage(img_f3)
(1.0, 0.0, 0.0)
>>> kwimage.Color('red').forimage(img_f4)
(1.0, 0.0, 0.0, 1.0)
>>> kwimage.Color('red').forimage(img_u3)
(255, 0, 0)
>>> kwimage.Color('red').forimage(img_u4)
(255, 0, 0, 255)
>>> kwimage.Color('red', alpha=0.5).forimage(img_f4)
(1.0, 0.0, 0.0, 0.5)
>>> kwimage.Color('red', alpha=0.5).forimage(img_u4)
(255, 0, 0, 127)
>>> kwimage.Color('red').forimage(np.uint8)
(255, 0, 0)
_forimage(image, space='rgb')[source]

backwards compat, deprecate

ashex(space=None)[source]

Convert to hex values

Parameters:

space (None | str) – if specified convert to this colorspace before returning

Returns:

the hex representation

Return type:

str

as255(space=None)[source]

Convert to byte values

Parameters:

space (None | str) – if specified convert to this colorspace before returning

Returns:

The uint8 tuple of color values between 0 and 255.

Return type:

Tuple[int, int, int] | Tuple[int, int, int, int]

as01(space=None)[source]

Convert to float values

Parameters:

space (None | str) – if specified convert to this colorspace before returning

Returns:

The float tuple of color values between 0 and 1

Return type:

Tuple[float, float, float] | Tuple[float, float, float, float]

Note

This function is only guarenteed to return 0-1 values for rgb values. For HSV and LAB, the native spaces are used. This is not ideal, and we may create a new function that fixes this - at least conceptually - and deprate this for that in the future.

For HSV, H is between 0 and 360. S, and V are in [0, 1]

classmethod _is_base01()[source]

check if a color is in base 01

classmethod _is_base255(channels)[source]

there is a one corner case where all pixels are 1 or less

classmethod _hex_to_01(hex_color)[source]

hex_color = ‘#6A5AFFAF’

_ensure_color01(color)[source]

Infer what type color is and normalize to 01

classmethod _255_to_01(color255)[source]

converts base 255 color to base 01 color

classmethod _string_to_01(color)[source]
classmethod named_colors()[source]
Returns:

names of colors that Color accepts

Return type:

List[str]

Example

>>> import kwimage
>>> named_colors = kwimage.Color.named_colors()
>>> color_lut = {name: kwimage.Color(name).as01() for name in named_colors}
>>> # xdoctest: +REQUIRES(module:kwplot)
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> # This is a very big table if we let it be, reduce it
>>> color_lut =dict(list(color_lut.items())[0:10])
>>> canvas = kwplot.make_legend_img(color_lut)
>>> kwplot.imshow(canvas)
_images/fig_kwimage_im_color_Color_named_colors_002.jpeg
classmethod distinct(num, existing=None, space='rgb', legacy='auto', exclude_black=True, exclude_white=True)[source]

Make multiple distinct colors.

The legacy variant is based on a stack overflow post [HowToDistinct], but the modern variant is based on the distinctipy package.

References

Todo

  • [ ] If num is more than a threshold we should switch to

    a different strategy to generating colors that just samples uniformly from some colormap and then shuffles. We have no hope of making things distinguishable when num starts going over 10 or so. See [ColorLimits] [WikiDistinguish] [Disinct2] for more ideas.

Returns:

list of distinct float color values

Return type:

List[Tuple]

Example

>>> # xdoctest: +REQUIRES(module:matplotlib)
>>> from kwimage.im_color import *  # NOQA
>>> import kwimage
>>> colors1 = kwimage.Color.distinct(5, legacy=False)
>>> colors2 = kwimage.Color.distinct(3, existing=colors1)
>>> # xdoctest: +REQUIRES(module:kwplot)
>>> # xdoctest: +REQUIRES(--show)
>>> from kwimage.im_color import _draw_color_swatch
>>> swatch1 = _draw_color_swatch(colors1, cellshape=9)
>>> swatch2 = _draw_color_swatch(colors1 + colors2, cellshape=9)
>>> import kwplot
>>> kwplot.autompl()
>>> kwplot.imshow(swatch1, pnum=(1, 2, 1), fnum=1)
>>> kwplot.imshow(swatch2, pnum=(1, 2, 2), fnum=1)
>>> kwplot.show_if_requested()
_images/fig_kwimage_im_color_Color_distinct_002.jpeg
classmethod random(pool='named', with_alpha=0, rng=None)[source]
Returns:

Color

distance(other, space='lab')[source]

Distance between self an another color

Parameters:
  • other (Color) – the color to compare

  • space (str) – the colorspace to comapre in

Returns:

float

interpolate(other, alpha=0.5, ispace=None, ospace=None)[source]

Interpolate between colors

Parameters:
  • other (Color) – A coercable Color

  • alpha (float | List[float]) – one or more interpolation values

  • ispace (str | None) – colorspace to interpolate in

  • ospace (str | None) – colorspace of returned color

Returns:

Color | List[Color]

Example

>>> import kwimage
>>> color1 = self = kwimage.Color.coerce('orangered')
>>> color2 = other = kwimage.Color.coerce('dodgerblue')
>>> alpha = np.linspace(0, 1, 6)
>>> ispace = 'rgb'
>>> ospace = 'rgb'
>>> colorBs = self.interpolate(other, alpha, ispace=ispace, ospace=ospace)
>>> # xdoctest: +REQUIRES(module:kwplot)
>>> # xdoctest: +REQUIRES(--show)
>>> from kwimage.im_color import _draw_color_swatch
>>> swatch_colors = [color1] + colorBs + [color2]
>>> print('swatch_colors = {}'.format(ub.urepr(swatch_colors, nl=1)))
>>> swatch1 = _draw_color_swatch(swatch_colors, cellshape=(8, 8))
>>> import kwplot
>>> kwplot.autompl()
>>> kwplot.imshow(swatch1, pnum=(1, 1, 1), fnum=1)
>>> kwplot.show_if_requested()
_images/fig_kwimage_im_color_Color_interpolate_002.jpeg
to_image(dsize=(8, 8))[source]

Create an solid-color image with this color

Parameters:

dsize (Tuple[int, int]) – the desired width / height of the image (defaults to 8x8)

adjust(saturate=0, lighten=0)[source]

Adjust the saturation or value of a color.

Requires that colormath is installed.

Parameters:
  • saturate (float) – between +1 and -1, when positive saturates the color, when negative desaturates the color.

  • lighten (float) – between +1 and -1, when positive lightens the color, when negative darkens the color.

Example

>>> # xdoctest: +REQUIRES(module:colormath)
>>> import kwimage
>>> self = kwimage.Color.coerce('salmon')
>>> new = self.adjust(saturate=+0.2)
>>> cell1 = self.to_image()
>>> cell2 = new.to_image()
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> canvas = kwimage.stack_images([cell1, cell2], axis=1)
>>> kwplot.imshow(canvas)
_images/fig_kwimage_im_color_Color_adjust_002.jpeg

Example

>>> # xdoctest: +REQUIRES(module:colormath)
>>> import kwimage
>>> self = kwimage.Color.coerce('salmon', alpha=0.5)
>>> new = self.adjust(saturate=+0.2)
>>> cell1 = self.to_image()
>>> cell2 = new.to_image()
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> canvas = kwimage.stack_images([cell1, cell2], axis=1)
>>> kwplot.imshow(canvas)
_images/fig_kwimage_im_color_Color_adjust_003.jpeg

Example

>>> # xdoctest: +REQUIRES(module:colormath)
>>> import kwimage
>>> adjustments = [
>>>     {'saturate': -0.2},
>>>     {'saturate': +0.2},
>>>     {'lighten': +0.2},
>>>     {'lighten': -0.2},
>>>     {'saturate': -0.9},
>>>     {'saturate': +0.9},
>>>     {'lighten': +0.9},
>>>     {'lighten': -0.9},
>>> ]
>>> self = kwimage.Color.coerce('kitware_green')
>>> dsize = (256, 64)
>>> to_show = []
>>> to_show.append(self.to_image(dsize))
>>> for kwargs in adjustments:
>>>     new = self.adjust(**kwargs)
>>>     cell = new.to_image(dsize=dsize)
>>>     text = ub.urepr(kwargs, compact=1, nobr=1)
>>>     cell, info = kwimage.draw_text_on_image(cell, text, return_info=1, border={'thickness': 2}, color='white', fontScale=1.0)
>>>     to_show.append(cell)
>>> # xdoctest: +REQUIRES(--show)
>>> # xdoctest: +REQUIRES(module:kwplot)
>>> import kwplot
>>> kwplot.autompl()
>>> canvas = kwimage.stack_images_grid(to_show)
>>> canvas = kwimage.draw_header_text(canvas, 'kwimage.Color.adjust')
>>> kwplot.imshow(canvas)
_images/fig_kwimage_im_color_Color_adjust_004.jpeg