On this page
Per-label intensity measurements¶
Introduced in Inklet 3.1, measure_labels is available from inklet.volume.
Install the volume extra with
pip install "inklet[volume]>=4.3". The inklet.experimental import paths
used before 4.3 still work and return the same objects.
Measure original channel values on a native voxel grid or on one sampled plane. The returned table supplies plots, CSV exports and JSON provenance. Display windows, channel colors and composite clipping do not enter the calculation. See the real microscopy example for a complete figure.

The complete microscopy intensity example connects measured label tables to plots. Its recipe and data attribution are included there.
A complete example¶
import numpy as np
from inklet.volume import Volume, measure_labels
labels = Volume(np.array([[[17, 17, 0]]], dtype='uint64'),
(2, 3, 4), 'um', source_id='illustrative labels')
signal = Volume(np.array([[[2., 6., 99.]]]),
(2, 3, 4), 'um', source_id='illustrative signal')
table = measure_labels(labels, {'Signal': signal}, label_ids=[17, 42])
row = table.rows[0]
assert row['mean'] == 4 and row['std'] == 2
assert row['count'] == 2 and row['measure'] == 48
assert row['sum'] == 8 and row['integral'] == 192
assert table.rows[1]['mean'] is None # requested ID 42 is absent
csv_text = table.to_csv()
json_text = table.to_json()
Geometry and selection¶
measure_labels(labels, channels, *, label_ids=None, region=None,
coverage='intersection') accepts a nonempty mapping of channel names to data:
- An integer
Volumeof labels and channelVolumeobjects with exactly equal shapes, spacing, origins and units. Measurements use original voxel values. - A label
SampledSectionand intensity sections sharing exactly the samePlane. Measurements use the sampled floating-point values, with label and channel validity masks. Nearest-neighbour labels and interpolated intensities remain separate operations, recorded in the report.
Matching geometry does not verify image registration. Resample differing source volumes onto an explicitly shared plane before measuring them together. Slab projections, RGB composites and label sections used as intensity channels are rejected. A projected slab has no single label-bearing depth.
By default, all positive IDs present in the selected label domain are measured
in increasing order. Supply unique nonnegative Python integers in label_ids
to choose IDs, preserve a particular order, include background 0, or retain
absent IDs as empty rows. Negative selected IDs are rejected. Large uint64
identities are never converted through floating point or used to allocate an
array indexed by the largest ID.
An optional BoxRegion selects native voxel or output pixel centres using
lower-inclusive, upper-exclusive physical bounds. Selected voxels/pixels count
with their whole element volume/area; boundary elements are not fractionally
clipped. Regions must use the same units. Section area and native volume are
different measures and cannot be substituted for each other.
Missing samples and table fields¶
coverage='intersection' uses only samples available in every channel. This
provides matching measurement support across channels. 'per-channel' uses each
channel's own available samples; means can then describe different subsets.
Neither policy fills unavailable intensities with measured zeros.
Each row records one label and one channel:
| Field | Meaning |
|---|---|
label, label_id |
Integer identity and its exact decimal string |
selected_count |
Valid label samples after region selection, before channel coverage |
count, excluded_count |
Contributing samples and selected samples excluded by coverage |
coverage_fraction |
count / selected_count; null if there are no selected label samples |
mean, std |
Arithmetic mean and population standard deviation (ddof=0) |
minimum, maximum, sum |
Extrema and sum of contributing intensity values |
measure, measure_unit |
Contributing count × voxel volume (um^3, etc.) or pixel area (um^2, etc.) |
integral |
Intensity sum × element volume or area |
A row with zero contributing samples has null mean, spread and extrema, and
zero sum, measure and integral. This distinguishes no data from a measured zero.
report() and rows return fresh copies. to_json() includes channel/source
geometry, selection and statistics conventions; to_csv() writes a long-form
table. When opening CSV in a spreadsheet, import label_id as text to avoid
rounding large IDs. JSON consumers should also use label_id where their numeric
type cannot represent the integer exactly.
Intensity statistics use float64, including sums of integer-valued intensities;
they are not arbitrary-precision integer sums. Overflow is rejected. Population
SD describes sample spread, not a confidence interval, biological replication,
or an uncertainty estimate. The ImageJ measurement definitions
also distinguish mean intensity, intensity sums and area-scaled integrated
density. Inklet's integral uses the explicit physical element measure and
unmodified source intensity; it does not infer intensity calibration, background
correction, object completeness or colocalization. Retain segmentation methods
and boundary flags alongside the table, as the example does.