A vision library for performing sliced inference on large images/small objects
—
SAHI's image slicing capabilities enable processing of large images by dividing them into smaller, overlapping patches. This approach significantly improves small object detection performance and enables processing of images that exceed memory or model input size limitations.
Generates coordinate bounding boxes for slicing an image into overlapping crops with automatic parameter calculation.
def get_slice_bboxes(
image_height: int,
image_width: int,
slice_height: Optional[int] = None,
slice_width: Optional[int] = None,
auto_slice_resolution: Optional[bool] = True,
overlap_height_ratio: Optional[float] = 0.2,
overlap_width_ratio: Optional[float] = 0.2,
) -> List[List[int]]:
"""
Generate bounding boxes for slicing an image into crops.
Parameters:
- image_height (int): Height of the original image
- image_width (int): Width of the original image
- slice_height (int, optional): Height of each slice
- slice_width (int, optional): Width of each slice
- auto_slice_resolution (bool): Auto-calculate slice dimensions from image size
- overlap_height_ratio (float): Fractional vertical overlap between slices (0-1)
- overlap_width_ratio (float): Fractional horizontal overlap between slices (0-1)
Returns:
List[List[int]]: List of slice bounding boxes as [xmin, ymin, xmax, ymax]
"""Slice an image into overlapping patches and save them with optional output directory management.
def slice_image(
image: Union[str, Image.Image],
output_file_name: Optional[str] = None,
output_dir: Optional[str] = None,
slice_height: int = 512,
slice_width: int = 512,
overlap_height_ratio: float = 0.2,
overlap_width_ratio: float = 0.2,
auto_slice_resolution: bool = True,
min_area_ratio: float = 0.1,
out_ext: Optional[str] = None,
verbose: bool = False,
) -> SliceImageResult:
"""
Slice image into overlapping crops with automatic file management.
Parameters:
- image: Image path (str) or PIL Image object
- output_file_name (str, optional): Base name for output files
- output_dir (str, optional): Directory for saving sliced images
- slice_height (int): Height of each slice in pixels
- slice_width (int): Width of each slice in pixels
- overlap_height_ratio (float): Vertical overlap ratio between slices
- overlap_width_ratio (float): Horizontal overlap ratio between slices
- auto_slice_resolution (bool): Auto-calculate optimal slice dimensions
- min_area_ratio (float): Minimum area ratio for valid slices
- out_ext (str, optional): Output file extension
- verbose (bool): Print slicing progress
Returns:
SliceImageResult: Container with sliced images and metadata
"""Slice COCO format datasets including images and annotations with proper annotation mapping and filtering.
def slice_coco(
coco_annotation_file_path: str,
image_dir: str,
output_coco_annotation_file_name: str = "",
output_dir: Optional[str] = None,
ignore_negative_samples: bool = False,
slice_height: int = 512,
slice_width: int = 512,
overlap_height_ratio: float = 0.2,
overlap_width_ratio: float = 0.2,
min_area_ratio: float = 0.1,
verbose: bool = False,
) -> str:
"""
Slice COCO dataset including images and annotations.
Parameters:
- coco_annotation_file_path (str): Path to COCO format JSON file
- image_dir (str): Directory containing dataset images
- output_coco_annotation_file_name (str): Name for output annotation file
- output_dir (str, optional): Output directory for sliced dataset
- ignore_negative_samples (bool): Skip slices without annotations
- slice_height (int): Height of each slice
- slice_width (int): Width of each slice
- overlap_height_ratio (float): Vertical overlap between slices
- overlap_width_ratio (float): Horizontal overlap between slices
- min_area_ratio (float): Minimum annotation area ratio to keep
- verbose (bool): Print progress information
Returns:
str: Path to output COCO annotation file
"""Automatically determine optimal slice parameters based on image resolution and orientation.
def get_auto_slice_params(
height: int,
width: int
) -> Tuple[int, int]:
"""
Automatically calculate slice parameters from image dimensions.
Parameters:
- height (int): Image height
- width (int): Image width
Returns:
Tuple[int, int]: Optimal (slice_height, slice_width)
"""Process annotations for slicing operations including coordinate transformations and filtering.
def annotation_inside_slice(
annotation: Dict,
slice_bbox: List[int],
min_area_ratio: float = 0.1
) -> bool:
"""
Check if annotation is sufficiently inside slice boundaries.
Parameters:
- annotation (Dict): COCO format annotation dictionary
- slice_bbox (List[int]): Slice bounding box [xmin, ymin, xmax, ymax]
- min_area_ratio (float): Minimum area ratio threshold
Returns:
bool: True if annotation should be included in slice
"""
def process_coco_annotations(
coco_annotation_list: List[Dict],
slice_bbox: List[int],
min_area_ratio: float = 0.1,
full_shape: Optional[List[int]] = None
) -> List[Dict]:
"""
Process COCO annotations for a specific slice.
Parameters:
- coco_annotation_list: List of COCO annotation dictionaries
- slice_bbox: Slice bounding box coordinates
- min_area_ratio: Minimum area ratio for keeping annotations
- full_shape: Original image dimensions
Returns:
List[Dict]: Processed annotations with updated coordinates
"""Utilities for shifting bounding boxes and masks between coordinate systems.
def shift_bboxes(
boxes: np.ndarray,
shift_amount: List[int]
) -> np.ndarray:
"""
Shift bounding boxes by specified offset.
Parameters:
- boxes (np.ndarray): Bounding boxes in xyxy format
- shift_amount (List[int]): Shift offset [x_shift, y_shift]
Returns:
np.ndarray: Shifted bounding boxes
"""
def shift_masks(
masks: List[List],
shift_amount: List[int]
) -> List[List]:
"""
Shift segmentation masks by specified offset.
Parameters:
- masks: List of COCO format segmentation masks
- shift_amount: Coordinate shift [x_shift, y_shift]
Returns:
List[List]: Shifted segmentation masks
"""Container for image slicing operation results with metadata and file paths.
class SliceImageResult:
def __init__(
self,
original_image_size: List[int],
image_dir: str
):
"""
Initialize slice result container.
Parameters:
- original_image_size: Original image dimensions [height, width]
- image_dir: Directory containing sliced images
"""
@property
def images(self) -> List[SlicedImage]: ...
@property
def starting_pixels(self) -> List[List[int]]: ...Individual sliced image with metadata and coordinate information.
class SlicedImage:
def __init__(
self,
image: Image.Image,
coco_image: CocoImage,
starting_pixel: List[int]
):
"""
Initialize sliced image with metadata.
Parameters:
- image: PIL Image of the slice
- coco_image: COCO format image metadata
- starting_pixel: Top-left coordinate [x, y] in original image
"""
@property
def image(self) -> Image.Image: ...
@property
def starting_pixel(self) -> List[int]: ...from sahi.slicing import slice_image, get_slice_bboxes
from PIL import Image
# Calculate slice bounding boxes
image = Image.open("large_image.jpg")
height, width = image.size
slice_bboxes = get_slice_bboxes(
image_height=height,
image_width=width,
slice_height=640,
slice_width=640,
overlap_height_ratio=0.2,
overlap_width_ratio=0.2
)
print(f"Generated {len(slice_bboxes)} slices")
# Slice image and save crops
result = slice_image(
image="large_image.jpg",
output_dir="sliced_images/",
slice_height=640,
slice_width=640,
overlap_height_ratio=0.2,
overlap_width_ratio=0.2,
verbose=True
)
print(f"Created {len(result.images)} slice images")from sahi.slicing import slice_image
# Auto-calculate optimal slice dimensions
result = slice_image(
image="very_large_image.jpg",
output_dir="auto_sliced/",
auto_slice_resolution=True, # Enable auto-calculation
overlap_height_ratio=0.15,
overlap_width_ratio=0.15,
verbose=True
)from sahi.slicing import slice_coco
# Slice entire COCO dataset
output_path = slice_coco(
coco_annotation_file_path="dataset/annotations.json",
image_dir="dataset/images/",
output_dir="sliced_dataset/",
output_coco_annotation_file_name="sliced_annotations.json",
slice_height=512,
slice_width=512,
overlap_height_ratio=0.2,
overlap_width_ratio=0.2,
min_area_ratio=0.1, # Keep annotations with >=10% area in slice
ignore_negative_samples=False, # Keep slices without annotations
verbose=True
)
print(f"Sliced dataset saved to: {output_path}")from sahi.slicing import process_coco_annotations, annotation_inside_slice
# Load COCO annotations
annotations = [
{
"bbox": [100, 150, 50, 80], # [x, y, width, height]
"category_id": 1,
"area": 4000,
"id": 1
}
]
# Define slice region
slice_bbox = [80, 120, 200, 250] # [xmin, ymin, xmax, ymax]
# Check if annotation should be included
should_include = annotation_inside_slice(
annotation=annotations[0],
slice_bbox=slice_bbox,
min_area_ratio=0.3
)
# Process annotations for slice
processed_annotations = process_coco_annotations(
coco_annotation_list=annotations,
slice_bbox=slice_bbox,
min_area_ratio=0.1,
full_shape=[1000, 1000]
)
print(f"Processed {len(processed_annotations)} annotations for slice")from sahi.slicing import slice_image
# Custom slicing with specific parameters
result = slice_image(
image="satellite_image.tif",
output_dir="satellite_slices/",
output_file_name="satellite_slice",
slice_height=1024,
slice_width=1024,
overlap_height_ratio=0.25, # 25% overlap
overlap_width_ratio=0.25,
min_area_ratio=0.05, # Keep small partial slices
out_ext=".png", # Convert format
verbose=True
)
# Access individual slices
for i, sliced_image in enumerate(result.images):
print(f"Slice {i}: starts at {sliced_image.starting_pixel}")
# Process individual slice
slice_pil = sliced_image.imageInstall with Tessl CLI
npx tessl i tessl/pypi-sahi