pythonarraysnumpyscipy

How can I seperate the fringes that have been calculated with findpeaks


I would like to seperate the fringes (the red curved lines) that I have calculated with scipy findpeaks how can I achive it. I would like to seperate them and store in the text file.

enter image description here

import numpy as np
from scipy.signal import find_peaks
import matplotlib.pyplot as plt


X = np.load('X.npy')  
Y = np.load('Y.npy')  
P_new = np.load('P_new.npy')  

# Example data: Replace with your actual data
T = np.real(P_new)  # Simulating a 2D matrix

# Plot the original image
plt.figure()
plt.imshow(T, cmap='jet', aspect='auto')
plt.colorbar()
plt.title('Original Image')
plt.show()

# Peak detection parameters
min_peak_dist = 3   # Minimum distance between peaks
min_peak_h = 3e-5   # Minimum peak height

x_coords = []
y_coords = []

# Process all rows from top to bottom
for k in range(T.shape[0]):
      tex = T[k, :]
      peaks, _ = find_peaks(tex, distance=min_peak_dist, height=min_peak_h)

if peaks.size > 0:
      x_coords.extend(X[k, peaks])
      y_coords.extend(Y[k, peaks])

# Plot detected peaks
plt.figure()
plt.scatter(x_coords, y_coords, color='r', s=2)  # 's' controls marker size
plt.xlabel('X Coordinate')
plt.ylabel('Y Coordinate')
plt.title('Detected Fringes in Real-World Coordinates')
plt.colorbar()
plt.show()

data for plotting is here

Want I want see is just seperate fringes like here: enter image description here

previously I could do it with cv2 method contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) but this is from finding the edges which is not very rigorous for my case as with finding peaks of the actual data.

Can someone help with this? Thanks


Solution

  • I had reasonable success using HDBSCAN.

    I first ran find_peaks to find peaks along y (rather than along x) - these are the black lines. I then clipped the image to within the blue square, and clustered the points using HDBSCAN. The final clusterings are coloured.

    enter image description here

    To plot a particular cluster, you could use:

    view_cluster = 20
    
    plt.figure(figsize=(3, 5))
    plt.scatter(*clustered[view_cluster].T, marker='.', s=1)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.title(f'Fringe {view_cluster}')
    plt.grid(linestyle=':')
    

    enter image description here

    Solution

    Load data and preprocess:

    import numpy as np
    from scipy.signal import find_peaks
    import matplotlib.pyplot as plt
    from matplotlib.patheffects import withTickedStroke
    
    #
    # Example data: Replace with your actual data
    #
    X_orig = np.load('X.npy')
    Y_orig = np.load('Y.npy')
    
    P_new = np.load('P_new.npy')
    n_rows, n_cols = P_new.shape
    T = np.real(P_new)  # Simulating a 2D matrix
    
    #Resample X and Y to match resolution of P_new
    # NB. I use the min/max values for simplicity
    x_axis = np.linspace(X_orig.min(), X_orig.max(), num=n_cols)
    y_axis = np.linspace(Y_orig.min(), Y_orig.max(), num=n_rows)
    
    X_grid, Y_grid = np.meshgrid(x_axis, y_axis)
    
    # Peak detection parameters
    min_peak_dist = 3   # Minimum distance between peaks
    min_peak_h = 3e-5   # Minimum peak height
    
    coords = []
    
    # Process all cols (x axis)
    for col_ix in range(n_cols):
        peaks, _ = find_peaks(T[:, col_ix], distance=min_peak_dist, height=min_peak_h)
    
        if not len(peaks):
            continue
    
        x_coord = x_axis[col_ix]
        peaks_y = y_axis[peaks]
        coords.extend([(x_coord, peak_y) for peak_y in peaks_y])
    
    coords = np.array(coords)
    x_coords, y_coords = coords.T
    
    
    #
    #Clip unwanted regions
    #
    ignore_left_of = 5
    ignore_below = 25
    # ignore_shorter_than = 10
    
    coords_clipped = coords[(x_coords > ignore_left_of) & (y_coords > ignore_below)]
    

    Cluster and visualise:

    #
    # HDBSCAN
    #
    from sklearn.cluster import HDBSCAN
    coord_labels = HDBSCAN().fit_predict(coords_clipped)
    
    clustered = [
        coords_clipped[coord_labels==cluster_id]
        for cluster_id in np.unique(coord_labels)
    ]
    
    #
    # Visualise
    #
    plt.figure()
    
    #Original image
    plt.matshow(
        T, extent=[x_axis.min(), x_axis.max(), y_axis.min(), y_axis.max()],
        cmap='Greys_r', origin='lower', vmax=5e-4, aspect='auto'
    )
    plt.gcf().set_size_inches(12, 6)
    
    plt.colorbar(extend='both')
    
    #Detected peaks
    plt.scatter(x_coords, y_coords, color='black', marker='.', s=0.2, alpha=0.4)
    
    # #Clip regions
    plt.axvline(ignore_left_of, path_effects=[withTickedStroke(angle=135)])
    plt.axhline(ignore_below, path_effects=[withTickedStroke(angle=-135)])
    
    #Clusters
    clustered = sorted(clustered, key=lambda members: members[:, 1].min())
    for cluster_members in clustered:
        plt.plot(*cluster_members[::30].T, alpha=0.2, zorder=0, lw=8)
    
    #Formatting
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()