Let me provide a basic and a fully vectorized implementation that picks a random sample out of each kernel_size x kernel_size region sliding over the image.
Naive approach
def random_filter_naive(image: np.ndarray, kernel_size: int = 3, seed: int = None) -> np.ndarray:
# Check input dimensions
assert image.ndim == 2, "Input image must be a 2D array."
assert kernel_size > 0, "Kernel size must be a positive integer."
assert image.shape[0] >= kernel_size and image.shape[1] >= kernel_size, "Image dimensions must be at least as large as the kernel size."
if seed is not None:
np.random.seed(seed)
# Pad the image to handle borders
pad_size = kernel_size // 2
padded_image = np.pad(image, pad_size, mode='reflect')
filtered_image = np.zeros_like(image)
for i in range(image.shape[0]):
for j in range(image.shape[1]):
# Extract the neighborhood
neighborhood = padded_image[i:i+kernel_size, j:j+kernel_size]
# Flatten the neighborhood and choose a random element
random_value = np.random.choice(neighborhood.flatten())
filtered_image[i, j] = random_value
return filtered_image
Time taken for with naive approach on image with size (512, 512) and kernel size 13: 1.4364 seconds
Optimized approach
def random_filter(image: np.ndarray, kernel_size: int = 3, seed: int = None) -> np.ndarray:
# Check input dimensions
assert image.ndim == 2, "Input image must be a 2D array."
assert kernel_size > 0, "Kernel size must be a positive integer."
assert image.shape[0] >= kernel_size and image.shape[1] >= kernel_size, "Image dimensions must be at least as large as the kernel size."
if seed is not None:
np.random.seed(seed)
# Pad the image to handle borders
pad_size = kernel_size // 2
padded_image = np.pad(image, pad_size, mode='reflect')
rows, cols = image.shape
# Generate random row and column offsets for each pixel, respectively
rand_row_offsets = np.random.randint(0, kernel_size, size=(rows, cols))
rand_col_offsets = np.random.randint(0, kernel_size, size=(rows, cols))
# Compute the indices of the random neighbors
row_indices = np.arange(rows)[:, None] + rand_row_offsets
col_indices = np.arange(cols)[None, :] + rand_col_offsets
# Use advanced indexing to select random neighbors
filtered_image = padded_image[row_indices, col_indices]
return filtered_image
Time taken for fully vectorized approach on image with size (512, 512) and kernel size 13: 0.0050 seconds
Image courtesy of the Computing Sciences Unit, Tampere University
numpy/python. This is how I read the question. However, please include what you tried? Do you have a sample image? What is the dimension of image and kernel, respectively?x,yfor pixel position, choosedx,dy < NwhereNis the size of the rectangular support region then swap those two pixels. I rather like the designer tweaked JPEGs that are to a human eye very obviously of a farm tractor but some AI classifies as "a cat". Things have improved a lot on that front recently.