roboflow/supervision · error · ValueError

InferenceSlicer requires a projected coordinate reference sy

Error message

InferenceSlicer requires a projected coordinate reference system for pixel-space tiled inference on a raster dataset. The provided dataset uses a geographic CRS ({crs}). Reproject it to a projected CRS (e.g. with `gdalwarp`) before slicing.

What it means

Raised by InferenceSlicer._get_resolution_wh when the input is a windowed raster dataset whose CRS is geographic (latitude/longitude degrees, e.g. EPSG:4326). The slicer works purely in pixel space; the guard exists because downstream georeferencing math (converting pixel offsets to world coordinates) is only meaningful when map units are linear, so the dataset must use a projected CRS (metres/feet).

Source

Thrown at src/supervision/detection/tools/inference_slicer.py:445

            with ThreadPoolExecutor(max_workers=self.thread_workers) as executor:
                futures = [
                    executor.submit(self._run_callback, image, offset)
                    for offset in remaining_offsets
                ]
                for future in as_completed(futures):
                    detections_list.append(future.result())

        merged = Detections.merge(detections_list=detections_list)
        return self._apply_overlap_filter(merged)

    def _get_resolution_wh(
        self, image: ImageType | WindowedRasterDataset
    ) -> tuple[int, int]:
        """Return ``(width, height)`` for the image, validating CRS for rasters."""
        if _is_windowed_raster(image):
            crs = image.crs
            if crs is not None and not getattr(crs, "is_projected", True):
                raise ValueError(
                    "InferenceSlicer requires a projected coordinate reference "
                    "system for pixel-space tiled inference on a raster dataset. "
                    f"The provided dataset uses a geographic CRS ({crs}). Reproject "
                    "it to a projected CRS (e.g. with `gdalwarp`) before slicing."
                )
            return (image.width, image.height)
        return get_image_resolution_wh(image)

    def _apply_overlap_filter(self, merged: Detections) -> Detections:
        """Apply the configured overlap filter strategy to merged detections."""
        if self.overlap_filter == OverlapFilter.NONE:
            return merged
        if self.overlap_filter == OverlapFilter.NON_MAX_SUPPRESSION:
            return merged.with_nms(
                threshold=self.iou_threshold,
                overlap_metric=self.overlap_metric,
            )
        if self.overlap_filter == OverlapFilter.NON_MAX_MERGE:

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Reproject the raster to a projected CRS before slicing, e.g. gdalwarp -t_srs EPSG:32633 input.tif output.tif, or rasterio.warp.reproject.
  2. Pick a sensible local/UTM zone so pixel sizes stay approximately uniform.
  3. If georeferencing accuracy does not matter, convert the raster to a plain image array and slice that instead.

Example fix

# before
with rasterio.open('wgs84.tif') as src:
    detections = slicer(src)  # ValueError: geographic CRS

# after
# shell: gdalwarp -t_srs EPSG:32633 wgs84.tif utm.tif
with rasterio.open('utm.tif') as src:
    detections = slicer(src)
Defensive patterns

Strategy: validation

Validate before calling

def ensure_projected_crs(dataset, default_epsg=None):
    crs = dataset.crs
    if crs is not None and not getattr(crs, 'is_projected', True):
        raise ValueError(
            f'Geographic CRS {crs} not supported; reproject e.g. with '
            f'gdalwarp -t_srs EPSG:{default_epsg or 32633}'
        )
    return dataset

with rasterio.open(path) as src:
    ensure_projected_crs(src)
    detections = slicer(src)

Type guard

def is_projected_dataset(dataset) -> bool:
    crs = dataset.crs
    return crs is None or bool(getattr(crs, 'is_projected', True))

Try / catch

try:
    detections = slicer(raster)
except ValueError as err:
    if 'projected' in str(err) and 'CRS' in str(err):
        raise RuntimeError(f'reproject the raster first: {err}') from err
    raise

Prevention

When it happens

Trigger: Calling slicer(raster_dataset) where raster_dataset is a rasterio-style windowed dataset with dataset.crs.is_projected == False, e.g. a standard WGS84 GeoTIFF (EPSG:4326).

Common situations: Slicing satellite/drone imagery delivered in WGS84; forgetting to reproject newly acquired tiles; pipelines that worked with UTM datasets failing on web-mercator-vs-WGS84 mixed data.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/95fd0584ca90bf29. Report an issue: GitHub.