# Announcing Regions.jl — run-length encoded 2D regions for machine vision and image processing

**URL:** <https://discourse.julialang.org/t/announcing-regions-jl-run-length-encoded-2d-regions-for-machine-vision-and-image-processing/136961>\
**Category:** Package Announcements\
**Tags:** images, image-processing, juliaimages\
**Created:** [May 2, 2026, 1:31pm UTC](https://discourse.julialang.org/t/announcing-regions-jl-run-length-encoded-2d-regions-for-machine-vision-and-image-processing/136961 "2026-05-02T13:31:55Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![schrpe](https://avatars.discourse-cdn.com/v4/letter/s/f19dbf/32.png) [@schrpe](https://discourse.julialang.org/u/schrpe)\
**Post date:** [May 2, 2026, 1:31pm UTC](https://discourse.julialang.org/t/announcing-regions-jl-run-length-encoded-2d-regions-for-machine-vision-and-image-processing/136961/1 "2026-05-02T13:31:55Z")

</div>

I’m happy to announce **[Regions.jl](https://github.com/schrpe/Regions.jl)**, a package that introduces a first-class _region_ type for discrete 2D image analysis, now registered in the Julia General Registry.

### What is a region?

A region is a set of discrete 2D pixel positions represented as a **run-length encoding (RLE)**. Instead of storing or iterating over individual pixels, Regions.jl tracks contiguous vertical _runs_ of active pixels. This seemingly simple representation unlocks two major advantages for machine vision workflows:

- **Binary morphology without touching every pixel.** Dilation, erosion, and related operations work on runs rather than on the full image array, yielding substantial speedups — on sparse industrial images, typically **orders of magnitude faster** than pixel-array approaches.
- **Efficient blob analysis.** Connected-component labeling and shape feature extraction (area, centroid, bounding box, …) all exploit the run-length structure, so computation scales with the _number of runs_, not with the image area.

### Quick taste

```julia-auto
using Regions, Images, FileIO

img = load("test/gear.png")
region = binarize(img, px -> px < 0.9)
blob = argmax(area, components(region)) # pick the largest connected component

l, t, r, b = bounds(blob) # bounding box
cc, cr = centroid(blob) # area-weighted centroid

```

No manual pixel loops needed — the region abstraction takes care of the bookkeeping.

### Status

The package is at **v0.5.0** and is MIT-licensed. Feedback, bug reports, and contributions are very welcome!

- 📦 Install: `] add Regions`
- 📖 Docs: [Home · Regions.jl](https://schrpe.github.io/Regions.jl/dev/)
- 🐙 GitHub: [GitHub - schrpe/Regions.jl: Regions.jl defines a set of types and functions that model a discrete 2-dimensional region concept. · GitHub](https://github.com/schrpe/Regions.jl)

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [May 3, 2026, 6:01am UTC](https://discourse.julialang.org/t/announcing-regions-jl-run-length-encoded-2d-regions-for-machine-vision-and-image-processing/136961/2 "2026-05-03T06:01:49Z")

</div>

This looks really cool. Thank you for sharing.

Do Regions always start in column 1? As I read the docs, a Run is a starting row and a range of rows, and a Region is a vector or Runs. Why does the Region not have a starting column?

I think the [use of `Images.binarize`](https://schrpe.github.io/Regions.jl/dev/introduction/#Build-regions-by-segmentation) is borderline type piracy: If Images.jl defines a method with Function on the second argument, there will be a conflict. You can prevent this by wrapping the function in a struct, e.g. replace `binarize(img, px -> px > 0.5)` with `binarize(img, DefReg(px -> px > 0.5))` , where you define `DefReg` in Regions.jl as `struct DefReg fun::Function end`.

---

<div class="post-metadata">

**Author:** ![schrpe](https://avatars.discourse-cdn.com/v4/letter/s/f19dbf/32.png) [@schrpe](https://discourse.julialang.org/u/schrpe)\
**Post date:** [May 3, 2026, 7:46am UTC](https://discourse.julialang.org/t/announcing-regions-jl-run-length-encoded-2d-regions-for-machine-vision-and-image-processing/136961/3 "2026-05-03T07:46:27Z")

</div>

I’ve recently changed from row-major to column-major, and I might have missed something in the docs.

A Region consists of a sorted vector of Runs, each Run has a column and a range of rows; thus the starting column of a Region is the column of its first run.

Thanks for pointing out the binarize issue, i was feeling a bit uneasy also. I mean it is really doing the same thing and thus should be named the same. Maybe having both Images.binarize() and Regions.binarize() is not so bad, one would have to disambiguate with the module name. Still not decided what is the best solution.

A similar topic comes up with other names - like opening and closing - and here I have not yet captured the Images function.

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [May 3, 2026, 11:54am UTC](https://discourse.julialang.org/t/announcing-regions-jl-run-length-encoded-2d-regions-for-machine-vision-and-image-processing/136961/4 "2026-05-03T11:54:05Z")

</div>

> A Region consists of a sorted vector of Runs, each Run has a column and a range of rows; thus the starting column of a Region is the column of its first run.

Thank you, I was reading it wrong.
