3. Visualizing Curvelet Coefficients#

This example shows the how to visualize curvelet coefficients of an image, using as example a typical subsurface structure.

# sphinx_gallery_thumbnail_number = 3
import matplotlib.pyplot as plt
import numpy as np

from curvelops import FDCT2D, apply_along_wedges, curveshow

Input data#

inputfile = "../testdata/sigmoid.npz"

d = np.load(inputfile)
d = d["sigmoid"]
nx, nt = d.shape
dx, dt = 0.005, 0.004
x, t = np.arange(nx) * dx, np.arange(nt) * dt
aspect = dt / dx
opts_plot = dict(
    extent=(x[0], x[-1], t[-1], t[0]),
    cmap="gray",
    interpolation="lanczos",
    aspect=aspect,
)
vmax = 0.5 * np.max(np.abs(d))
figsize_aspect = aspect * nt / nx
fig, ax = plt.subplots(figsize=(8, figsize_aspect * 8), sharey=True, sharex=True)
ax.imshow(d.T, vmin=-vmax, vmax=vmax, **opts_plot)
ax.set(xlabel="Position [m]", ylabel="Time [s]", title=f"Data shape {d.shape}")
fig.tight_layout()
Data shape (256, 200)

Create Curvelet Transform#

nbscales = 4
nbangles_coarse = 8
allcurvelets = False  # Last scale will be a wavelet transform

Convert to a list of lists of ndarrays.

d_fdct_struct = Cop.struct(Cop @ d)

Real part of FDCT coefficients#

Curvelet coefficients are essentially directionally-filtered, shrunk versions of the original signal. Note that the “shrinking” does not preserve aspect ratio.

for j, c_scale in enumerate(d_fdct_struct, start=1):
    nangles = len(c_scale)
    rows = int(np.floor(np.sqrt(nangles)))
    cols = int(np.ceil(nangles / rows))
    fig, axes = plt.subplots(
        rows,
        cols,
        figsize=(5 * rows, figsize_aspect * 5 * rows),
    )
    fig.suptitle(f"Scale {j} ({len(c_scale)} wedge{'s' if len(c_scale) > 1 else ''})")
    axes = np.atleast_1d(axes).ravel()
    vmax = 0.5 * max(np.abs(Cweg).max() for Cweg in c_scale)
    for iw, (fdct_wedge, ax) in enumerate(zip(c_scale, axes), start=1):
        # Note that wedges are transposed in comparison to the input vector.
        # This is due to the underlying implementation of the transform. In
        # order to plot in the same manner as the data, we must first
        # transpose the wedge. We will using the transpose of the wedge for
        # visualization.
        c = fdct_wedge.real.T
        ax.imshow(c.T, vmin=-vmax, vmax=vmax, **opts_plot)
        ax.set(title=f"Wedge {iw} shape {c.shape}")
        ax.axis("off")
    fig.tight_layout()
  • Scale 1 (1 wedge), Wedge 1 shape (43, 33)
  • Scale 2 (8 wedges), Wedge 1 shape (39, 67), Wedge 2 shape (39, 67), Wedge 3 shape (87, 31), Wedge 4 shape (87, 31), Wedge 5 shape (39, 67), Wedge 6 shape (39, 67), Wedge 7 shape (87, 31), Wedge 8 shape (87, 31)
  • Scale 3 (16 wedges), Wedge 1 shape (71, 67), Wedge 2 shape (71, 67), Wedge 3 shape (71, 67), Wedge 4 shape (71, 67), Wedge 5 shape (87, 55), Wedge 6 shape (87, 55), Wedge 7 shape (87, 55), Wedge 8 shape (87, 55), Wedge 9 shape (71, 67), Wedge 10 shape (71, 67), Wedge 11 shape (71, 67), Wedge 12 shape (71, 67), Wedge 13 shape (87, 55), Wedge 14 shape (87, 55), Wedge 15 shape (87, 55), Wedge 16 shape (87, 55)
  • Scale 4 (1 wedge), Wedge 1 shape (256, 200)

Imaginagy part of FDCT coefficients#

Curvelops includes much of the above logic wrapped in the following curvelops.plot.cuveshow. Since we

# Normalize each coefficient by max abs
y_norm = apply_along_wedges(d_fdct_struct, lambda w, *_: w / np.abs(w).max())
figs = curveshow(
    y_norm,
    real=False,
    kwargs_imshow={**opts_plot, "vmin": -0.5, "vmax": 0.5},
)
  • Scale 0 (1 wedge)
  • Scale 1 (8 wedges), Wedge 0, Wedge 1, Wedge 2, Wedge 3, Wedge 4, Wedge 5, Wedge 6, Wedge 7
  • Scale 2 (16 wedges), Wedge 0, Wedge 1, Wedge 2, Wedge 3, Wedge 4, Wedge 5, Wedge 6, Wedge 7, Wedge 8, Wedge 9, Wedge 10, Wedge 11, Wedge 12, Wedge 13, Wedge 14, Wedge 15
  • Scale 3 (1 wedge)

Total running time of the script: ( 0 minutes 7.143 seconds)

Gallery generated by Sphinx-Gallery