Sign in Get started

Tile a dataset

Slice every image into a grid of tiles for small-object detection — with correct annotation geometry per tile.

View as Markdown

tile_dataset() slices every image in a dataset into a rows × cols grid of smaller tiles and uploads the tiles back through the standard ingest pipeline (SigLIP2 embeddings, auto-tags, CDN thumbnails). It’s the standard fix for small-object detection — aerial, satellite, and microscopy imagery, where objects are tiny relative to the frame: after tiling, each object occupies a larger fraction of its tile and trains far better. Crucially, every annotation is translated into its tile’s local coordinates and clipped to the tile frame, so a box or polygon straddling a boundary is split correctly across the adjacent tiles. Native, on the base install (Pillow only, no extra dependencies).

from pictograph import Client
from pictograph.pipelines import tile_dataset

client = Client()

report = tile_dataset(
    client,
    "aerial",
    rows=2,
    cols=2,
    overlap=0.1,          # each tile extends 10% past its edge so boundary objects stay whole
    into="aerial-tiled",  # new dataset; the source's class config is copied
)
print(f"{report.tiles_created} tiles generated from {report.source_images} images")

Pass into=None (or the source’s own name) to append the tiles into the source dataset itself, under a /tiles virtual folder. Every generated tile counts toward your organization’s image quota, exactly like a normal upload.

Signature

tile_dataset(
    client: Client,
    source: str,
    *,
    rows: int = 2,
    cols: int = 2,
    overlap: float = 0.0,
    min_visibility: float = 0.1,
    include_empty: bool = True,
    into: str | None = None,
    folder_path: str = "/tiles",
    max_source_images: int | None = None,
    jpeg_quality: int = 95,
    on_progress: Callable[[int, int], None] | None = None,
) -> TileReport
  • rows / cols — the grid dimensions (e.g. 2 × 2 = four tiles per image).
  • overlap — a fraction (0.00.9) each tile extends past its edge, so an object sitting on a tile boundary appears whole in at least one neighbour.
  • min_visibility — an annotation is dropped from a tile when less than this fraction of its area survives the clip.
  • include_empty — set False to skip tiles left with no annotations (Roboflow’s “exclude tiles without annotations”); the default keeps them as useful background negatives.

Like every workflow, it returns a report rather than raising on a single bad image — inspect report.failures to retry the affected source images.

report = tile_dataset(client, "aerial", rows=3, cols=3, into="aerial-tiled")
print(report.source_images, report.tiles_created, report.annotations_written)
for f in report.failures:
    print(f.image_id, f.reason)

The engine: pictograph.tile

Under the pipeline is a standalone, reusable engine you can drive on any local (image, annotations) pair — no API call required:

from pictograph.tile import tile_image

tiles = tile_image("aerial.jpg", annotations, rows=2, cols=2, overlap=0.1)
for t in tiles:
    t.image.save(f"tile_r{t.row}_c{t.col}.jpg")
    print(len(t.annotations), "annotations in this tile", t.origin)

Each Tile carries the cropped image, the geometry-remapped annotations, its grid row/col, and its origin (the tile’s top-left corner in source pixels). The grid partitions the image exactly; a box straddling a boundary is clipped (Sutherland–Hodgman for polygons) into every tile it touches.

CLI

# slice every image into a 2×2 grid → a new dataset
pictograph tile dataset aerial --into aerial-tiled --rows 2 --cols 2

# a 3×3 grid with 10% overlap, dropping empty tiles
pictograph tile dataset aerial --into aerial-tiled \
    --rows 3 --cols 3 --overlap 0.1 --exclude-empty

See pictograph tile dataset --help for the full flag set.

Tiling vs. augmentation

Tiling is a preprocessing step — it deterministically slices each image so small objects are bigger relative to their tile. Augmentation is a version-generation step — it produces randomized variants (flip/rotate/colour) to expand the effective training set. They compose: tile first for small-object detection, then augment the tiled dataset.

Notes

  • Geometry stays correct per tile: boxes are clipped to the tile, polygons are Sutherland–Hodgman-clipped, keypoints outside a tile are dropped, and an annotation whose visible area falls below min_visibility is removed from that tile.
  • The pipeline runs deterministically — re-running yields byte-identical output.
  • Generated tiles ride the normal ingest path — they get embeddings, auto-tags, and thumbnails just like uploads, so you can search and filter them immediately.
Copied to clipboard