kwimage.im_core

Not sure how to best classify these functions

Module Contents

Functions

num_channels(img) Returns the number of color channels in an image
ensure_float01(img, dtype=np.float32, copy=True) Ensure that an image is encoded using a float32 properly
ensure_uint255(img, copy=True) Ensure that an image is encoded using a uint8 properly. Either
make_channels_comparable(img1, img2, atleast3d=False) Broadcasts image arrays so they can have elementwise operations applied
_alpha_fill_for(img) helper for make_channels_comparable
atleast_3channels(arr, copy=True) Ensures that there are 3 channels in the image
normalize(arr, mode=’linear’, alpha=None, beta=None, out=None) Rebalance pixel intensities via contrast stretching.
kwimage.im_core.num_channels(img)

Returns the number of color channels in an image

Parameters:img (ndarray) – an image with 2 or 3 dimensions.
Returns:the number of color channels (1, 3, or 4)
Return type:int

Example

>>> H = W = 3
>>> assert num_channels(np.empty((W, H))) == 1
>>> assert num_channels(np.empty((W, H, 1))) == 1
>>> assert num_channels(np.empty((W, H, 3))) == 3
>>> assert num_channels(np.empty((W, H, 4))) == 4
>>> # xdoctest: +REQUIRES(module:pytest)
>>> import pytest
>>> with pytest.raises(ValueError):
...     num_channels(np.empty((W, H, 2)))
kwimage.im_core.ensure_float01(img, dtype=np.float32, copy=True)

Ensure that an image is encoded using a float32 properly

Parameters:
  • img (ndarray) – an image in uint255 or float01 format. Other formats will raise errors.
  • dtype (type, default=np.float32) – a numpy floating type
  • copy (bool, default=False) – always copy if True, else copy if needed.
Returns:

an array of floats in the range 0-1

Return type:

ndarray

Raises:

ValueError – if the image type is integer and not in [0-255]

Example

>>> ensure_float01(np.array([[0, .5, 1.0]]))
array([[0. , 0.5, 1. ]], dtype=float32)
>>> ensure_float01(np.array([[0, 1, 200]]))
array([[0..., 0.0039..., 0.784...]], dtype=float32)
kwimage.im_core.ensure_uint255(img, copy=True)

Ensure that an image is encoded using a uint8 properly. Either

Parameters:
  • img (ndarray) – an image in uint255 or float01 format. Other formats will raise errors.
  • copy (bool, default=False) – always copy if True, else copy if needed.
Returns:

an array of bytes in the range 0-255

Return type:

ndarray

Raises:
  • ValueError – if the image type is float and not in [0-1]
  • ValueError – if the image type is integer and not in [0-255]

Example

>>> ensure_uint255(np.array([[0, .5, 1.0]]))
array([[  0, 127, 255]], dtype=uint8)
>>> ensure_uint255(np.array([[0, 1, 200]]))
array([[  0,   1, 200]], dtype=uint8)
kwimage.im_core.make_channels_comparable(img1, img2, atleast3d=False)

Broadcasts image arrays so they can have elementwise operations applied

Parameters:
  • img1 (ndarray) – first image
  • img2 (ndarray) – second image
  • atleast3d (bool, default=False) – if true we ensure that the channel dimension exists (only relevant for 1-channel images)

Example

>>> import itertools as it
>>> wh_basis = [(5, 5), (3, 5), (5, 3), (1, 1), (1, 3), (3, 1)]
>>> for w, h in wh_basis:
>>>     shape_basis = [(w, h), (w, h, 1), (w, h, 3)]
>>>     # Test all permutations of shap inputs
>>>     for shape1, shape2 in it.product(shape_basis, shape_basis):
>>>         print('*    input shapes: %r, %r' % (shape1, shape2))
>>>         img1 = np.empty(shape1)
>>>         img2 = np.empty(shape2)
>>>         img1, img2 = make_channels_comparable(img1, img2)
>>>         print('... output shapes: %r, %r' % (img1.shape, img2.shape))
>>>         elem = (img1 + img2)
>>>         print('... elem(+) shape: %r' % (elem.shape,))
>>>         assert elem.size == img1.size, 'outputs should have same size'
>>>         assert img1.size == img2.size, 'new imgs should have same size'
>>>         print('--------')
kwimage.im_core._alpha_fill_for(img)

helper for make_channels_comparable

kwimage.im_core.atleast_3channels(arr, copy=True)

Ensures that there are 3 channels in the image

Parameters:
  • arr (ndarray[N, M, …]) – the image
  • copy (bool) – Always copies if True, if False, then copies only when the size of the array must change.
Returns:

with shape (N, M, C), where C in {3, 4}

Return type:

ndarray

Doctest:
>>> assert atleast_3channels(np.zeros((10, 10))).shape[-1] == 3
>>> assert atleast_3channels(np.zeros((10, 10, 1))).shape[-1] == 3
>>> assert atleast_3channels(np.zeros((10, 10, 3))).shape[-1] == 3
>>> assert atleast_3channels(np.zeros((10, 10, 4))).shape[-1] == 4
kwimage.im_core.normalize(arr, mode='linear', alpha=None, beta=None, out=None)

Rebalance pixel intensities via contrast stretching.

By default linearly stretches pixel intensities to minimum and maximum values.

Parameters:
  • arr (ndarray) – array to normalize, usually an image
  • out (ndarray | None) – output array. Note, that we will create an internal floating point copy for integer computations.
  • mode (str) – either linear or sigmoid.
  • alpha (float) – Only used if mode=sigmoid. Division factor (pre-sigmoid). If unspecified computed as: max(abs(old_min - beta), abs(old_max - beta)) / 6.212606. Note this parameter is sensitive to if the input is a float or uint8 image.
  • beta (float) – subtractive factor (pre-sigmoid). This should be the intensity of the most interesting bits of the image, i.e. bring them to the center (0) of the distribution. Defaults to (max - min) / 2. Note this parameter is sensitive to if the input is a float or uint8 image.

References

https://en.wikipedia.org/wiki/Normalization_(image_processing)

Example

>>> raw_f = np.random.rand(8, 8)
>>> norm_f = normalize(raw_f)
>>> raw_f = np.random.rand(8, 8) * 100
>>> norm_f = normalize(raw_f)
>>> assert np.isclose(norm_f.min(), 0)
>>> assert np.isclose(norm_f.max(), 1)
>>> raw_u = (np.random.rand(8, 8) * 255).astype(np.uint8)
>>> norm_u = normalize(raw_u)

Example

>>> from kwimage.im_core import *  # NOQA
>>> import kwimage
>>> arr = kwimage.grab_test_image('lowcontrast')
>>> arr = kwimage.ensure_float01(arr)
>>> norms = {}
>>> norms['arr'] = arr.copy()
>>> norms['linear'] = normalize(arr, mode='linear')
>>> norms['sigmoid'] = normalize(arr, mode='sigmoid')
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> kwplot.figure(fnum=1, doclf=True)
>>> pnum_ = kwplot.PlotNums(nSubplots=len(norms))
>>> for key, img in norms.items():
>>>     kwplot.imshow(img, pnum=pnum_(), title=key)
Benchmark:

# Our method is faster than standard in-line implementations.

import timerit ti = timerit.Timerit(100, bestof=10, verbose=2, unit=’ms’) arr = kwimage.grab_test_image(‘lowcontrast’, dsize=(512, 512))

print(‘— uint8 —’) arr = ensure_float01(arr) out = arr.copy() for timer in ti.reset(‘naive1-float’):

with timer:
(arr - arr.min()) / (arr.max() - arr.min())

import timerit for timer in ti.reset(‘simple-float’):

with timer:
max_ = arr.max() min_ = arr.min() result = (arr - min_) / (max_ - min_)
for timer in ti.reset(‘normalize-float’):
with timer:
normalize(arr)
for timer in ti.reset(‘normalize-float-inplace’):
with timer:
normalize(arr, out=out)

print(‘— float —’) arr = ensure_uint255(arr) out = arr.copy() for timer in ti.reset(‘naive1-uint8’):

with timer:
(arr - arr.min()) / (arr.max() - arr.min())

import timerit for timer in ti.reset(‘simple-uint8’):

with timer:
max_ = arr.max() min_ = arr.min() result = (arr - min_) / (max_ - min_)
for timer in ti.reset(‘normalize-uint8’):
with timer:
normalize(arr)
for timer in ti.reset(‘normalize-uint8-inplace’):
with timer:
normalize(arr, out=out)
Ignore:
globals().update(xdev.get_func_kwargs(normalize))