Loading images

Many image data sets are too large to be loaded into memory entirely and need to be processed lazily. This is the main reason for using nuts-ml. Otherwise, pre-processing data sets via scikit-learn or NumPy is more efficient and simpler.

The common strategy in nuts-ml to deal with large image data is to use samples that contain image file paths and meta-data such as labels, and load images on demand. For instance, the ReadImage() nut reads images from a given path and returns Numpy arrays. Here a simple example

>>> samples = [('nut_color.jpg', 'color'), ('nut_grayscale.jpg', 'gray')]
>>> imagepath = 'tests/data/img_formats/*'
>>> samples >> ReadImage(0, imagepath) >> PrintColType() >> Consume()
item 0: <tuple>
  0: <ndarray> shape:213x320x3 dtype:uint8 range:0..248
  1: <str> color
item 1: <tuple>
  0: <ndarray> shape:213x320 dtype:uint8 range:18..235
  1: <str> gray

where samples are composed of the image filename and a (class) label (‘color’, ‘gray’). ReadImage(0, imagepath) takes a sample, extracts the image filename from column 0 of the sample, constructs the full file path by replacing * in imagepath by the image name, loads the image and replaces the image name by the actual image data.

Color images are loaded as Numpy array with shape (H, W, 3) and gray scale images with shape (H, W) both with data type uint8. In this example the images are of size 213x320(x3) and range list the smallest and largest value of the image – as printed by PrintColType().

PrintColType() displays the data types of sample columns. Here, the first sample (item 0) is a tuple and contains a Numpy array (the loaded image) in column 0 and the class label as a string in column 1. Similarly, the second sample (item 1) contains the loaded image as a Numpy array and the class label.

Sometimes it is useful to directly load images that are not part of a sample. Setting the column to None in ReadImage() enables this:

>>> images = ['nut_color', 'nut_grayscale']
>>> imagepath = 'tests/data/img_formats/*.jpg'
>>> images >> ReadImage(None, imagepath) >> PrintColType() >> Consume()
item 0: <tuple>
  0: <ndarray> shape:213x320x3 dtype:uint8 range:0..248
item 1: <tuple>
  0: <ndarray> shape:213x320 dtype:uint8 range:18..235

Note that ReadImage() still returns tuples with the image as element (<image>,) and not just the images.

Instead of providing a base image path and image file names within samples it is also possible to directly provide the full file path within the sample:

>>> images = ['tests/data/img_formats/nut_color.gif']
>>> images >> ReadImage(None) >> PrintColType() >> Consume()
item 0: <tuple>
  0: <ndarray> shape:213x320x3 dtype:uint8 range:0..255

Furthermore ReadImage() allows to read multiple images at the same time, e.g. for samples that contain an image and mask. In the following example we read color images and their gray-scale version as pairs

>>> samples = [('color.jpg', 'grayscale.jpg'), ('color.png', 'grayscale.png')]
>>> imagepath = 'tests/data/img_formats/nut_*'
>>> samples >> ReadImage((0,1), imagepath) >> PrintColType() >> Consume()
item 0: <tuple>
  0: <ndarray> shape:213x320x3 dtype:uint8 range:0..248
  1: <ndarray> shape:213x320 dtype:uint8 range:18..235
item 1: <tuple>
  0: <ndarray> shape:213x320x3 dtype:uint8 range:0..246
  1: <ndarray> shape:213x320 dtype:uint8 range:20..235

where ReadImage((0,1), ...) specifies that the image names are in columns 0 and 1 of the samples. Note that we moved the common prefix nut_ of the image file names to the image path.

The printout of PrintColType confirms that we loaded color images with 3 color channels (shape:213x320x3) and gray-scale images that have no channel axis (shape:213x320).

The next section will show how to display loaded images conveniently.