# -*- coding: utf-8 -*- import numpy as np import scipy from scipy import fftpack import torch from math import cos, sin from numpy import zeros, ones, prod, array, pi, log, min, mod, arange, sum, mgrid, exp, pad, round from numpy.random import randn, rand from scipy.signal import convolve2d import cv2 import random # import utils_image as util ''' modified by Kai Zhang (github: https://github.com/cszn) 03/03/2019 ''' def get_uperleft_denominator(img, kernel): ''' img: HxWxC kernel: hxw denominator: HxWx1 upperleft: HxWxC ''' V = psf2otf(kernel, img.shape[:2]) denominator = np.expand_dims(np.abs(V)**2, axis=2) upperleft = np.expand_dims(np.conj(V), axis=2) * np.fft.fft2(img, axes=[0, 1]) return upperleft, denominator def get_uperleft_denominator_pytorch(img, kernel): ''' img: NxCxHxW kernel: Nx1xhxw denominator: Nx1xHxW upperleft: NxCxHxWx2 ''' V = p2o(kernel, img.shape[-2:]) # Nx1xHxWx2 denominator = V[..., 0]**2+V[..., 1]**2 # Nx1xHxW upperleft = cmul(cconj(V), rfft(img)) # Nx1xHxWx2 * NxCxHxWx2 return upperleft, denominator def c2c(x): return torch.from_numpy(np.stack([np.float32(x.real), np.float32(x.imag)], axis=-1)) def r2c(x): return torch.stack([x, torch.zeros_like(x)], -1) def cdiv(x, y): a, b = x[..., 0], x[..., 1] c, d = y[..., 0], y[..., 1] cd2 = c**2 + d**2 return torch.stack([(a*c+b*d)/cd2, (b*c-a*d)/cd2], -1) def cabs(x): return torch.pow(x[..., 0]**2+x[..., 1]**2, 0.5) def cmul(t1, t2): ''' complex multiplication t1: NxCxHxWx2 output: NxCxHxWx2 ''' real1, imag1 = t1[..., 0], t1[..., 1] real2, imag2 = t2[..., 0], t2[..., 1] return torch.stack([real1 * real2 - imag1 * imag2, real1 * imag2 + imag1 * real2], dim=-1) def cconj(t, inplace=False): ''' # complex's conjugation t: NxCxHxWx2 output: NxCxHxWx2 ''' c = t.clone() if not inplace else t c[..., 1] *= -1 return c def rfft(t): return torch.rfft(t, 2, onesided=False) def irfft(t): return torch.irfft(t, 2, onesided=False) def fft(t): return torch.fft(t, 2) def ifft(t): return torch.ifft(t, 2) def p2o(psf, shape): ''' # psf: NxCxhxw # shape: [H,W] # otf: NxCxHxWx2 ''' otf = torch.zeros(psf.shape[:-2] + shape).type_as(psf) otf[...,:psf.shape[2],:psf.shape[3]].copy_(psf) for axis, axis_size in enumerate(psf.shape[2:]): otf = torch.roll(otf, -int(axis_size / 2), dims=axis+2) otf = torch.rfft(otf, 2, onesided=False) n_ops = torch.sum(torch.tensor(psf.shape).type_as(psf) * torch.log2(torch.tensor(psf.shape).type_as(psf))) otf[...,1][torch.abs(otf[...,1])= abs(y)] = abs(x)[abs(x) >= abs(y)] maxxy[abs(y) >= abs(x)] = abs(y)[abs(y) >= abs(x)] minxy = np.zeros(x.shape) minxy[abs(x) <= abs(y)] = abs(x)[abs(x) <= abs(y)] minxy[abs(y) <= abs(x)] = abs(y)[abs(y) <= abs(x)] m1 = (rad**2 < (maxxy+0.5)**2 + (minxy-0.5)**2)*(minxy-0.5) +\ (rad**2 >= (maxxy+0.5)**2 + (minxy-0.5)**2)*\ np.sqrt((rad**2 + 0j) - (maxxy + 0.5)**2) m2 = (rad**2 > (maxxy-0.5)**2 + (minxy+0.5)**2)*(minxy+0.5) +\ (rad**2 <= (maxxy-0.5)**2 + (minxy+0.5)**2)*\ np.sqrt((rad**2 + 0j) - (maxxy - 0.5)**2) h = None return h def fspecial_gaussian(hsize, sigma): hsize = [hsize, hsize] siz = [(hsize[0]-1.0)/2.0, (hsize[1]-1.0)/2.0] std = sigma [x, y] = np.meshgrid(np.arange(-siz[1], siz[1]+1), np.arange(-siz[0], siz[0]+1)) arg = -(x*x + y*y)/(2*std*std) h = np.exp(arg) h[h < scipy.finfo(float).eps * h.max()] = 0 sumh = h.sum() if sumh != 0: h = h/sumh return h def fspecial_laplacian(alpha): alpha = max([0, min([alpha,1])]) h1 = alpha/(alpha+1) h2 = (1-alpha)/(alpha+1) h = [[h1, h2, h1], [h2, -4/(alpha+1), h2], [h1, h2, h1]] h = np.array(h) return h def fspecial_log(hsize, sigma): raise(NotImplemented) def fspecial_motion(motion_len, theta): raise(NotImplemented) def fspecial_prewitt(): return np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]]) def fspecial_sobel(): return np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]]) def fspecial(filter_type, *args, **kwargs): ''' python code from: https://github.com/ronaldosena/imagens-medicas-2/blob/40171a6c259edec7827a6693a93955de2bd39e76/Aulas/aula_2_-_uniform_filter/matlab_fspecial.py ''' if filter_type == 'average': return fspecial_average(*args, **kwargs) if filter_type == 'disk': return fspecial_disk(*args, **kwargs) if filter_type == 'gaussian': return fspecial_gaussian(*args, **kwargs) if filter_type == 'laplacian': return fspecial_laplacian(*args, **kwargs) if filter_type == 'log': return fspecial_log(*args, **kwargs) if filter_type == 'motion': return fspecial_motion(*args, **kwargs) if filter_type == 'prewitt': return fspecial_prewitt(*args, **kwargs) if filter_type == 'sobel': return fspecial_sobel(*args, **kwargs) def fspecial_gauss(size, sigma): x, y = mgrid[-size // 2 + 1 : size // 2 + 1, -size // 2 + 1 : size // 2 + 1] g = exp(-((x ** 2 + y ** 2) / (2.0 * sigma ** 2))) return g / g.sum() def blurkernel_synthesis(h=37, w=None): # https://github.com/tkkcc/prior/blob/879a0b6c117c810776d8cc6b63720bf29f7d0cc4/util/gen_kernel.py w = h if w is None else w kdims = [h, w] x = randomTrajectory(250) k = None while k is None: k = kernelFromTrajectory(x) # center pad to kdims pad_width = ((kdims[0] - k.shape[0]) // 2, (kdims[1] - k.shape[1]) // 2) pad_width = [(pad_width[0],), (pad_width[1],)] if pad_width[0][0]<0 or pad_width[1][0]<0: k = k[0:h, 0:h] else: k = pad(k, pad_width, "constant") x1,x2 = k.shape if np.random.randint(0, 4) == 1: k = cv2.resize(k, (random.randint(x1, 5*x1), random.randint(x2, 5*x2)), interpolation=cv2.INTER_LINEAR) y1, y2 = k.shape k = k[(y1-x1)//2: (y1-x1)//2+x1, (y2-x2)//2: (y2-x2)//2+x2] if sum(k)<0.1: k = fspecial_gaussian(h, 0.1+6*np.random.rand(1)) k = k / sum(k) # import matplotlib.pyplot as plt # plt.imshow(k, interpolation="nearest", cmap="gray") # plt.show() return k def kernelFromTrajectory(x): h = 5 - log(rand()) / 0.15 h = round(min([h, 27])).astype(int) h = h + 1 - h % 2 w = h k = zeros((h, w)) xmin = min(x[0]) xmax = max(x[0]) ymin = min(x[1]) ymax = max(x[1]) xthr = arange(xmin, xmax, (xmax - xmin) / w) ythr = arange(ymin, ymax, (ymax - ymin) / h) for i in range(1, xthr.size): for j in range(1, ythr.size): idx = ( (x[0, :] >= xthr[i - 1]) & (x[0, :] < xthr[i]) & (x[1, :] >= ythr[j - 1]) & (x[1, :] < ythr[j]) ) k[i - 1, j - 1] = sum(idx) if sum(k) == 0: return k = k / sum(k) k = convolve2d(k, fspecial_gauss(3, 1), "same") k = k / sum(k) return k def randomTrajectory(T): x = zeros((3, T)) v = randn(3, T) r = zeros((3, T)) trv = 1 / 1 trr = 2 * pi / T for t in range(1, T): F_rot = randn(3) / (t + 1) + r[:, t - 1] F_trans = randn(3) / (t + 1) r[:, t] = r[:, t - 1] + trr * F_rot v[:, t] = v[:, t - 1] + trv * F_trans st = v[:, t] st = rot3D(st, r[:, t]) x[:, t] = x[:, t - 1] + st return x def rot3D(x, r): Rx = array([[1, 0, 0], [0, cos(r[0]), -sin(r[0])], [0, sin(r[0]), cos(r[0])]]) Ry = array([[cos(r[1]), 0, sin(r[1])], [0, 1, 0], [-sin(r[1]), 0, cos(r[1])]]) Rz = array([[cos(r[2]), -sin(r[2]), 0], [sin(r[2]), cos(r[2]), 0], [0, 0, 1]]) R = Rz @ Ry @ Rx x = R @ x return x if __name__ == '__main__': a = opt_fft_size([111]) print(a) print(fspecial('gaussian', 5, 1)) print(p2o(torch.zeros(1,1,4,4).float(),(14,14)).shape) k = blurkernel_synthesis(11) import matplotlib.pyplot as plt plt.imshow(k, interpolation="nearest", cmap="gray") plt.show()