示例#1
0
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
示例#2
0
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
示例#3
0
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
示例#4
0
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)
示例#5
0
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)
示例#6
0
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)
示例#7
0
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
示例#8
0
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)
示例#9
0
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)
示例#10
0
def comp_ch(ch, f):
    xch = dctn(ch)
    xch[f:] = 0
    return idctn(xch)
示例#11
0
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()
示例#12
0
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
示例#13
0
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)
示例#14
0
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)
示例#15
0
def idct2(sub_img):
    return DCT2_library.idctn(sub_img, 2, norm='ortho')
示例#16
0
# 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()