Expressions (.cv)¶
The .cv accessor is registered on every Polars expression once polars_cv is
imported. It is the entry point for pipelines, for raw byte access, and for the
header-only metadata readers.
Overview¶
| Method | Input column | Returns | Purpose |
|---|---|---|---|
pipe() |
image bytes, paths, lists/arrays, contour structs | LazyPipelineExpr |
Apply a Pipeline; finish with .sink(...) |
read_bytes() |
String paths |
Binary |
Read the bytes a path names, without decoding |
width() |
Binary encoded images |
UInt32 |
Image width from the header only |
height() |
Binary encoded images |
UInt32 |
Image height from the header only |
channels() |
Binary encoded images |
UInt32 |
Channel count from the header only |
image_dtype() |
Binary encoded images |
String |
Sample dtype from the header only |
Only pipe() builds a graph and runs through the vb_graph expression. The
others are standalone plugin expressions: they take a column and return a
column, with no pipeline to build.
Pipelines¶
pipe = Pipeline().source("image_bytes").resize(height=224, width=224)
df.with_columns(out=pl.col("image").cv.pipe(pipe).sink("numpy"))
See Pipeline for the operations and LazyPipelineExpr for composition and sinks.
Everything that configures a pipeline lives on the Pipeline (or on the
LazyPipelineExpr it produces), not on the accessor — including the per-row
error and null-parameter policies, .on_error() and .on_null_param(). Unlike
the geometry namespaces, .cv has no on_null().
Byte access¶
read_bytes() is the fetch half of the "file_path" source — that source
fetches a path's bytes and then decodes them as an image, and this stops after
the fetch. Bytes are returned verbatim, so an encoded file survives the round
trip byte-for-byte.
# Read originals, filter on header metadata, decode only the survivors.
lf = (
pl.scan_parquet("images.parquet")
.with_columns(raw=pl.col("path").cv.read_bytes())
.filter(pl.col("raw").cv.width() > 512)
.with_columns(thumb=pl.col("raw").cv.pipe(pipe).sink("png"))
)
It takes the same cloud_options and on_error values as
Pipeline.source("file_path"). See
Reading Bytes Without Decoding
for the memory and streaming behaviour, and for the path-sandboxing caveat.
Metadata¶
The metadata readers parse only the image header, so they do not decode pixels.
They take a Binary column of encoded images or a String column of paths (a
local file is read only as far as its header needs):
See Metadata & Display for details.
API Reference¶
CvNamespace ¶
Bases: _PluginNamespace
Namespace for computer vision operations on Polars expressions.
Example
pipe = Pipeline().source("image_bytes").resize(height=100, width=200) expr = pl.col("image").cv.pipe(pipe).sink("numpy") df.with_columns(processed=expr)
Metadata methods (header-only, no full decode): >>> df.with_columns(w=pl.col("image").cv.width()) >>> df.filter(pl.col("image").cv.height() > 1024)
pipe ¶
Apply a vision pipeline to this column.
Returns a LazyPipelineExpr that can be composed with other operations. Call .sink(format) to finalize and get a Polars expression.
read_bytes ¶
read_bytes(
*,
cloud_options: "CloudOptions | dict[str, Any] | None" = None,
on_error: str = "raise",
allowed_roots: "Sequence[str] | None" = None,
) -> pl.Expr
Read the bytes each path names, without decoding them.
This is the first half of the "file_path" source: that source
fetches a path's bytes and then decodes them as an image, and this
stops after the fetch. Bytes are returned verbatim, so an encoded file
survives the round trip unchanged and can be written back
byte-for-byte — something a decode cannot offer, since re-encoding a
decoded JPEG never reproduces the original file and the image sinks
carry no EXIF/ICC metadata.
The header-only metadata methods below take a path column directly (a local file read only as far as its header needs), so they do not need this first.
Local paths (bare or file://) and remote URIs (s3://, gs://,
az://, http://) are both supported, with the same credential
handling as source("file_path"). Within one call the distinct
remote paths are fetched concurrently; local files are read per row.
Under engine="streaming" a bytes column produced here is
morsel-bounded, so it only becomes corpus-resident if you select it in
the final projection — which is the point when you want the originals.
Note
Without allowed_roots paths are not sandboxed: whatever the
column names is read in full, including any local file and any
http:// address (link-local metadata endpoints among them).
That is the right default for your own paths and the wrong one for
paths that came from somewhere else. File size is not capped
either way.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cloud_options
|
'CloudOptions | dict[str, Any] | None'
|
Credentials/settings for remote reads, as
|
None
|
on_error
|
str
|
|
'raise'
|
allowed_roots
|
'Sequence[str] | None'
|
Restrict which locations may be read, exactly as
|
None
|
Returns:
| Type | Description |
|---|---|
Expr
|
Binary expression with each path's raw file contents. |
width ¶
width(
*,
cloud_options: "CloudOptions | dict[str, Any] | None" = None,
on_error: str | None = None,
allowed_roots: "Sequence[str] | None" = None,
) -> pl.Expr
Get image width from its header, without a full decode.
The column holds image bytes (Binary) or paths (String). A
local path's file is read only as far as its header needs; a remote
path's object is fetched whole, as .cv.read_bytes() does. Supports
encoded images (PNG, JPEG, WebP, TIFF, BMP, GIF) and VIEW protocol
blobs; null for an unrecognised format or a null input. For more
than one field, .cv.image_info() reads each header once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cloud_options
|
'CloudOptions | dict[str, Any] | None'
|
Path columns only: credentials for remote reads,
as for |
None
|
on_error
|
str | None
|
Path columns only: |
None
|
allowed_roots
|
'Sequence[str] | None'
|
Path columns only: the locations that may be read,
as for |
None
|
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32 expression with the width of each image. |
height ¶
height(
*,
cloud_options: "CloudOptions | dict[str, Any] | None" = None,
on_error: str | None = None,
allowed_roots: "Sequence[str] | None" = None,
) -> pl.Expr
Get image height from its header, without a full decode.
Takes bytes or paths, as :meth:width does (see it for the options).
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32 expression with the height of each image. |
channels ¶
channels(
*,
cloud_options: "CloudOptions | dict[str, Any] | None" = None,
on_error: str | None = None,
allowed_roots: "Sequence[str] | None" = None,
) -> pl.Expr
Get the number of channels from its header, without a full decode.
Takes bytes or paths, as :meth:width does (see it for the options).
Returns:
| Type | Description |
|---|---|
Expr
|
UInt32 expression with the channel count of each image. |
image_dtype ¶
image_dtype(
*,
cloud_options: "CloudOptions | dict[str, Any] | None" = None,
on_error: str | None = None,
allowed_roots: "Sequence[str] | None" = None,
) -> pl.Expr
Get the element dtype from its header, without a full decode.
Returns dtype names like "uint8", "uint16", "float32".
Takes bytes or paths, as :meth:width does (see it for the options).
Returns:
| Type | Description |
|---|---|
Expr
|
String expression with the dtype name of each image. |
image_info ¶
image_info(
*,
cloud_options: "CloudOptions | dict[str, Any] | None" = None,
on_error: str | None = None,
allowed_roots: "Sequence[str] | None" = None,
) -> pl.Expr
Width, height, channels and dtype from one header read per row.
Takes bytes or paths, as :meth:width does (see it for the options).
Returns:
| Name | Type | Description |
|---|---|---|
Expr
|
``Struct{width: UInt32, height: UInt32, channels: UInt32, |
|
dtype |
Expr
|
String}``; null for a null input or an unrecognised format. |