Stochastically displaces each pixel by sampling its value from a random source within a local square neighborhood, without blurring or coherent warping.
For every output pixel (row, col) an offset (d_row, d_col) is drawn independently and
uniformly from the square neighborhood [-radius, radius] x [-radius, radius] and the pixel
value is read from source position (row + d_row, col + d_col). The same dense remapping
field is applied to all targets (image, mask, bboxes, keypoints) so spatial annotations remain
consistent.
This occupies a useful middle ground between blur (which aggregates a neighborhood) and smooth elastic warps (which produce coherent displacement fields): the displacement field is intentionally non-smooth and high-frequency, making it suitable for simulating sensor noise, compression artifacts, fine-grained texture corruption, and domain shifts where local pixel structure becomes unstable but global object geometry is preserved.
radiusMaximum pixel displacement in each direction. The sampling neighborhood is
the square [-radius, radius] x [-radius, radius], giving (2*radius+1)^2 possible
source locations per output pixel. Must be >= 1. Default: 2.
interpolationInterpolation flag used by cv2.remap. Default: cv2.INTER_NEAREST.
Nearest-neighbor is the natural choice because the effect is explicitly about discrete
pixel reassignment, not sub-pixel blending.
mask_interpolationInterpolation flag for masks. Default: cv2.INTER_NEAREST.
keypoint_remapping_methodStrategy for remapping keypoints.
Default: "mask".
border_modeOpenCV border extrapolation mode for out-of-bounds source lookups.
Default: cv2.BORDER_REFLECT_101.
fillFill value used when border_mode is
cv2.BORDER_CONSTANT. Default: 0.
fill_maskFill value for masks under constant border. Default: 0.
pProbability of applying the transform. Default: 0.5.
>>> import numpy as np
>>> import albumentations as A
>>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
>>> mask = np.random.randint(0, 2, (100, 100), dtype=np.uint8)
>>> bboxes = np.array([[10, 10, 50, 50]], dtype=np.float32)
>>> bbox_labels = [1]
>>> keypoints = np.array([[20, 30]], dtype=np.float32)
>>> keypoint_labels = [0]
>>>
>>> transform = A.Compose([
... A.PixelSpread(radius=3, p=1.0)
... ], bbox_params=A.BboxParams(coord_format='pascal_voc', label_fields=['bbox_labels']),
... keypoint_params=A.KeypointParams(coord_format='xy', label_fields=['keypoint_labels']))
>>>
>>> result = transform(
... image=image,
... mask=mask,
... bboxes=bboxes,
... bbox_labels=bbox_labels,
... keypoints=keypoints,
... keypoint_labels=keypoint_labels,
... )
>>> transformed_image = result['image']
>>> transformed_mask = result['mask']