delayed_image.delayed_leafs module

Terminal nodes

class delayed_image.delayed_leafs.DelayedImageLeaf(subdata=None, dsize=None, channels=None)[source]

Bases: DelayedImage

Parameters:
  • subdata (DelayedArray)

  • dsize (None | Tuple[int | None, int | None]) – overrides subdata dsize

  • channels (None | int | FusedChannelSpec) – overrides subdata channels

get_transform_from_leaf()[source]

Returns the transformation that would align data with the leaf

Returns:

kwimage.Affine

optimize()[source]
class delayed_image.delayed_leafs.DelayedLoad(fpath, channels=None, dsize=None, nodata_method=None)[source]

Bases: DelayedImageLeaf

Points to an image on disk to be loaded.

This is the starting point for most delayed operations. Disk IO is avoided until the finalize operation is called. Calling prepare can read image headers if metadata like the image width, height, and number of channels is not provided, but most operations can be performed while these are still unknown.

If a gdal backend is available, and the underlying image is in the appropriate formate (e.g. COG), finalize will return a lazy reference that enables fast overviews and crops. For image formats that do not allow for tiling / overviews, then there is no way to avoid reading entire image as an ndarray.

Example

>>> from delayed_image import *  # NOQA
>>> self = DelayedLoad.demo(dsize=(16, 16)).prepare()
>>> data1 = self.finalize()

Example

>>> # xdoctest: +REQUIRES(module:osgeo)
>>> # Demo code to develop support for overviews
>>> from delayed_image import *  # NOQA
>>> import kwimage
>>> import ubelt as ub
>>> fpath = kwimage.grab_test_image_fpath(overviews=3)
>>> self = DelayedLoad(fpath, channels='r|g|b').prepare()
>>> print(f'self={self}')
>>> print('self.meta = {}'.format(ub.repr2(self.meta, nl=1)))
>>> quantization = {
>>>     'quant_max': 255,
>>>     'nodata': 0,
>>> }
>>> node0 = self
>>> node1 = node0.get_overview(2)
>>> node2 = node1[13:900, 11:700]
>>> node3 = node2.dequantize(quantization)
>>> node4 = node3.warp({'scale': 0.05})
>>> #
>>> data0 = node0._validate().finalize()
>>> data1 = node1._validate().finalize()
>>> data2 = node2._validate().finalize()
>>> data3 = node3._validate().finalize()
>>> data4 = node4._validate().finalize()
>>> node4.write_network_text()

Example

>>> # xdoctest: +REQUIRES(module:osgeo)
>>> # Test delayed ops with int16 and nodata values
>>> from delayed_image import *  # NOQA
>>> import kwimage
>>> from delayed_image.helpers import quantize_float01
>>> import ubelt as ub
>>> dpath = ub.Path.appdir('delayed_image/tests/test_delay_nodata').ensuredir()
>>> fpath = dpath / 'data.tif'
>>> data = kwimage.ensure_float01(kwimage.grab_test_image())
>>> poly = kwimage.Polygon.random(rng=321032).scale(data.shape[0])
>>> poly.fill(data, np.nan)
>>> data_uint16, quantization = quantize_float01(data)
>>> nodata = quantization['nodata']
>>> kwimage.imwrite(fpath, data_uint16, nodata=nodata, backend='gdal', overviews=3)
>>> # Test loading the data
>>> self = DelayedLoad(fpath, channels='r|g|b', nodata_method='float').prepare()
>>> node0 = self
>>> node1 = node0.dequantize(quantization)
>>> node2 = node1.warp({'scale': 0.51}, interpolation='lanczos')
>>> node3 = node2[13:900, 11:700]
>>> node4 = node3.warp({'scale': 0.9}, interpolation='lanczos')
>>> node4.write_network_text()
>>> node5 = node4.optimize()
>>> node5.write_network_text()
>>> node6 = node5.warp({'scale': 8}, interpolation='lanczos').optimize()
>>> node6.write_network_text()
>>> #
>>> data0 = node0._validate().finalize()
>>> data1 = node1._validate().finalize()
>>> data2 = node2._validate().finalize()
>>> data3 = node3._validate().finalize()
>>> data4 = node4._validate().finalize()
>>> data5 = node5._validate().finalize()
>>> data6 = node6._validate().finalize()
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> stack1 = kwimage.stack_images([data1, data2, data3, data4, data5])
>>> stack2 = kwimage.stack_images([stack1, data6], axis=1)
>>> kwplot.imshow(stack2)
Parameters:
  • fpath (str | PathLike) – URI pointing at the image data to load

  • channels (int | str | FusedChannelSpec | None) – the underlying channels of the image if known a-priori

  • dsize (Tuple[int, int]) – The width / height of the image if known a-priori

  • nodata_method (str | None) – How to handle nodata values in the file itself. Can be “auto”, “float”, or “ma”.

property fpath
classmethod demo(key='astro', channels=None, dsize=None, nodata_method=None, overviews=None)[source]

Creates a demo DelayedLoad node that points to a file generated by kwimage.grab_test_image_fpath().

If metadata like dsize and channels are not provided, then the prepare() can be used to auto-populate them at the cost of the disk IO to read image headers.

Parameters:
  • key (str) – which test image to grab. Valid choices are: astro - an astronaught carl - Carl Sagan paraview - ParaView logo stars - picture of stars in the sky

  • channels (str) – if specified, these channels will be stored in the delayed load metadata. Note: these are not auto-populated. Usually the key corresponds to 3-channel data,

  • dsize (None | Tuple[int, int]) – if specified, we will return a variant of the data with the specific dsize

  • nodata_method (str | None) – How to handle nodata values in the file itself. Can be “auto”, “float”, or “ma”.

  • overviews (None | int) – if specified, will return a variant of the data with overviews

Returns:

DelayedLoad

Example

>>> from delayed_image.delayed_leafs import *  # NOQA
>>> import delayed_image
>>> delayed = delayed_image.DelayedLoad.demo()
>>> print(f'delayed={delayed}')
>>> delayed.prepare()
>>> print(f'delayed={delayed}')
>>> delayed = DelayedLoad.demo(channels='r|g|b', nodata_method='float')
>>> print(f'delayed={delayed}')
>>> delayed.prepare()
>>> print(f'delayed={delayed}')
>>> delayed.finalize()
prepare()[source]

If metadata is missing, perform minimal IO operations in order to prepopulate metadata that could help us better optimize the operation tree.

Returns:

DelayedLoad

class delayed_image.delayed_leafs.DelayedNans(dsize=None, channels=None)[source]

Bases: DelayedImageLeaf

Constructs nan channels as needed

Example

self = DelayedNans((10, 10), channel_spec.FusedChannelSpec.coerce(‘rgb’)) region_slices = (slice(5, 10), slice(1, 12)) delayed = self.crop(region_slices)

Example

>>> from delayed_image.delayed_leafs import *  # NOQA
>>> from delayed_image import DelayedChannelConcat
>>> dsize = (307, 311)
>>> c1 = DelayedNans(dsize=dsize, channels='foo')
>>> c2 = DelayedLoad.demo('astro', dsize=dsize, channels='R|G|B').prepare()
>>> cat = DelayedChannelConcat([c1, c2])
>>> warped_cat = cat.warp({'scale': 1.07}, dsize=(328, 332))._validate()
>>> warped_cat._validate().optimize().finalize()
class delayed_image.delayed_leafs.DelayedNodata(dsize=None, channels=None, nodata_method='float')[source]

Bases: DelayedNans

Constructs nan or masked array depending on what is needed

Example

>>> from delayed_image.delayed_leafs import *  # NOQA
>>> dsize = (307, 311)
>>> self1 = DelayedNodata(dsize=dsize, channels='foo', nodata_method='float')
>>> self2 = DelayedNodata(dsize=dsize, channels='foo', nodata_method='ma')
>>> im1 = self1.finalize()
>>> im2 = self2.finalize()
>>> assert im1.dtype.kind == 'f'
>>> assert not hasattr(im1, 'mask')
>>> assert hasattr(im2, 'mask')
class delayed_image.delayed_leafs.DelayedIdentity(data, channels=None, dsize=None)[source]

Bases: DelayedImageLeaf

Returns an ndarray as-is

Example

self = DelayedNans((10, 10), channel_spec.FusedChannelSpec.coerce(‘rgb’)) region_slices = (slice(5, 10), slice(1, 12)) delayed = self.crop(region_slices)

Example

>>> from delayed_image import *  # NOQA
>>> arr = kwimage.checkerboard()
>>> self = DelayedIdentity(arr, channels='gray')
>>> warp = self.warp({'scale': 1.07})
>>> warp.optimize().finalize()