Qu

otsu_threshold

Builtin index · Images

result = otsu_threshold(x)

Input: x · Output: result

What it is

x is an Image, Vec, or Signal. Computes (does not apply) the classic Otsu optimal threshold from x's histogram (Image reads per-pixel luma; Vec/Signal read their own values).

Overloads

One call shape — this function is not overloaded.

CodeInputOutputDescription
result = otsu_threshold(x)
x Image, Vec, or Signalnot documented yet
result number
Returns a single number, the threshold level. Compose with threshold(x, otsu_threshold(x)) to segment.

Examples

From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.

# Three bright discs on a dark field, written out and read back. The blob

# count printed below is then checkable against an image the reader can

# see being built, rather than asserted about a file nobody has.

n = 60
field = zeros(n, n)
centres = [15, 15; 42, 20; 30, 45]
for i in 0 to n - 1
    for j in 0 to n - 1
        for k in 0 to 2
            dy = i - centres[k, 0]
            dx = j - centres[k, 1]
            if dy * dy + dx * dx < 64
                field[i, j] = 230
            end if
        end for
    end for
end for
save_image("cells.bmp", image_from_matrix(field))

img = load_image("cells.bmp")
level = otsu_threshold(img)
mask = threshold(img, level)
clean = bwareaopen(mask, 20)          # drop specks smaller than 20 px

imshow(clean)

labeled = bwlabel(clean)
print(labeled.count)                  # number of detected blobs


stats = regionprops(labeled)
for i = 1 to labeled.count
    r = stats[i - 1]
    print(r.label, r.area, r.centroid_x, r.centroid_y)
end for
output
3
1 193 15 15
2 193 45 30
3 193 20 42

from images

How it works

otsu_threshold(x) — computes (does NOT apply) the classic Otsu optimal threshold: Image reads its per-pixel BT.601 luma histogram; Vec/Signal read their own value histogram. A pure compute step, meant to compose with threshold(x, otsu_threshold(x)) to actually segment — see qu_core::threshold::otsu_threshold's doc comment for the algorithm itself. otsu(x) below is the compute+apply convenience for when the scalar threshold isn't needed on its own.

From the note above this builtin in the interpreter, where the reasoning was written down as it was built.