{"record":{"id":"95fd0584ca90bf29","repo":"roboflow/supervision","slug":"inferenceslicer-requires-a-projected-coordinate-re","errorCode":null,"errorMessage":"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.","messagePattern":"InferenceSlicer requires a projected coordinate reference system for pixel-space tiled inference on a raster dataset\\. The provided dataset uses a geographic CRS \\((.+?)\\)\\. Reproject it to a projected CRS \\(e\\.g\\. with `gdalwarp`\\) before slicing\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/tools/inference_slicer.py","lineNumber":445,"sourceCode":"            with ThreadPoolExecutor(max_workers=self.thread_workers) as executor:\n                futures = [\n                    executor.submit(self._run_callback, image, offset)\n                    for offset in remaining_offsets\n                ]\n                for future in as_completed(futures):\n                    detections_list.append(future.result())\n\n        merged = Detections.merge(detections_list=detections_list)\n        return self._apply_overlap_filter(merged)\n\n    def _get_resolution_wh(\n        self, image: ImageType | WindowedRasterDataset\n    ) -> tuple[int, int]:\n        \"\"\"Return ``(width, height)`` for the image, validating CRS for rasters.\"\"\"\n        if _is_windowed_raster(image):\n            crs = image.crs\n            if crs is not None and not getattr(crs, \"is_projected\", True):\n                raise ValueError(\n                    \"InferenceSlicer requires a projected coordinate reference \"\n                    \"system for pixel-space tiled inference on a raster dataset. \"\n                    f\"The provided dataset uses a geographic CRS ({crs}). Reproject \"\n                    \"it to a projected CRS (e.g. with `gdalwarp`) before slicing.\"\n                )\n            return (image.width, image.height)\n        return get_image_resolution_wh(image)\n\n    def _apply_overlap_filter(self, merged: Detections) -> Detections:\n        \"\"\"Apply the configured overlap filter strategy to merged detections.\"\"\"\n        if self.overlap_filter == OverlapFilter.NONE:\n            return merged\n        if self.overlap_filter == OverlapFilter.NON_MAX_SUPPRESSION:\n            return merged.with_nms(\n                threshold=self.iou_threshold,\n                overlap_metric=self.overlap_metric,\n            )\n        if self.overlap_filter == OverlapFilter.NON_MAX_MERGE:","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/tools/inference_slicer.py#L427-L463","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Reproject the raster to a projected CRS before slicing, e.g. gdalwarp -t_srs EPSG:32633 input.tif output.tif, or rasterio.warp.reproject.","Pick a sensible local/UTM zone so pixel sizes stay approximately uniform.","If georeferencing accuracy does not matter, convert the raster to a plain image array and slice that instead."],"exampleFix":"# before\nwith rasterio.open('wgs84.tif') as src:\n    detections = slicer(src)  # ValueError: geographic CRS\n\n# after\n# shell: gdalwarp -t_srs EPSG:32633 wgs84.tif utm.tif\nwith rasterio.open('utm.tif') as src:\n    detections = slicer(src)","handlingStrategy":"validation","validationCode":"def ensure_projected_crs(dataset, default_epsg=None):\n    crs = dataset.crs\n    if crs is not None and not getattr(crs, 'is_projected', True):\n        raise ValueError(\n            f'Geographic CRS {crs} not supported; reproject e.g. with '\n            f'gdalwarp -t_srs EPSG:{default_epsg or 32633}'\n        )\n    return dataset\n\nwith rasterio.open(path) as src:\n    ensure_projected_crs(src)\n    detections = slicer(src)","typeGuard":"def is_projected_dataset(dataset) -> bool:\n    crs = dataset.crs\n    return crs is None or bool(getattr(crs, 'is_projected', True))","tryCatchPattern":"try:\n    detections = slicer(raster)\nexcept ValueError as err:\n    if 'projected' in str(err) and 'CRS' in str(err):\n        raise RuntimeError(f'reproject the raster first: {err}') from err\n    raise","preventionTips":["Standardize the ingestion pipeline on a projected CRS (UTM zone of the area of interest).","Check dataset.crs.is_projected during data validation, before inference starts."],"tags":["inference-slicer","geospatial","rasterio","crs","gdal","valueerror"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}