Skip to content

Geometry

API reference for geometry operations on contours and points.

Schemas

POINT_SCHEMA

from polars_cv import POINT_SCHEMA

# Struct({x: Float64, y: Float64})

BBOX_SCHEMA

from polars_cv import BBOX_SCHEMA

# Struct({x: Float64, y: Float64, width: Float64, height: Float64})

CONTOUR_SCHEMA

from polars_cv import CONTOUR_SCHEMA

# Struct({
#     exterior: List({x: Float64, y: Float64}),
#     holes: List(List({x: Float64, y: Float64})),
#     is_closed: Boolean
# })

The holes field is the only thing that makes a ring a hole. Point order is never read as a hole signal, and no operation requires a particular winding — area, centroid, contains_point, iou, dice and rasterization all give the same answer whichever way each ring is wound.

The region a contour describes is its exterior minus the union of its hole rings. Overlapping rings are not subtracted twice, and a ring nested inside another hole remains a hole. Winding is reported by .contour.winding() and set by .contour.ensure_winding(), and is consulted nowhere else.

is_closed=False makes a contour an open polyline, measured as a line by the boundary functions and refused by the region ones (see Open polylines); an unspecified is_closed reads as closed. Rings are implicitly closed, so do not repeat the first point at the end.

Other schemas

Name Type What it holds
RING_SCHEMA List(POINT_SCHEMA) One ring: the exterior field, or one entry of holes
CONTOUR_SET_SCHEMA List(CONTOUR_SCHEMA) Several contours per row, as extract_contours returns
POINT_SET_SCHEMA List(POINT_SCHEMA) Several points per row (keypoints, landmarks)
ANNOTATED_POINT_SCHEMA Struct({x, y, label: String, confidence: Float64}) A point with a label and score
CORRESPONDENCE_SCHEMA Struct({right_idx: List(UInt32), overlap: List(Float64), duplicate: List(Boolean)}) What .contour.correspond() / .bbox.correspond() return, each list aligned with the left set

All are importable from polars_cv and polars_cv.geometry.

Helper Functions

from polars_cv.geometry.schemas import contour_from_points

contour = contour_from_points([
    (10, 10), (10, 90), (90, 90), (90, 10)
])

Per-Row Parameters and Nulls

Parameters on all three namespaces accept a pl.Expr as well as a literal, resolved per row — numbers, and the enums and flags too, since eligibility is decided by whether a value changes the output shape, rank or dtype rather than by its type. A null in such a column raises by default; on_null("null") — shared by .contour, .point and .bbox — yields null for the affected rows instead:

df.with_columns(
    norm=pl.col("contour").contour.on_null("null").normalize(pl.col("w"), 100)
)

on_null() returns a copy of the accessor with the policy applied and chains ahead of the call, so it never appears in a method signature. The .cv namespace has no equivalent: its parameters belong to a Pipeline, so the control there is Pipeline.on_null_param(). See Geometry Operations for which parameters are per-row.

on_error("null"), chained the same way, nulls a row whose data the function refuses (e.g. close_along_border on a line that does not reach the frame) instead of failing the query; an error about the column itself (its arity or dtype) still raises. See Invalid rows.

ContourNamespace

Bases: _ContourOpsMixin, _GeomNamespace

Namespace for geometric operations on contour columns.

One contour per row or a set of them — every accessor takes both. A column may be a CONTOUR_SCHEMA struct per row, or the CONTOUR_SET_SCHEMA list of them that extract_contours() produces. The two are told apart by the column's dtype, and the result is wrapped to match: an accessor returning Float64 for a single contour returns List(Float64) for a set, one entry per contour, in input order.

Two-operand accessors (:meth:iou, :meth:dice, :meth:hausdorff_distance) broadcast: a set on one side and a single contour on the other gives one result per contour in the set, whichever side the set is on. A set on both sides is rejected rather than guessed — it could mean the N×M matrix (:meth:pairwise_iou) or an index-wise pairing (.explode() one side), and the two mean different things.

The set-level accessors (:meth:pairwise_iou, :meth:correspond, :meth:label_reduce) work the other way round for the same reason: a lone contour is read as a set of one.

Numeric parameters accept either a literal or a Polars expression; an expression is resolved per row at execution time. A per-row parameter applies to every contour in that row's set — parameters vary by row, not by contour.

Example

df.with_columns( ... area=pl.col("contour").contour.area(), ... bbox=pl.col("contour").contour.bounding_box(), ... norm=pl.col("contour").contour.normalize( ... pl.col("img_w"), pl.col("img_h") ... ), ... )

A set column: one area per contour, per row.

df.with_columns(areas=pl.col("contours").contour.area())

on_null

on_null(policy: str) -> _Policy

Set what a null in a per-row expression parameter means.

These namespaces have no Pipeline object to hang a graph-level setting on, so the policy lives on the accessor itself and chains ahead of the call::

pl.col("c").contour.on_null("null").normalize(pl.col("w"), 100)
  • "raise" (default): a null parameter fails the expression.
  • "null": rows whose parameter is null yield null, matching how a null input geometry is already handled.

For a fallback value instead, fill the null in the expression itself — pl.col("w").fill_null(1.0).

The .cv namespace deliberately has no on_null; its equivalent is Pipeline.on_null_param.

Parameters:

Name Type Description Default
policy str

One of "raise", "null".

required

Returns:

Type Description
_Policy

A copy of this namespace with the policy applied. The original is

_Policy

unchanged, matching Pipeline's immutable-builder convention.

on_error

on_error(policy: str) -> _Policy

Set what a row whose data the function refuses means.

The accessors' counterpart of source(on_error=...): a row error — an open line too far from the frame to close, an open contour given to an area, a zero normalize size — fails the expression by default. Under "null" that row is null and the others proceed, so the invalid rows can be counted and inspected::

pl.col("line").contour.on_error("null").close_along_border(w, h)

An error about the column rather than a row — a contour set where one contour per row is expected, a dtype no reader understands — still raises: no row could succeed, and nulling it would null them all.

Parameters:

Name Type Description Default
policy str

One of "raise", "null".

required

Returns:

Type Description
_Policy

A copy of this namespace with the policy applied.

area

area(*, signed: BoolOrExpr = False) -> pl.Expr

Compute the area of the contour using the Shoelace formula.

The area of the region the contour describes: the exterior minus the union of its hole rings, in either winding direction. Overlapping or nested hole rings are not double-subtracted. One value per contour for a contour set.

Parameters:

Name Type Description Default
signed BoolOrExpr

If True, return signed area (negative for CW winding).

False

boundary

boundary() -> pl.Expr

A region's rings as open lines: the exterior, then each hole, each returning to its first point. The result is a set (holes add rings); an open contour, already a line, is refused.

boundary_distances

boundary_distances(
    other: Expr,
    *,
    sample_step: FloatOrExpr | None = None,
    frame: Expr | None = None,
) -> pl.Expr

Point-to-edge boundary distances to another contour, both directions.

Each boundary is sampled — its vertices, plus a point every sample_step along each edge when given — and every sample is measured to the edges of the other contour, so two tracings of one outline at different vertex densities are distance zero apart. Open contours (is_closed=False) are measured as polylines, without a closing edge. For a physical unit, .contour.scale(sx, sy, origin="origin") both sides by the pixel spacing first (anisotropic spacing included). A contour with no vertices gives null.

An object cut off by the image edge has a frame segment in its outline that an annotation of it does not trace. With frame (a bbox per row, e.g. {x: 0, y: 0, width: w, height: h}), boundary on the frame's edges or outside it is not measured: those samples are dropped from both directions. Each remaining sample is measured to the other side's whole boundary, so distances stay continuous as boundary approaches the edge (an annotation 1 px inside it is 1 px away). To also skip boundary near the edge, inset the frame (x: 1, width: w - 2 skips the outermost pixel). Nothing left inside the frame gives null.

Parameters:

Name Type Description Default
other Expr

Another contour column to compare with.

required
sample_step FloatOrExpr | None

Spacing of the points sampled along every edge, > 0; None samples the vertices only (literal or expression).

None
frame Expr | None

A bbox column, the image frame: boundary not strictly inside it is not measured. A null frame row gives null.

None

Returns:

Type Description
Expr

Struct{mean_a_to_b, mean_b_to_a, assd, hd, hd95} (Float64):

Expr

the directed means, the average symmetric surface distance (mean

Expr

over both sample sets), the Hausdorff distance (largest sample

Expr

distance) and the larger directed 95th percentile (linear

Expr

interpolation; MONAI's percentile=95) — a List of them when

Expr

either side is a contour set.

bounding_box

bounding_box() -> pl.Expr

Compute the axis-aligned bounding box of the contour.

Returns [x, y, width, height].

centroid

centroid() -> pl.Expr

Compute the centroid (center of mass) of the contour.

Measured on the same region as area() — the exterior minus the union of the hole rings — so overlapping or nested holes are not subtracted twice.

Returns [x, y].

close

close() -> pl.Expr

Join an open line's ends into the region it bounds. A line that returns to its first point (as boundary() draws one) drops the repeat, so close() undoes boundary() on a region without holes. A closed contour is refused.

close_along_border

close_along_border(
    width: FloatOrExpr,
    height: FloatOrExpr,
    *,
    arc: str | Expr = "shortest",
    max_snap: FloatOrExpr = 2.0,
) -> pl.Expr

Close an open line whose ends lie on the image frame into a region, along the frame.

A region annotated only by its boundary — a pectoral muscle edge from the top edge to the chest-wall edge, a skin line — becomes the region it bounds: each end is snapped onto its nearest frame edge, then the frame is walked from the line's last point back to its first, arc deciding which way round, through every corner it passes. A straight chord would drop a corner region entirely. The input must be open (is_closed=False); an end farther than max_snap from the frame is refused rather than joined.

Parameters:

Name Type Description Default
width FloatOrExpr

Image width: the frame is [0, width] x [0, height] (literal or expression).

required
height FloatOrExpr

Image height (literal or expression).

required
arc str | Expr

"shortest", "clockwise" or "counterclockwise" (as displayed, y down), from the line's end back to its start (literal or expression).

'shortest'
max_snap FloatOrExpr

The farthest an end may lie from the frame to be snapped onto it, in pixels (literal or expression).

2.0

Returns:

Type Description
Expr

A closed contour — a List of them for a contour set.

contains_point

contains_point(point: Expr) -> pl.Expr

Test if contour contains a point.

Parameters:

Name Type Description Default
point Expr

Point column to test.

required

Returns:

Type Description
Expr

Boolean indicating if point is inside contour — List(Boolean), one

Expr

per contour, for a contour-set column.

convex_hull

convex_hull() -> pl.Expr

Compute the convex hull of the contour.

correspond

correspond(
    other: Expr,
    *,
    threshold: FloatOrExpr = 0.5,
    order: Expr | None = None,
) -> pl.Expr

Pair each contour with at most one contour in other, by overlap.

Greedy and exclusive: contours are visited in order and each takes the highest-IoU partner not already taken, keeping it only if that IoU is at least threshold. A partner claimed earlier is unavailable later, so the order is what resolves contention. Exact ties go to the lowest index in other; the threshold bound is inclusive.

The relation carries no interpretation. Contours can represent anything, and whether a pairing means a "detection" is the caller's business -- as is deriving order from confidence, and counting pairings across a population.

Parameters:

Name Type Description Default
other Expr

Contour-set expression to pair against (List[Contour]).

required
threshold FloatOrExpr

Minimum IoU for a pairing, in [0, 1]. Accepts a Polars expression for a per-row threshold.

0.5
order Expr | None

Optional per-row list of indices giving the visit sequence, a permutation of 0..n. Defaults to natural order.

None

Returns:

Type Description
Expr

A struct matching :data:polars_cv.CORRESPONDENCE_SCHEMA:

Expr

right_idx (index into other, null where unpaired) and

Expr

overlap (the IoU of the chosen pair, 0.0 where unpaired) and

Expr

duplicate (unpaired, but cleared the threshold against a

Expr

contour another one had already claimed), all positionally aligned

Expr

with this expression's contours.

correspond_by_coverage

correspond_by_coverage(
    other: Expr,
    tolerance: FloatOrExpr,
    *,
    threshold: FloatOrExpr = 0.5,
    order: Expr | None = None,
    sample_step: FloatOrExpr | None = None,
) -> pl.Expr

Pair each contour with at most one contour in other, by coverage.

The rule of :meth:correspond — greedy, exclusive, visited in order, the threshold inclusive — over a different score: the fraction of each other contour's boundary samples that lie inside this contour (when closed) or within tolerance of its edges. That scores line-shaped targets, such as a polyline annotation, which IoU cannot: a polyline has no area. Open contours are read as polylines on both sides.

Parameters:

Name Type Description Default
other Expr

Contour-set expression to pair against (List[Contour]).

required
tolerance FloatOrExpr

How far from this contour a target sample still counts as covered, in pixels, >= 0 (literal or expression).

required
threshold FloatOrExpr

Minimum coverage for a pairing, in [0, 1] (literal or expression).

0.5
order Expr | None

Optional per-row visit order, a permutation of 0..n.

None
sample_step FloatOrExpr | None

Spacing of the samples taken along each target edge, > 0; None samples its vertices only (literal or expression).

None

Returns:

Type Description
Expr

A struct matching :data:polars_cv.CORRESPONDENCE_SCHEMA, with

Expr

overlap the coverage of the chosen pair.

densify

densify(max_segment_length: FloatOrExpr) -> pl.Expr

Add points so no edge is longer than max_segment_length: each edge is split into ceil(length / max_segment_length) equal parts, and every existing point is kept. A region's closing edges are split too.

Parameters:

Name Type Description Default
max_segment_length FloatOrExpr

The longest edge allowed, a finite length > 0 (literal or expression).

required

dice

dice(other: Expr) -> pl.Expr

Compute Dice coefficient with another contour.

Dice = 2 * intersection / (area1 + area2)

Parameters:

Name Type Description Default
other Expr

Another contour column to compare with.

required

Returns:

Type Description
Expr

Float64 Dice coefficient in [0, 1] — List(Float64) when either

Expr

side is a contour set.

difference

difference(other: Expr) -> pl.Expr

Inside this set and not other: this contour set's regions with other's cut away.

Each side is read as the union of its set (a single contour is a set of one), and the result is disjoint regions — always a set, since combining shapes can split or merge them. An open contour (a line) on either side is refused, and a null on either side nulls the row. One definition for both surfaces: in a pipeline other is another contour-domain expression; .contour.difference takes a contour column and runs this op.

Parameters:

Name Type Description Default
other Expr

The other contour set: a contour-domain expression (a contour column, through .contour).

required

Returns:

Type Description
Expr

A contour set (List[Contour]) per row: disjoint regions.

Example
>>> a = pl.col("pred").cv.pipe(Pipeline().source("contour"))
>>> b = pl.col("truth").cv.pipe(Pipeline().source("contour"))
>>> result = a.difference(b).sink("native")
>>> same = pl.col("pred").contour.difference(pl.col("truth"))

ensure_winding

ensure_winding(direction: str | Expr) -> pl.Expr

Ensure contour has specified winding direction.

Flips the contour if needed to match target winding. Use this when handing contours to an external consumer that expects a convention; polars-cv's own operations never require one.

Parameters:

Name Type Description Default
direction str | Expr

Target winding direction. Accepts a Polars expression for a per- row choice — rewinding a ring reorders its vertices and leaves the output schema untouched.

required

Returns:

Type Description
Expr

Contour with guaranteed winding direction, or a list of them for a

Expr

contour-set column.

flip

flip() -> pl.Expr

Reverse point order (flips winding direction).

Exterior and holes are reversed together. This changes only what winding() reports — the region the contour describes is unaffected, because no operation reads winding.

Returns:

Type Description
Expr

Contour with reversed point order, or a list of them for a

Expr

contour-set column.

hausdorff_distance

hausdorff_distance(other: Expr) -> pl.Expr

Compute Hausdorff distance to another contour.

The maximum, over every vertex of either contour, of the distance to the nearest vertex of the other. This is a vertex-to-vertex measure, not point-to-edge: two contours tracing the same outline with different vertex spacing have a non-zero distance. Hole vertices are included. An empty contour gives inf. For point-to-edge distances, see boundary_distances.

Parameters:

Name Type Description Default
other Expr

Another contour column to compare with.

required

Returns:

Type Description
Expr

Float64 Hausdorff distance — List(Float64) when either side is a

Expr

contour set.

intersection

intersection(other: Expr) -> pl.Expr

Inside both: where this contour set's regions overlap other's.

Each side is read as the union of its set (a single contour is a set of one), and the result is disjoint regions — always a set, since combining shapes can split or merge them. An open contour (a line) on either side is refused, and a null on either side nulls the row. One definition for both surfaces: in a pipeline other is another contour-domain expression; .contour.intersection takes a contour column and runs this op.

Parameters:

Name Type Description Default
other Expr

The other contour set: a contour-domain expression (a contour column, through .contour).

required

Returns:

Type Description
Expr

A contour set (List[Contour]) per row: disjoint regions.

Example
>>> a = pl.col("pred").cv.pipe(Pipeline().source("contour"))
>>> b = pl.col("truth").cv.pipe(Pipeline().source("contour"))
>>> result = a.intersection(b).sink("native")
>>> same = pl.col("pred").contour.intersection(pl.col("truth"))

iou

iou(other: Expr) -> pl.Expr

Compute Intersection over Union with another contour.

Overlap is exact for arbitrary simple polygons — concave shapes and holes included, in either winding direction. Each contour is measured as its exterior minus the union of its hole rings, the same region area(), contains_point() and rasterization use.

Parameters:

Name Type Description Default
other Expr

Another contour column to compare with.

required

Returns:

Type Description
Expr

Float64 IoU value in [0, 1] — List(Float64) when either side is a

Expr

contour set (see the class docstring on broadcasting).

is_convex

is_convex() -> pl.Expr

Check if contour is convex.

Returns:

Type Description
Expr

Boolean indicating convexity, or List(Boolean) for a contour-set

Expr

column.

label_reduce

label_reduce(
    image: Expr,
    *,
    reduction: str | Expr = "max",
    region_mode: str | Expr = "interior",
) -> pl.Expr

Score each contour from an image/array expression with configurable reduction.

Runs the same engine routine as :meth:polars_cv.Pipeline.label_reduce, so the two agree on every reduction, region mode and edge case; this accessor differs only in taking an already-materialized contour column rather than extracting one inside a pipeline.

Pixels are sampled at their centres. A contour with no area (a point or a line) or whose region catches no pixel centre (a sub-pixel contour) is scored on the pixels its outline passes through, in every region mode, rather than as 0.0.

Parameters:

Name Type Description Default
image Expr

Image/array expression aligned by row with contour sets.

required
reduction str | Expr

Aggregation method over pixels in each contour region. Accepts a Polars expression for a per-row choice.

'max'
region_mode str | Expr

Region selector - "interior" (pixels strictly inside), "boundary" (interior plus the contour boundary) or "bbox" (everything in the bounding box). Accepts a Polars expression.

'interior'

Returns:

Type Description
Expr

A list of float scores, aligned to the input contour order.

largest

largest(*, k: IntOrExpr = 1) -> pl.Expr

Keep the k largest contours of the set, by area: largest first, equal areas in their input order. A set of fewer keeps them all.

Parameters:

Name Type Description Default
k IntOrExpr

How many contours to keep, >= 1 (literal or expression).

1

normalize

normalize(
    width: FloatOrExpr, height: FloatOrExpr
) -> pl.Expr

Convert pixel coordinates to normalized [0,1] range.

Parameters:

Name Type Description Default
width FloatOrExpr

Reference width for normalization (literal or expression).

required
height FloatOrExpr

Reference height for normalization (literal or expression).

required

Returns:

Type Description
Expr

Contour with coordinates in [0,1] range, or a list of them for a

Expr

contour-set column.

offset

offset(
    distance: FloatOrExpr, *, join: str | Expr = "round"
) -> pl.Expr

Grow the set's regions by distance (negative: shrink them): every point within distance of their union, or inside it and at least -distance from its edge.

The set is read as one union, so growing can merge regions and shrinking can split them or leave none: the result is always a set. Convex corners turn by join; concave ones stay sharp. Round arcs are polygons within 1/64 pixel of the true arc, or about distance / 2000 past a distance of 32 pixels. An open contour is refused.

Parameters:

Name Type Description Default
distance FloatOrExpr

How far to move the edge, in pixels: positive grows, negative shrinks (literal or expression).

required
join str | Expr

"round" (an arc about each corner), "miter" (the edges extended to meet, cut off past 4 times distance) or "bevel" (cut straight across). Accepts an expression.

'round'

pairwise_iou

pairwise_iou(other: Expr) -> pl.Expr

Compute full pairwise IoU matrix between contour sets.

Parameters:

Name Type Description Default
other Expr

Ground-truth contour-set expression (List[Contour]).

required

Returns:

Type Description
Expr

A nested list (List[List[Float64]]) representing an N x M IoU matrix.

perimeter

perimeter() -> pl.Expr

Compute the perimeter (arc length) of the contour.

scale

scale(
    sx: FloatOrExpr,
    sy: FloatOrExpr,
    *,
    origin: str | Expr = "centroid",
) -> pl.Expr

Scale the contour about origin.

Parameters:

Name Type Description Default
sx FloatOrExpr

X scale factor.

required
sy FloatOrExpr

Y scale factor.

required
origin str | Expr

Point to scale about — "centroid" (center of mass), "bbox_center" (bounding-box center) or "origin" (the coordinate origin (0, 0)). Accepts an expression for a per-row choice: which point the scale is measured from changes no output shape, rank or dtype.

'centroid'

set_boundary_distances

set_boundary_distances(
    other: Expr,
    *,
    sample_step: FloatOrExpr | None = None,
    frame: Expr | None = None,
) -> pl.Expr

Boundary distances between two contour sets, each measured as one boundary: the union of its contours.

The surface distance of two masks with several regions (MONAI's compute_average_surface_distance / compute_hausdorff_distance): every sample of either side is measured to the nearest edge of any contour of the other, so a region with no counterpart is measured to the nearest one there is. boundary_distances pairs contours instead (one result per contour of a set). A single-contour column is a set of one. Sampling and frame are as for boundary_distances; an empty set (an empty mask) has no boundary and gives null.

Parameters:

Name Type Description Default
other Expr

Another contour (or contour-set) column to compare with.

required
sample_step FloatOrExpr | None

Spacing of the points sampled along every edge, > 0; None samples the vertices only (literal or expression).

None
frame Expr | None

A bbox column, the image frame: boundary not strictly inside it is not measured. A null frame row gives null.

None

Returns:

Type Description
Expr

Struct{mean_a_to_b, mean_b_to_a, assd, hd, hd95} (Float64), one

Expr

per row.

simplify

simplify(tolerance: FloatOrExpr) -> pl.Expr

Simplify the contour using the Douglas-Peucker algorithm.

Parameters:

Name Type Description Default
tolerance FloatOrExpr

Maximum distance from the original contour.

required

single

single(label: Expr) -> pl.Expr

The one contour of each row's set; a set of any other size fails.

For a column whose every row should hold exactly one contour (the outline extracted from an instance mask, say), where taking the first or the largest of several would silently measure a different object. The error quotes the failing row's label, so it can name the image rather than a row number (which, under the streaming engine, is only a position within one batch).

Parameters:

Name Type Description Default
label Expr

String expression aligned by row, quoted in the error to identify the row (an image id, say).

required

Returns:

Type Description
Expr

A single-contour column; null where the set is null.

smooth

smooth(*, iterations: IntOrExpr = 1) -> pl.Expr

Round off corners by Chaikin's corner cutting: each pass replaces every edge by its points a quarter and three quarters along, doubling the point count. A region's rings are cut all the way round; an open line keeps its two ends, unless it returns to its first point (as boundary() draws one), when it is cut through it as a loop.

Parameters:

Name Type Description Default
iterations IntOrExpr

Passes to make; 0 returns the contour as it is (literal or expression).

1

stroke

stroke(
    *,
    width: FloatOrExpr = 1.0,
    cap: str | Expr = "round",
    join: str | Expr = "round",
) -> pl.Expr

The region the set's paths cover when stroked, as disjoint regions: every point within width / 2 of a path, its ends shaped by cap and its corners by join. Every member is read as its outline: an open line, capped at its ends (one returning to its first point, as boundary() draws one, is a closed path), and a region's rings, each a closed path with no ends. A ring of fewer than two points has no edge and covers nothing; a one-point line is a dot (its caps). The result is always a set, filled by rasterize(): stroke(width=2).rasterize(...) draws lines and outlines. Round arcs are polygons within 1/64 pixel of the true arc, or about width / 4000 past a width of 64 pixels.

Parameters:

Name Type Description Default
width FloatOrExpr

The stroke's full width in pixels, a finite width > 0 (literal or expression).

1.0
cap str | Expr

How an open line ends: "round" (a half disc), "square" (a half square) or "butt" (flat at its end point). Accepts an expression.

'round'
join str | Expr

How a path turns a corner: "round", "miter" (cut off past 4 half-widths) or "bevel". Accepts an expression.

'round'

symmetric_difference

symmetric_difference(other: Expr) -> pl.Expr

Inside exactly one: where this contour set's regions and other's do not overlap.

Each side is read as the union of its set (a single contour is a set of one), and the result is disjoint regions — always a set, since combining shapes can split or merge them. An open contour (a line) on either side is refused, and a null on either side nulls the row. One definition for both surfaces: in a pipeline other is another contour-domain expression; .contour.symmetric_difference takes a contour column and runs this op.

Parameters:

Name Type Description Default
other Expr

The other contour set: a contour-domain expression (a contour column, through .contour).

required

Returns:

Type Description
Expr

A contour set (List[Contour]) per row: disjoint regions.

Example
>>> a = pl.col("pred").cv.pipe(Pipeline().source("contour"))
>>> b = pl.col("truth").cv.pipe(Pipeline().source("contour"))
>>> result = a.symmetric_difference(b).sink("native")
>>> same = pl.col("pred").contour.symmetric_difference(pl.col("truth"))

to_absolute

to_absolute(
    width: FloatOrExpr, height: FloatOrExpr
) -> pl.Expr

Convert normalized coordinates to pixel coordinates.

Parameters:

Name Type Description Default
width FloatOrExpr

Reference width for scaling (literal or expression).

required
height FloatOrExpr

Reference height for scaling (literal or expression).

required

Returns:

Type Description
Expr

Contour with pixel coordinates, or a list of them for a

Expr

contour-set column.

to_coords

to_coords(*, order: str | Expr = 'xy') -> pl.Expr

The contour's points as plain coordinate pairs, for export — the inverse of polars_cv.geometry.contour_from_coords. A contour with holes is refused: its rings have no single coordinate list.

Parameters:

Name Type Description Default
order str | Expr

"xy" or "yx" (row, column) (literal or expression).

'xy'

Returns:

Type Description
Expr

List(Array(Float64, 2)) of the exterior's (or polyline's)

Expr

points in order — a List of them for a contour set.

translate

translate(dx: FloatOrExpr, dy: FloatOrExpr) -> pl.Expr

Translate the contour by an offset.

Parameters:

Name Type Description Default
dx FloatOrExpr

X offset (horizontal translation).

required
dy FloatOrExpr

Y offset (vertical translation).

required

union

union(other: Expr) -> pl.Expr

Inside either: the union of this contour set's regions and other's.

Each side is read as the union of its set (a single contour is a set of one), and the result is disjoint regions — always a set, since combining shapes can split or merge them. An open contour (a line) on either side is refused, and a null on either side nulls the row. One definition for both surfaces: in a pipeline other is another contour-domain expression; .contour.union takes a contour column and runs this op.

Parameters:

Name Type Description Default
other Expr

The other contour set: a contour-domain expression (a contour column, through .contour).

required

Returns:

Type Description
Expr

A contour set (List[Contour]) per row: disjoint regions.

Example
>>> a = pl.col("pred").cv.pipe(Pipeline().source("contour"))
>>> b = pl.col("truth").cv.pipe(Pipeline().source("contour"))
>>> result = a.union(b).sink("native")
>>> same = pl.col("pred").contour.union(pl.col("truth"))

union_all

union_all() -> pl.Expr

The union of the set's regions, as disjoint regions: overlapping members merge and a hole another member covers is filled. The result is always a set. An open contour is refused.

winding

winding() -> pl.Expr

Compute the exterior ring's winding direction from point order.

Returns:

Type Description
Expr

String 'ccw' for counter-clockwise, 'cw' for clockwise — a list of

Expr

them for a contour-set column.

Note

Winding is computed using the Shoelace formula: - Positive signed area = CCW - Negative signed area = CW

This is purely a report on point order. Winding does not mark a ring as a hole — the holes field does — and no other operation consults it.

PointNamespace

Bases: _PointOpsMixin, _GeomNamespace

Operations on point columns.

This namespace provides geometric operations for point data, including coordinate transformations and distance calculations.

The point column holds one point per row (POINT_SCHEMA) or a point set (POINT_SET_SCHEMA, List(point)) per row. Over a set every method gives one value per point, in input order (a null point gives a null in its place), as a List. A contour or bbox operand is one per row and broadcasts against the set; two point columns broadcast either way (a set against a single point), and a set on both sides is refused.

Numeric parameters accept either a literal or a Polars expression; an expression is resolved per row at execution time.

Example

df.with_columns( ... normalized=pl.col("keypoint").point.normalize(width=100, height=100), ... shifted=pl.col("keypoint").point.translate(dx=10, dy=20), ... per_row=pl.col("keypoint").point.normalize( ... width=pl.col("img_w"), height=pl.col("img_h") ... ), ... )

on_null

on_null(policy: str) -> _Policy

Set what a null in a per-row expression parameter means.

These namespaces have no Pipeline object to hang a graph-level setting on, so the policy lives on the accessor itself and chains ahead of the call::

pl.col("c").contour.on_null("null").normalize(pl.col("w"), 100)
  • "raise" (default): a null parameter fails the expression.
  • "null": rows whose parameter is null yield null, matching how a null input geometry is already handled.

For a fallback value instead, fill the null in the expression itself — pl.col("w").fill_null(1.0).

The .cv namespace deliberately has no on_null; its equivalent is Pipeline.on_null_param.

Parameters:

Name Type Description Default
policy str

One of "raise", "null".

required

Returns:

Type Description
_Policy

A copy of this namespace with the policy applied. The original is

_Policy

unchanged, matching Pipeline's immutable-builder convention.

on_error

on_error(policy: str) -> _Policy

Set what a row whose data the function refuses means.

The accessors' counterpart of source(on_error=...): a row error — an open line too far from the frame to close, an open contour given to an area, a zero normalize size — fails the expression by default. Under "null" that row is null and the others proceed, so the invalid rows can be counted and inspected::

pl.col("line").contour.on_error("null").close_along_border(w, h)

An error about the column rather than a row — a contour set where one contour per row is expected, a dtype no reader understands — still raises: no row could succeed, and nulling it would null them all.

Parameters:

Name Type Description Default
policy str

One of "raise", "null".

required

Returns:

Type Description
_Policy

A copy of this namespace with the policy applied.

angle_to

angle_to(other: Expr) -> pl.Expr

Compute the angle from this point to another, in radians.

Parameters:

Name Type Description Default
other Expr

Target point column.

required

Returns:

Type Description
Expr

Float64 angle in radians, from atan2(dy, dx).

distance

distance(other: Expr) -> pl.Expr

Compute Euclidean distance to another point.

Parameters:

Name Type Description Default
other Expr

Another point column.

required

Returns:

Type Description
Expr

Float64 distance.

distance_to_contour

distance_to_contour(contour: Expr) -> pl.Expr

Compute the minimum distance from the point to the contour boundary.

Parameters:

Name Type Description Default
contour Expr

Contour column.

required

Returns:

Type Description
Expr

Float64 distance to the nearest edge of the contour.

interpolate

interpolate(
    other: Expr, *, t: FloatOrExpr = 0.5
) -> pl.Expr

Linearly interpolate between this point and another.

Parameters:

Name Type Description Default
other Expr

Another point column.

required
t FloatOrExpr

Interpolation parameter: 0 gives this point, 1 gives other (literal or expression).

0.5

Returns:

Type Description
Expr

self + t * (other - self).

manhattan_distance

manhattan_distance(other: Expr) -> pl.Expr

Compute Manhattan (L1) distance to another point.

Parameters:

Name Type Description Default
other Expr

Another point column.

required

Returns:

Type Description
Expr

Float64 distance.

midpoint

midpoint(other: Expr) -> pl.Expr

Compute the midpoint between two points.

Parameters:

Name Type Description Default
other Expr

Another point column.

required

Returns:

Type Description
Expr

The point halfway between.

nearest_point_on_contour

nearest_point_on_contour(contour: Expr) -> pl.Expr

Find the nearest point on the contour boundary.

Parameters:

Name Type Description Default
contour Expr

Contour column.

required

Returns:

Type Description
Expr

The nearest point on the contour, or null for an empty contour.

normalize

normalize(
    width: FloatOrExpr, height: FloatOrExpr
) -> pl.Expr

Convert pixel coordinates to normalized [0,1] range.

Parameters:

Name Type Description Default
width FloatOrExpr

Reference width for normalization; non-zero (literal or expression).

required
height FloatOrExpr

Reference height for normalization; non-zero (literal or expression).

required

Returns:

Type Description
Expr

Point with coordinates in [0,1] range.

rotate

rotate(
    angle: FloatOrExpr, *, origin: Expr | None = None
) -> pl.Expr

Rotate the point about an origin by an angle in radians.

Parameters:

Name Type Description Default
angle FloatOrExpr

Rotation angle in radians (literal or expression); positive is counter-clockwise in a y-up frame.

required
origin Expr | None

Point column to rotate about; the coordinate origin (0, 0) when omitted (or null in a row).

None

Returns:

Type Description
Expr

Rotated point.

scale

scale(sx: FloatOrExpr, sy: FloatOrExpr) -> pl.Expr

Scale point coordinates about the coordinate origin.

Parameters:

Name Type Description Default
sx FloatOrExpr

X scale factor (literal or expression).

required
sy FloatOrExpr

Y scale factor (literal or expression).

required

Returns:

Type Description
Expr

Scaled point.

signed_distance_to_contour

signed_distance_to_contour(contour: Expr) -> pl.Expr

Compute the signed distance from the point to the contour boundary.

Parameters:

Name Type Description Default
contour Expr

Contour column.

required

Returns:

Type Description
Expr

Float64 distance: negative if the point is inside the contour,

Expr

positive if outside.

to_absolute

to_absolute(
    width: FloatOrExpr, height: FloatOrExpr
) -> pl.Expr

Convert normalized coordinates to pixel coordinates.

Parameters:

Name Type Description Default
width FloatOrExpr

Reference width for scaling (literal or expression).

required
height FloatOrExpr

Reference height for scaling (literal or expression).

required

Returns:

Type Description
Expr

Point with pixel coordinates.

to_coords

to_coords(*, order: str | Expr = 'xy') -> pl.Expr

The point's coordinates as a plain pair, for export — the inverse of polars_cv.geometry.point_from_coords.

Parameters:

Name Type Description Default
order str | Expr

"xy" or "yx" (row, column) (literal or expression).

'xy'

Returns:

Type Description
Expr

Array(Float64, 2) in order.

translate

translate(dx: FloatOrExpr, dy: FloatOrExpr) -> pl.Expr

Translate point by offset.

Parameters:

Name Type Description Default
dx FloatOrExpr

X offset (literal or expression).

required
dy FloatOrExpr

Y offset (literal or expression).

required

Returns:

Type Description
Expr

Translated point.

within_bbox

within_bbox(bbox: Expr) -> pl.Expr

Check whether the point lies within a bounding box (edges included).

Parameters:

Name Type Description Default
bbox Expr

Bounding-box column.

required

Returns:

Type Description
Expr

Boolean.

x

x() -> pl.Expr

Extract the X coordinate.

Returns:

Type Description
Expr

Float64 X coordinate.

y

y() -> pl.Expr

Extract the Y coordinate.

Returns:

Type Description
Expr

Float64 Y coordinate.

BBoxNamespace

Bases: _BBoxOpsMixin, _GeomNamespace

Namespace for bounding-box operations on List[BBOX_SCHEMA] columns.

Example::

df.with_columns(
    iou_matrix=pl.col("pred_bboxes").bbox.pairwise_iou(pl.col("gt_bboxes")),
    pairs=pl.col("pred_bboxes").bbox.correspond(
        pl.col("gt_bboxes"), threshold=0.5
    ),
)

on_null

on_null(policy: str) -> _Policy

Set what a null in a per-row expression parameter means.

These namespaces have no Pipeline object to hang a graph-level setting on, so the policy lives on the accessor itself and chains ahead of the call::

pl.col("c").contour.on_null("null").normalize(pl.col("w"), 100)
  • "raise" (default): a null parameter fails the expression.
  • "null": rows whose parameter is null yield null, matching how a null input geometry is already handled.

For a fallback value instead, fill the null in the expression itself — pl.col("w").fill_null(1.0).

The .cv namespace deliberately has no on_null; its equivalent is Pipeline.on_null_param.

Parameters:

Name Type Description Default
policy str

One of "raise", "null".

required

Returns:

Type Description
_Policy

A copy of this namespace with the policy applied. The original is

_Policy

unchanged, matching Pipeline's immutable-builder convention.

on_error

on_error(policy: str) -> _Policy

Set what a row whose data the function refuses means.

The accessors' counterpart of source(on_error=...): a row error — an open line too far from the frame to close, an open contour given to an area, a zero normalize size — fails the expression by default. Under "null" that row is null and the others proceed, so the invalid rows can be counted and inspected::

pl.col("line").contour.on_error("null").close_along_border(w, h)

An error about the column rather than a row — a contour set where one contour per row is expected, a dtype no reader understands — still raises: no row could succeed, and nulling it would null them all.

Parameters:

Name Type Description Default
policy str

One of "raise", "null".

required

Returns:

Type Description
_Policy

A copy of this namespace with the policy applied.

correspond

correspond(
    other: Expr,
    *,
    threshold: FloatOrExpr = 0.5,
    order: Expr | None = None,
) -> pl.Expr

Pair each box with at most one box in other, by IoU.

The bounding-box form of :meth:ContourNamespace.correspond — the same greedy, exclusive rule, threshold and ordering, over box overlap.

Parameters:

Name Type Description Default
other Expr

Bounding-box set expression to pair against.

required
threshold FloatOrExpr

Minimum IoU for a pairing, in [0, 1]. Accepts a Polars expression for a per-row threshold.

0.5
order Expr | None

Optional per-row list of indices giving the visit sequence, a permutation of 0..n. Defaults to natural order.

None

Returns:

Type Description
Expr

A struct matching :data:polars_cv.CORRESPONDENCE_SCHEMA.

pairwise_iou

pairwise_iou(other: Expr) -> pl.Expr

Compute the full pairwise IoU matrix between two bounding-box sets.

Parameters:

Name Type Description Default
other Expr

Ground-truth bounding-box set expression.

required

Returns:

Type Description
Expr

A nested list (List[List[Float64]]) representing an N x M IoU matrix.

Constructors from coordinate lists

Build POINT_SCHEMA / CONTOUR_SCHEMA / CONTOUR_SET_SCHEMA columns from plain [x, y] or [y, x] pairs; .point.to_coords() and .contour.to_coords() are the inverse. bbox_from_coords builds BBOX_SCHEMA boxes from four numbers in a named layout, one of BoxFormat ("xyxy", "xywh", "cxcywh"; from polars_cv.geometry import BoxFormat).

point_from_coords

point_from_coords(
    expr: Expr, *, order: str | CoordOrder = "xy"
) -> pl.Expr

A point (POINT_SCHEMA) from each [a, b] pair.

Parameters:

Name Type Description Default
expr Expr

A column of pairs: List or Array(_, 2) of numbers.

required
order str | CoordOrder

"xy" or "yx" (row, column).

'xy'

Returns:

Type Description
Expr

A POINT_SCHEMA expression; a null pair gives a null point.

contour_from_coords

contour_from_coords(
    expr: Expr,
    *,
    order: str | CoordOrder = "xy",
    closed: bool = True,
) -> pl.Expr

A contour (CONTOUR_SCHEMA) from each list of [a, b] pairs.

Parameters:

Name Type Description Default
expr Expr

A column of rings: List of pairs.

required
order str | CoordOrder

"xy" or "yx" (row, column).

'xy'
closed bool

True for a region (the ring closes back on its first point), False for an open polyline.

True

Returns:

Type Description
Expr

A CONTOUR_SCHEMA expression, without holes.

contour_set_from_coords

contour_set_from_coords(
    expr: Expr,
    *,
    order: str | CoordOrder = "xy",
    closed: bool = True,
) -> pl.Expr

A contour set (CONTOUR_SET_SCHEMA) from each list of rings.

Parameters:

Name Type Description Default
expr Expr

A column of ring lists: List of List of pairs.

required
order str | CoordOrder

"xy" or "yx" (row, column).

'xy'
closed bool

True for regions, False for open polylines.

True

Returns:

Type Description
Expr

A CONTOUR_SET_SCHEMA expression.

bbox_from_coords

bbox_from_coords(
    coords: str | Expr | Sequence[str | Expr],
    *,
    format: BoxFormat,
) -> pl.Expr

A box (BBOX_SCHEMA: x, y, width, height) from four coordinates.

Parameters:

Name Type Description Default
coords str | Expr | Sequence[str | Expr]

Either one column holding four numbers per row (List or Array(_, 4)), or four columns / expressions in layout order.

required
format BoxFormat

The layout of the four numbers (required — the three are indistinguishable from the data):

  • "xyxy": x_min, y_min, x_max, y_max;
  • "xywh": x_min, y_min, width, height (COCO);
  • "cxcywh": x_centre, y_centre, width, height (YOLO).
required

Returns:

Type Description
Expr

A BBOX_SCHEMA expression named after the first input column; a

Expr

null box gives a null struct, and a row whose box does not hold four

Expr

numbers is an error.

Raises:

Type Description
ValueError

An unknown format, or a sequence of other than four columns.