Source code for pywick.transforms.distortion_transforms

"""
Transforms to distort local or global information of an image
"""


import torch as th
import numpy as np
import random


[docs]class Scramble: """ Create blocks of an image and scramble them """ def __init__(self, blocksize): self.blocksize = blocksize def __call__(self, *inputs): outputs = [] idx = None for idx, _input in enumerate(inputs): size = _input.size() img_height = size[1] img_width = size[2] x_blocks = int(img_height/self.blocksize) # number of x blocks y_blocks = int(img_width/self.blocksize) ind = th.randperm(x_blocks*y_blocks) new = th.zeros(_input.size()) count = 0 for i in range(x_blocks): for j in range (y_blocks): row = int(ind[count] / x_blocks) column = ind[count] % x_blocks new[:, i*self.blocksize:(i+1)*self.blocksize, j*self.blocksize:(j+1)*self.blocksize] = \ _input[:, row*self.blocksize:(row+1)*self.blocksize, column*self.blocksize:(column+1)*self.blocksize] count += 1 outputs.append(new) return outputs if idx >= 1 else outputs[0]
[docs]class RandomChoiceScramble: def __init__(self, blocksizes): self.blocksizes = blocksizes def __call__(self, *inputs): blocksize = random.choice(self.blocksizes) outputs = Scramble(blocksize=blocksize)(*inputs) return outputs
def _blur_image(image, H): # break image up into its color components size = image.shape imr = image[0,:,:] img = image[1,:,:] imb = image[2,:,:] # compute Fourier transform and frequqnecy spectrum Fim1r = np.fft.fftshift(np.fft.fft2(imr)) Fim1g = np.fft.fftshift(np.fft.fft2(img)) Fim1b = np.fft.fftshift(np.fft.fft2(imb)) # Apply the lowpass filter to the Fourier spectrum of the image filtered_imager = np.multiply(H, Fim1r) filtered_imageg = np.multiply(H, Fim1g) filtered_imageb = np.multiply(H, Fim1b) newim = np.zeros(size) # convert the result to the spatial domain. newim[0,:,:] = np.absolute(np.real(np.fft.ifft2(filtered_imager))) newim[1,:,:] = np.absolute(np.real(np.fft.ifft2(filtered_imageg))) newim[2,:,:] = np.absolute(np.real(np.fft.ifft2(filtered_imageb))) return newim.astype('uint8') def _butterworth_filter(rows, cols, thresh, order): # X and Y matrices with ranges normalised to +/- 0.5 array1 = np.ones(rows) array2 = np.ones(cols) array3 = np.arange(1,rows+1) array4 = np.arange(1,cols+1) x = np.outer(array1, array4) y = np.outer(array3, array2) x = x - float(cols/2) - 1 y = y - float(rows/2) - 1 x = x / cols y = y / rows radius = np.sqrt(np.square(x) + np.square(y)) matrix1 = radius/thresh matrix2 = np.power(matrix1, 2*order) f = np.reciprocal(1 + matrix2) return f
[docs]class Blur: """ Blur an image with a Butterworth filter with a frequency cutoff matching local block size """ def __init__(self, threshold, order=5): """ scramble blocksize of 128 => filter threshold of 64 scramble blocksize of 64 => filter threshold of 32 scramble blocksize of 32 => filter threshold of 16 scramble blocksize of 16 => filter threshold of 8 scramble blocksize of 8 => filter threshold of 4 """ self.threshold = threshold self.order = order def __call__(self, *inputs): """ inputs should have values between 0 and 255 """ outputs = [] idx = None for idx, _input in enumerate(inputs): rows = _input.size(1) cols = _input.size(2) fc = self.threshold # threshold fs = 128.0 # max frequency n = self.order # filter order fc_rad = (fc/fs)*0.5 H = _butterworth_filter(rows, cols, fc_rad, n) _input_blurred = _blur_image(_input.numpy().astype('uint8'), H) _input_blurred = th.from_numpy(_input_blurred).float() outputs.append(_input_blurred) return outputs if idx >= 1 else outputs[0]
[docs]class RandomChoiceBlur: def __init__(self, thresholds, order=5): """ thresholds = [64.0, 32.0, 16.0, 8.0, 4.0] """ self.thresholds = thresholds self.order = order def __call__(self, *inputs): threshold = random.choice(self.thresholds) outputs = Blur(threshold=threshold, order=self.order)(*inputs) return outputs