Draw an instance map over its image

Description

One colour per object, chosen so that no two touching objects share one. The rule is adjacency rather than identity: a colour repeats across the picture and never between neighbours, because nobody reads object 214 by its colour and everybody needs to see where one object ends.

Usage

overlay_instances(
  image,
  labels,
  alpha = drawing_style()\$overlay_alpha,
  outline = FALSE,
  colours = drawing_style()\$class_colours
)

Arguments

image One image: height x width x 3, height x width x 1 or a matrix. Values may be 0-1 or 0-255.
labels An instance label map - one integer per object, 0 for background. Not a one-hot array: an object identity cannot be carried by a channel.
alpha How much of the tint shows. Ignored when outline is true, where the stroke is drawn at full strength, because a translucent outline is a smudge.
outline Draw one stroke per object instead of filling it, which leaves the tissue entirely visible and is what a pathologist is used to.
colours The palette to take slots from. Eight by default, mirrored from the engine’s own. A picture needing more colours than this has warns, naming how many it needs and how many objects lost the guarantee: the slot wraps onto a colour a neighbour already holds - provably, since it is only past the end once every colour before it was taken by a neighbour - so two touching objects are drawn as one and this figure answers its own question wrongly. The engine warns in the same words, which is checked rather than claimed. Unreachable on anything measured: the hardest of 670 Data Science Bowl cases needs three of the eight.

Details

That is an exact graph colouring, and it is affordable rather than clever. Measured over all 670 Data Science Bowl cases: the hardest needs three colours and class_colours has eight, while the cheap alternative - colour by object number, modulo the palette - draws one touching pair in ten as a single object.

Eight-connected, so two objects meeting at a corner get different colours. A label-maker goes the other way and joins only along edges, because there the risk is merging two objects into one; here the risk is drawing two as one, which is the opposite direction.

Value

A height x width x 3 array of integers, 0-255.

See Also

overlay_instance_agreement() for whether the objects are the right ones, overlay_mask() for classes rather than objects.

Examples

library("rplatypus")

image <- array(0.5, dim = c(5, 9, 3))
labels <- matrix(0L, nrow = 5, ncol = 9)
labels[2:4, 2:4] <- 1L
labels[2:4, 5:7] <- 2L   # touching object 1 along a seam
shown <- overlay_instances(image, labels)
# Two touching objects, two colours.
!identical(shown[3, 2, ], shown[3, 6, ])
[1] TRUE