def unwrap_phase_based_cosine_transform(mat, window=None): """ Unwrap a phase image using the cosine transform as described in Ref. [1]_. Parameters ---------- mat : array_like 2D array. Wrapped phase-image in the range of [-Pi; Pi]. window : array_like 2D array. Window is used for the cosine transform. Generated if None. Returns ------- array_like 2D array. Unwrapped phase-image. References ---------- .. [1] https://doi.org/10.1364/JOSAA.11.000107 """ (height, width) = mat.shape if window is None: window = _make_cosine_window(height, width) else: if window.shape != mat.shape: raise ValueError("Window must be the same size as the image!!!") rho_x = _wrap_to_pi(np.diff(mat, axis=1)) rho_y = _wrap_to_pi(np.diff(mat, axis=0)) rho_x2 = np.diff(rho_x, axis=1, prepend=0, append=0) rho_y2 = np.diff(rho_y, axis=0, prepend=0, append=0) rho = rho_x2 + rho_y2 mat_unwrap = idctn(dctn(rho) / window, overwrite_x=True) return mat_unwrap
def convJPG(im, Q): # Separarea canaleleor RGB r = im[:, :, 0] g = im[:, :, 1] b = im[:, :, 2] #Trecerea din RGB in YCbCr y, cb, cr = RGBtoYCbCr(r, g, b) for i in range(1, im.shape[0]): for j in range(1, im.shape[1]): if i % 8 == 0 and j % 8 == 0: xy = y[i - 8:i, j - 8:j] xcb = cb[i - 8:i, j - 8:j] xcr = cr[i - 8:i, j - 8:j] x = [xy, xcb, xcr] for k in range(len(x)): yt = dctn(x[k]) yjpeg = Q * (np.round(yt / Q)) xjpeg = idctn(yjpeg) x[k] = xjpeg y[i - 8:i, j - 8:j] = x[0] cb[i - 8:i, j - 8:j] = x[1] cr[i - 8:i, j - 8:j] = x[2] imr = im.copy() # Trecerea din YCrCb in RGB r, g, b = YCbCrtoRGB(y, cb, cr) imr[:, :, 0] = r imr[:, :, 1] = g imr[:, :, 2] = b return imr
def solvePoisson_precomped(rho, scale): """Solve the poisson equation "P phi = rho" using DCT Uses precomputed scaling factors `scale` """ dctPhi = dctn(rho) / scale # now invert to get the result phi = idctn(dctPhi, overwrite_x=True) return phi
def low_removed(filename): img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) height, width = img.shape[:2] dct_coef = dctn(img) dct_coef = dct_coef[30:, 30:] img = idctn(dct_coef) img = cv2.resize(img, dsize=(width, height), interpolation=cv2.INTER_LINEAR) cv2.imwrite("low_removed_" + filename, img)
def swap_dct_coef(): img_building = cv2.imread("img_building.png", cv2.IMREAD_GRAYSCALE) img_face = cv2.imread("img_face.png", cv2.IMREAD_GRAYSCALE) img_pattern = cv2.imread("img_pattern.png", cv2.IMREAD_GRAYSCALE) dct_building = dctn(img_building) dct_face = dctn(img_face) dct_pattern = dctn(img_pattern) # swap first 50x50 building and pattern coefficients dct_bp = dct_building.copy() dct_bp[:50, :50] = dct_pattern[:50, :50] img_bp = idctn(dct_bp) cv2.imwrite("swapped_bp.png", img_bp) # swap first 50x50 face and building coefficients dct_fb = dct_face.copy() dct_fb[:50, :50] = dct_building[:50, :50] img_fb = idctn(dct_fb) cv2.imwrite("swapped_fb.png", img_fb)
def low_frequencies(filename): img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) height, width = img.shape[:2] low_width = width // 4 low_height = height // 4 dct_coef = dctn(img) dct_coef = dct_coef[:low_height, :low_width] img = idctn(dct_coef) img = cv2.resize(img, dsize=(width, height), interpolation=cv2.INTER_LINEAR) cv2.imwrite("low_" + filename, img)
def solvePoisson(rho): """Solve the poisson equation "P phi = rho" using DCT """ dctRho = dctn(rho) N, M = rho.shape I, J = np.ogrid[0:N, 0:M] with np.errstate(divide='ignore'): dctPhi = dctRho / 2 / (np.cos(np.pi * I / M) + np.cos(np.pi * J / N) - 2) dctPhi[0, 0] = 0 # handling the inf/nan value # now invert to get the result phi = idctn(dctPhi) return phi
def rescale_coef(filename): img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) height, width = img.shape[:2] dct_coef = dctn(img) for i in range(dct_coef.shape[0]): for j in range(dct_coef.shape[1]): dist = (i**2 + j**2)**(1 / 3) if not np.isclose(dist, 0): dct_coef[i, j] /= dist img = idctn(dct_coef) img = cv2.resize(img, dsize=(width, height), interpolation=cv2.INTER_LINEAR) cv2.imwrite("rescaled_coef_" + filename, img)
def middle_frequencies(filename): img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) height, width = img.shape[:2] dct_coef = dctn(img) new_coef = np.zeros((height - 100, width - 10)) height = (height - 150) // 2 width = (width - 150) // 2 new_coef[:height, :width] = dct_coef[:height, :width] common_height = min(dct_coef.shape[0], new_coef.shape[0]) common_width = min(dct_coef.shape[1], new_coef.shape[1]) new_coef[-height:, :common_width] = dct_coef[-height:, :common_width] new_coef[:common_height, -width:] = dct_coef[:common_height, -width:] img = idctn(new_coef) img = cv2.resize(img, dsize=(width, height), interpolation=cv2.INTER_LINEAR) cv2.imwrite("middle_" + filename, img)
def comp_ch(ch, f): xch = dctn(ch) xch[f:] = 0 return idctn(xch)
freq_db_1 = 20 * np.log10(abs(Y1)) freq_db_2 = 20 * np.log10(abs(Y2)) freq_db_3 = 20 * np.log10(abs(Y3)) freq_db_4 = 20 * np.log10(abs(Y4)) plt.subplot(221).imshow(freq_db_1) plt.subplot(222).imshow(freq_db_2) plt.subplot(223).imshow(freq_db_3) plt.subplot(224).imshow(freq_db_4) plt.show() k = 120 Y_ziped = Y2.copy() Y_ziped[k:] = 0 X_ziped = idctn(Y_ziped) plt.imshow(X_ziped, cmap=plt.cm.gray) plt.show() Q_down = 10 X_jpeg = X.copy() X_jpeg = Q_down * np.round(X_jpeg / Q_down) plt.subplot(121).imshow(X, cmap=plt.cm.gray) plt.title('Original') plt.subplot(122).imshow(X_jpeg, cmap=plt.cm.gray) plt.title('Down-sampled') plt.show()
def unwrap( f_wrapped, phi_x=None, phi_y=None, max_iters=500, tol=np.pi / 5, lmbda=1, p=0, c=1.3, dtype="float32", debug=False, # boundary_conditions="neumann", ): """Unwrap interferogram phase Parameters ---------- f_wrapped (ndarray): wrapped phase image (interferogram) phi_x (ndarray): estimate of the x-derivative of the wrapped phase If not passed, will compute using `est_wrapped_gradient` phi_y (ndarray): estimate of the y-derivative of the wrapped phase If not passed, will compute using `est_wrapped_gradient` max_iters (int): maximum number of ADMM iterations to run tol (float): maximum allowed change for any pixel between ADMM iterations lmbda (float): splitting parameter of ADMM. Smaller = more stable, Larger = faster convergence. p (float): value used in shrinkage operator c (float): acceleration constant using in updating lagrange multipliers in ADMM dtype: numpy datatype for output debug (bool): print diagnostic ADMM information """ rows, columns = f_wrapped.shape num = rows * columns if dtype is None: dtype = f_wrapped.dtype else: f_wrapped = f_wrapped.astype(dtype) boundary_conditions = "neumann" if debug: print(f"Making Dx, Dy with BCs={boundary_conditions}") Dx, Dy = make_differentiation_matrices( *f_wrapped.shape, boundary_conditions=boundary_conditions) if phi_x is None or phi_y is None: phi_x, phi_y = est_wrapped_gradient(f_wrapped, Dx, Dy, dtype=dtype) # Lagrange multiplier variables Lambda_x = np.zeros_like(phi_x, dtype=dtype) Lambda_y = np.zeros_like(phi_y, dtype=dtype) # aux. variables for ADMM, holding difference between # unwrapped phase gradient and measured gradient from igram w_x = np.zeros_like(phi_x, dtype=dtype) w_y = np.zeros_like(phi_y, dtype=dtype) F_old = np.zeros_like(f_wrapped) # Get K ready once for solving linear system K = make_laplace_kernel(rows, columns, dtype=dtype) for iteration in range(max_iters): # update Unwrapped Phase F: solve linear eqn in fourier domain # rhs = dx.T @ phi[0].ravel() + dy.T @ phi[1].ravel() rx = w_x.ravel() + phi_x.ravel() - Lambda_x.ravel() ry = w_y.ravel() + phi_y.ravel() - Lambda_y.ravel() RHS = Dx.T * rx + Dy.T * ry # Use DCT for neumann: rho_hat = dctn(RHS.reshape(rows, columns), type=2, norm='ortho', workers=-1) F = idctn(rho_hat * K, type=2, norm='ortho', workers=-1) # calculate x, y gradients of new unwrapped phase estimate Fx = (Dx @ F.ravel()).reshape(rows, columns) Fy = (Dy @ F.ravel()).reshape(rows, columns) input_x = Fx - phi_x + Lambda_x input_y = Fy - phi_y + Lambda_y w_x, w_y = p_shrink(np.stack((input_x, input_y), axis=0), lmbda=lmbda, p=p, epsilon=0) # update lagrange multipliers Lambda_x += c * (Fx - phi_x - w_x) Lambda_y += c * (Fy - phi_y - w_y) change = np.max(np.abs(F - F_old)) if debug: print(f"Iteration:{iteration} change={change}") if change < tol or np.isnan(change): break else: F_old = F if debug: print(f"Finished after {iteration} with change={change}") return F
def kde2d(x, y, n=256, limits=None): """ Return the 2d density map from discrete observations via 2-dimensional diffusion Kernel density estimation. First the input data is binned. After binning, the function determines the optimal bandwidth according to the diffusion-based method. It then smooths the binned data over the grid using a Gaussian kernel with a standard deviation corresponding to that bandwidth. This module is based on the KDE-diffusion of Z. I. Botev, J. F. Grotowski, D. P. Kroese: Kernel density estimation via diffusion. Annals of Statistics 38 (2010), no. 5, 2916--2957. doi:10.1214/10-AOS799 and John Hennig DOI: 10.5281/zenodo.3830437 https://doi.org/10.5281/zenodo.3830437 **Parameters** x A lists of array of numbers that represent discrete observations of a random variable with two coordinate components. The observations are binned on a grid of n*n points, where ``n`` must be a power of 2 or will be coerced to the next one. If ``x`` and ``y`` are not the same length, the algorithm will raise a ``ValueError``. y A lists of array of numbers that represent discrete observations of a random variable with two coordinate components. The observations are binned on a grid of n*n points, where ``n`` must be a power of 2 or will be coerced to the next one. If ``x`` and ``y`` are not the same length, the algorithm will raise a ``ValueError``. n (optional) The number of grid points. It must be a power of 2. Otherwise, it will be coerced to the next power of two. The default is 256. limits (optional) Data ``limits`` specified as a tuple of tuples denoting ``((xmin, xmax), (ymin, ymax))``. If any of the values are ``None``, they will be inferred from the data. Each tuple, or even both of them, may also be replaced by a single value denoting the upper bound of a range centered at zero. The default is ``None``. **Returns** A tuple whose elements are the following: density The density map of the data. grid The grid at which the density is computed. bandwidth The optimal values (per axis) that the algorithm has determined. If the algorithm does not converge, it will raise a ``ValueError``. --------------------------------------------------------------------------- """ # Convert to arrays in case lists are passed in. x = np.array(x) y = np.array(y) # Make sure numbers of data points are consistent. N = len(x) if len(y) != N: raise ValueError('x and y must have the same length.') # Round up number of bins to next power of two. n = int(2**np.ceil(np.log2(n))) # Determine missing data limits. if limits is None: xmin = xmax = ymin = ymax = None elif isinstance(limits, tuple): (xlimits, ylimits) = limits if xlimits is None: xmin = xmax = None elif isinstance(xlimits, tuple): (xmin, xmax) = xlimits else: xmin = -xlimits xmax = +xlimits if ylimits is None: ymin = ymax = None elif isinstance(ylimits, tuple): (ymin, ymax) = ylimits else: ymin = -ylimits ymax = +ylimits else: xmin = -limits xmax = +limits ymin = -limits ymax = +limits if None in (xmin, xmax): delta = x.max() - x.min() if xmin is None: xmin = x.min() - delta / 4 if xmax is None: xmax = x.max() + delta / 4 if None in (ymin, ymax): delta = y.max() - y.min() if ymin is None: ymin = y.min() - delta / 4 if ymax is None: ymax = y.max() + delta / 4 deltax = xmax - xmin deltay = ymax - ymin # Bin samples on regular grid. (binned, xedges, yedges) = np.histogram2d(x, y, bins=n, range=((xmin, xmax), (ymin, ymax))) grid = (xedges[:-1], yedges[:-1]) # Compute discrete cosine transform. Adjust first component. transformed = dctn(binned / N) transformed[0, :] /= 2 transformed[:, 0] /= 2 # Pre-compute squared indices and transform components before solver loop. k = np.arange(n, dtype="float") # float avoids integer overflow. k2 = k**2 a2 = transformed**2 # Define internal functions to be solved iteratively. def γ(t): sigma = psi(0, 2, t) + psi(2, 0, t) + 2 * psi(1, 1, t) γ = (2 * np.pi * N * sigma)**(-1 / 3) return (t - γ) / γ def psi(i, j, t): if i + j <= 4: sigma = abs(psi(i + 1, j, t) + psi(i, j + 1, t)) C = (1 + 1 / 2**(i + j + 1)) / 3 pii = np.product(np.arange(1, 2 * i, 2)) pij = np.product(np.arange(1, 2 * j, 2)) t = (C * pii * pij / (np.pi * N * sigma))**(1 / (2 + i + j)) w = 0.5 * np.ones(n) w[0] = 1 w = w * np.exp(-np.pi**2 * k2 * t) wx = w * k2**i wy = w * k2**j return (-1)**(i + j) * np.pi**(2 * (i + j)) * wy @ a2 @ wx # Solve for optimal diffusion time t*. try: ts = brentq(lambda t: t - γ(t), 0, 0.1) except ValueError: raise ValueError('Bandwidth optimization did not converge.') from None # Calculate diffusion times along x- and y-axis. psi02 = psi(0, 2, ts) psi20 = psi(2, 0, ts) psi11 = psi(1, 1, ts) tx1 = (psi02**(3 / 4) / (4 * np.pi * N * psi20**(3 / 4) * (psi11 + np.sqrt(psi02 * psi20))))**(1 / 3) tx2 = (psi20**(3 / 4) / (4 * np.pi * N * psi02**(3 / 4) * (psi11 + np.sqrt(psi02 * psi20))))**(1 / 3) # Note: # The above uses the nomenclature from the paper. In the Matlab # reference, tx1 is called t_y, while tx2 is t_x. This is a curious # change in notation. It may be related to the fact that image # coordinates are typically in (y,x) index order, whereas matrices, # such as the binned histogram (in Matlab as much as in Python), # are in (x,y) order. The Matlab code eventually does return # image-like index order, though it never explicitly transposes # the density matrix. That is implicitly handled by its custom # implementation of the inverse transformation (idct2d), which # only employs one matrix transposition, not two as its forward # counterpart (dct2d). # Apply Gaussian filter with optimized kernel. smoothed = transformed * np.outer(np.exp(-np.pi**2 * k2 * tx2 / 2), np.exp(-np.pi**2 * k2 * tx1 / 2)) # Reverse transformation. smoothed[0, :] *= 2 smoothed[:, 0] *= 2 inverse = idctn(smoothed) # Normalize density. density = np.transpose(inverse) * n / deltax * n / deltay # Determine bandwidth from diffusion times. bandwidth = np.array([np.sqrt(tx2) * deltax, np.sqrt(tx1) * deltay]) # Return results. return (density, grid, bandwidth)
def kde2d(x, y, n=256, limits=None): """ Estimates the 2d density from discrete observations. The input is two lists/arrays `x` and `y` of numbers that represent discrete observations of a random variable with two coordinate components. The observations are binned on a grid of n×n points. `n` will be coerced to the next highest power of two if it isn't one to begin with. Data `limits` may be specified as a tuple of tuples denoting `((xmin, xmax), (ymin, ymax))`. If any of the values are `None`, they will be inferred from the data. Each tuple, or even both of them, may also be replaced by a single value denoting the upper bound of a range centered at zero. After binning, the function determines the optimal bandwidth according to the diffusion-based method. It then smooths the binned data over the grid using a Gaussian kernel with a standard deviation corresponding to that bandwidth. Returns the estimated `density` and the `grid` (along each of the two axes) upon which it was computed, as well as the optimal `bandwidth` values (per axis) that the algorithm determined. Raises `ValueError` if the algorithm did not converge or `x` and `y` are not the same length. """ # Convert to arrays in case lists are passed in. x = array(x) y = array(y) # Make sure numbers of data points are consistent. N = len(x) if len(y) != N: raise ValueError('x and y must have the same length.') # Round up number of bins to next power of two. n = int(2**ceil(log2(n))) # Determine missing data limits. if limits is None: xmin = xmax = ymin = ymax = None elif isinstance(limits, tuple): (xlimits, ylimits) = limits if xlimits is None: xmin = xmax = None elif isinstance(xlimits, tuple): (xmin, xmax) = xlimits else: xmin = -xlimits xmax = +xlimits if ylimits is None: ymin = ymax = None elif isinstance(ylimits, tuple): (ymin, ymax) = ylimits else: ymin = -ylimits ymax = +ylimits else: xmin = -limits xmax = +limits ymin = -limits ymax = +limits if None in (xmin, xmax): delta = x.max() - x.min() if xmin is None: xmin = x.min() - delta / 4 if xmax is None: xmax = x.max() + delta / 4 if None in (ymin, ymax): delta = y.max() - y.min() if ymin is None: ymin = y.min() - delta / 4 if ymax is None: ymax = y.max() + delta / 4 Δx = xmax - xmin Δy = ymax - ymin # Bin samples on regular grid. (binned, xedges, yedges) = histogram2d(x, y, bins=n, range=((xmin, xmax), (ymin, ymax))) grid = (xedges[:-1], yedges[:-1]) # Compute discrete cosine transform, then adjust first component. transformed = dctn(binned / N) transformed[0, :] /= 2 transformed[:, 0] /= 2 # Pre-compute squared indices and transform components before solver loop. k = arange(n, dtype='float') # "float" avoids integer overflow. k2 = k**2 a2 = transformed**2 # Define internal functions to be solved iteratively. def γ(t): Σ = ψ(0, 2, t) + ψ(2, 0, t) + 2 * ψ(1, 1, t) γ = (2 * π * N * Σ)**(-1 / 3) return (t - γ) / γ def ψ(i, j, t): if i + j <= 4: Σ = abs(ψ(i + 1, j, t) + ψ(i, j + 1, t)) C = (1 + 1 / 2**(i + j + 1)) / 3 Πi = product(arange(1, 2 * i, 2)) Πj = product(arange(1, 2 * j, 2)) t = (C * Πi * Πj / (π * N * Σ))**(1 / (2 + i + j)) w = 0.5 * ones(n) w[0] = 1 w = w * exp(-π**2 * k2 * t) wx = w * k2**i wy = w * k2**j return (-1)**(i + j) * π**(2 * (i + j)) * wy @ a2 @ wx # Solve for optimal diffusion time t*. try: ts = brentq(lambda t: t - γ(t), 0, 0.1) except ValueError: raise ValueError('Bandwidth optimization did not converge.') from None # Calculate diffusion times along x- and y-axis. ψ02 = ψ(0, 2, ts) ψ20 = ψ(2, 0, ts) ψ11 = ψ(1, 1, ts) tx1 = (ψ02**(3 / 4) / (4 * π * N * ψ20**(3 / 4) * (ψ11 + sqrt(ψ02 * ψ20))))**(1 / 3) tx2 = (ψ20**(3 / 4) / (4 * π * N * ψ02**(3 / 4) * (ψ11 + sqrt(ψ02 * ψ20))))**(1 / 3) # Note: # The above uses the nomenclature from the paper. In the Matlab # reference, tx1 is called t_y, while tx2 is t_x. This is a curious # change in notation. It may be related to the fact that image # coordinates are typically in (y,x) index order, whereas matrices, # such as the binned histogram (in Matlab as much as in Python), # are in (x,y) order. The Matlab code eventually does return # image-like index order, though it never explicitly transposes # the density matrix. That is implicitly handled by its custom # implementation of the inverse transformation (idct2d), which # only employs one matrix transposition, not two as its forward # counterpart (dct2d). # Apply Gaussian filter with optimized kernel. smoothed = transformed * outer(exp(-π**2 * k2 * tx2 / 2), exp(-π**2 * k2 * tx1 / 2)) # Reverse transformation after adjusting first component. smoothed[0, :] *= 2 smoothed[:, 0] *= 2 inverse = idctn(smoothed) # Normalize density. density = inverse * n / Δx * n / Δy # Determine bandwidth from diffusion times. bandwidth = array([sqrt(tx2) * Δx, sqrt(tx1) * Δy]) # Return results. return (density, grid, bandwidth)
def idct2(sub_img): return DCT2_library.idctn(sub_img, 2, norm='ortho')
# Solve for optimal diffusion time t*. ts = brentq(lambda t: t - γ(t), 0, 0.1) assert isclose(ts, ref['t_star']) # Calculate diffusion times along x- and y-axis. ψ02 = ψ(0, 2, ts) ψ20 = ψ(2, 0, ts) ψ11 = ψ(1, 1, ts) tx1 = (ψ02**(3 / 4) / (4 * π * N * ψ20**(3 / 4) * (ψ11 + sqrt(ψ02 * ψ20))))**(1 / 3) tx2 = (ψ20**(3 / 4) / (4 * π * N * ψ02**(3 / 4) * (ψ11 + sqrt(ψ02 * ψ20))))**(1 / 3) # Apply Gaussian filter with optimized kernel. smoothed = transformed * outer(exp(-π**2 * k2 * tx2 / 2), exp(-π**2 * k2 * tx1 / 2)) assert isclose(smoothed, ref['a_t']).all() # Reverse transformation. smoothed[0, :] *= 2 smoothed[:, 0] *= 2 inverse = idctn(smoothed) # Normalize density. density = inverse * n / Δx * n / Δy assert isclose(density.T, ref['density']).all() # Determine bandwidth from diffusion times. bandwidth = array([sqrt(tx2) * Δx, sqrt(tx1) * Δy]) assert isclose(bandwidth, ref['bandwidth']).all()