imdilate
result =imdilate(img, radius)<br>imdilate(img, se=)
Input: img, radius · Output: result
What it is
img is a binary (0/255 mask-style) Image; radius is a positive integer, the half-width of a square structuring element of side 2*radius+1 (a documented choice over a disk element). Performs binary morphological dilation, growing foreground regions.
Overloads
2 forms. Each carries its own inputs, outputs and worked example — pick the tab for the one you are calling.
| Code | Input | Output | Description |
result = imdilate(img, radius) <br> imdilate(img, se=) | img Imageimg a binary (0/255) Image.radius —Dilation/erosion/opening/closing/top-hat/bottom-hat all reduce to their textbook binary definitions on a genuine mask: the foreground blob grows outward by radius, and every output pixel stays exactly 0 or 255 — no new grey levels ever appear. | Image —from disk()/line(), or hand-built | — |
Examples
Written for this form and run by the build -- the output below is what the engine actually produced.
mb = [0, 0, 0, 0, 0; 0, 0, 0, 0, 0; 0, 0, 255, 0, 0; 0, 0, 0, 0, 0; 0, 0, 0, 0, 0]
binary_img = image_from_matrix(mb)
grown = imdilate(binary_img, 1)
print(imhist(grown, n_bins=4)) # [16, 0, 0, 9] -- only the two extreme bins are ever used
[16, 0, 0, 9]
| Code | Input | Output | Description |
result = imdilate(img, radius) <br> imdilate(img, se=) | img Imageimg a genuine grayscale (or color) Image with more than two intensity levels.radius Imageradius is a positive integer, the half-width of a square structuring element of side 2*radius+1 (a documented choice over a disk element). | Image —from disk()/line(), or hand-built | imdilate/imerode/imopen/imclose/imtophat/imbothat are all implemented as a per-channel MAX (dilate) or MIN (erode) over the structuring window — true grayscale morphology, not "threshold then grow." Fed a smooth image, the intermediate grey levels shift around instead of snapping everything to black/white. |
Examples
Written for this form and run by the build -- the output below is what the engine actually produced.
mg = [10, 60, 110, 160, 210; 20, 70, 120, 170, 220; 30, 80, 130, 180, 230; 40, 90, 140, 190, 240; 50, 100, 150, 200, 250]
gray_img = image_from_matrix(mg)
grown = imdilate(gray_img, 1)
print(imhist(grown, n_bins=4)) # [0, 6, 7, 12] -- three separate bins in use, no black survives at all
[0, 6, 7, 12]
How it works
and foreground/background separation (§ blob-manipulation pass, 2026-08-24). See image::Image's own "Binary morphology..." doc-comment section for the full binary-mask convention this whole group shares: a Value::Image is treated as "binary" when every pixel is grayscale (R=G=B) with two intended levels, 0 = background / 255 = foreground (is_foreground actually reads >=128, so a slightly antialiased mask still behaves sanely). No threshold/ otsu_threshold builtin existed in this shared working tree when this landed (a sibling agent's own lane) — this is a documented, independent design choice, not a guess at matching code that hadn't landed yet; reconcile if the sibling's own producer ends up using a different convention. imerode(img, radius) / imdilate(img, radius) — a square structuring element of side 2*radius+1 (documented choice over a disk — see image::Image::erode's doc comment). Additive se= kwarg (§ SE/hit-miss/watershed pass, 2026-09-25): an explicit structuring-element mask Image (disk()/line(), or hand-built) in place of the radius-implied square — radius is simply not read at all when se= is given, so the old two-positional-argument form keeps working unchanged.
From the note above this builtin in the interpreter, where the reasoning was written down as it was built.