How can I accurately get the fringes of this profile.

I have the following profile and I want to get the fringes (peaks along the fringes) that are shown.
What I want is accurately get the sape of this fringes I did edge detection but I don't think it's rigorous for this type of calculations. I have attached the .mat file if you want to look. All I want to is accuratly follow the local maxima of these fringes as shown in the figure below:
Did someone encounter similar problem. Thank you very much for the help.

댓글 수: 2

I wonder if it would work to do a findpeaks() across each row of the image, and trace the evolution?
It might help to start from the middle row and track down until each peak disappears, and then go up and track upwards until each peak disappears.
yes! I think it's a good idea here is my approach based on your comment.
load('fringes.mat'); % Load Data
T = abs(P_resize); % Convert to absolute values
figure, imagesc(T), colormap(jet);
colorbar;
hold on;
minpeakdist = 3; % Minimum distance between peaks
minpeakh = 3e-5; % Minimum peak height
x_coords = [];
y_coords = [];
% Process all rows from top to bottom
for k = 1:size(T,1)
tex = T(k,:);
[pks, locs] = findpeaks(tex, 'MinPeakDistance', minpeakdist, 'MinPeakHeight', minpeakh);
if ~isempty(locs)
x_coords = [x_coords, X(k, locs)];
y_coords = [y_coords, Y(k, locs)];
end
end
% Plot detected fringes
figure;
plot(x_coords, y_coords, 'r*', 'markersize', 2);
hold on;
xlabel('X Coordinate');
ylabel('Y Coordinate');
title('Detected Fringes in Real-World Coordinates');
colorbar;

댓글을 달려면 로그인하십시오.

 채택된 답변

Mathieu NOE
Mathieu NOE 2025년 2월 17일
hello
this is a very simple (simplistic ?) approach
I used peakseek for faster execution vs findpeaks but you can use your own prefered tool for this job
of course I suspect you would have prefered a solution where each line data is stored in a specific cell array
here it's just the whole points , not yet organized.
load('fringes.mat')
T = abs(P_resize);
figure,imagesc(T)
colorbar
hold on
minpeakdist = 3;
minpeakh = 3e-5;
for k = 20:size(T,1)
tex = T(k,:);
[locs{k}, pks{k}]=peakseek(tex,minpeakdist,minpeakh);
plot(locs{k},k*ones(size(locs{k})),'r*','markersize',2);
end

댓글 수: 6

maybe with a good clustering algorithm you could separate each line
made some attempts with for example
T = abs(P_resize);
figure,imagesc(T)
colorbar
hold on
minpeakdist = 3;
minpeakh = 1e-5;
xlocs_all= [];
ylocs_all= [];
for k = 20:size(T,1)
tex = T(k,:);
[locs, pks]=peakseek(tex,minpeakdist,minpeakh);
xlocs = locs;
ylocs = k*ones(size(locs));
%plot(xlocs,ylocs,'r.','markersize',2);
xlocs_all= [xlocs_all xlocs];
ylocs_all= [ylocs_all ylocs];
end
%% Run DBSCAN Clustering Algorithm
x = [xlocs_all;ylocs_all];
radius = 10;
tic
[clustCent,point2cluster,clustMembsCell] = MeanShiftCluster(x,radius); % NB : x must be row oriented (bcse : [numDim,numPts] = size(x))
toc
numClust = length(clustMembsCell);
Colors=jet(numClust);
for k = 1:numClust
myMembers = clustMembsCell{k};
myClustCen = clustCent(:,k);
plot(x(1,myMembers),x(2,myMembers), '.','color',Colors(k,:))
% plot(myClustCen(1),myClustCen(2),'o','MarkerEdgeColor','k','MarkerFaceColor',Colors(k,:), 'MarkerSize',10)
end
similar stuff with dbscan
load('fringes.mat')
T = abs(P_resize);
figure,imagesc(T)
colorbar
hold on
minpeakdist = 3;
minpeakh = 1e-5;
xlocs_all= [];
ylocs_all= [];
for k = 20:size(T,1)
tex = T(k,:);
[locs, pks]=peakseek(tex,minpeakdist,minpeakh);
xlocs = locs;
ylocs = k*ones(size(locs));
%plot(xlocs,ylocs,'r.','markersize',2);
xlocs_all= [xlocs_all xlocs];
ylocs_all= [ylocs_all ylocs];
end
%% Run DBSCAN Clustering Algorithm
epsilon=2;
MinPts=3;
X = [xlocs_all' ylocs_all'];
tic
IDX=DBSCAN(X,epsilon,MinPts);
toc
%% Plot Results
PlotClusterinResult(X, IDX);
Thanks a lot this is exactly what I wanted!
Glad I could help ! I was quite unsure I would be able to propose a solution that works good enough
In the mean time I was trying to improve the results , so I implemented some new features , maybe you will be interested to see the results
  • resampled the data to a higher dimensions to better separate each fringe line from its neighbours - of course this will slow down the code but the wait is worth
  • when doing the peaks search in each slice of data , I apply first a baseline correction to the data so when the peaks are in a low amplitude area it's easier to catch them (so at the end the fringe data collected is larger in size and we have less "holes" between segments)
  • modified a bit the plot function after the clustering and added some code to store each individual fringe data in cell array Data{kk} .
  • we don't store the small segments : here I opted to store only what is above this threshold :
% minimum size of data to be plotted (we don't want to plot the tiny bits)
minsize = 100;
  • if the code works the same on your side , you should now have Data is a cell array of size 1x 25, so you have each individual fringe coordinates at your disposal
result should look like : (see the improvement vs the first code with dbscan )
load('fringes.mat')
T = abs(P_resize);
[m,n] = size(T);
% resample at higher resolution
upsample_factor = 4;
[x, y] = meshgrid(1:n, 1:m);
[xq, yq] = meshgrid(linspace(1, n, upsample_factor*n), linspace(1, m, upsample_factor*m));
T = interp2(x, y, T, xq, yq);
% plot
figure,imagesc(T)
colorbar
hold on
% parameters for baseline correction function
minpeakdist = 3*upsample_factor;
minpeakh = 1e-6;
% init
xlocs_all= [];
ylocs_all= [];
for k = 15*upsample_factor:size(T,1)
tex = T(k,:);
% baseline correction
[Base, texc]=baseline(tex(:));
% find the peaks in each slice of T
[locs, ~]=peakseek(texc,minpeakdist,minpeakh);
xlocs = locs;
pks = tex(locs);
ylocs = k*ones(size(locs));
%plot(xlocs,ylocs,'r*','markersize',2);
% store new data;
xlocs_all= [xlocs_all xlocs];
ylocs_all= [ylocs_all ylocs];
end
%% Run DBSCAN Clustering Algorithm
epsilon=2*upsample_factor;
MinPts=2;
X = [xlocs_all' ylocs_all'];
tic
IDX=DBSCAN(X,epsilon,MinPts);
toc
% minimum size of data to be plotted (we don't want to plot the tiny bits)
minsize = 100;
%% Plot Results
k=max(IDX);
Colors=hsv(k);
Legends = {};
kk = 0;
for i=0:k
Xi=X(IDX==i,:);
if i~=0
Style = '.';
MarkerSize = 12;
Color = Colors(i,:);
Legends{end+1} = ['Cluster #' num2str(i)];
else
Style = 'o';
MarkerSize = 6;
Color = [0 0 0];
if ~isempty(Xi)
Legends{end+1} = 'Noise';
end
end
% if ~isempty(Xi) % original code
if size(Xi,1)>=minsize % modified code
plot(Xi(:,1),Xi(:,2),Style,'MarkerSize',MarkerSize,'Color',Color);
% store the data if the size is large enough
kk = kk + 1;
Data{kk} = Xi;
end
end
hold off;
axis equal;
grid on;
forgot to say : you will need the below and attached functions for the baseline correction
here I had to make a tiny modification in baseline to avoid sometimes an error :
% if A(i-1)<A(i-2) && A(i-1)<A(i) % original code
if (A(i-1)<A(i-2) && A(i-1)<A(i)) || n>=l % mod MN : added condition (n>=l) to avoid error
function [Base, Corrected_Spectrum]=baseline(Spectrum)
%Input
%-------
%Spectrum: vector of size (N*1)
%Output
%-------
%Base: Identified Baseline vector of size (N*1)
%Corrected_Spectrum: Corrected Spectrum vector of size (N*1)
l=length(Spectrum);
lp=ceil(0.5*l);
initial_Spectrum=[ones(lp,1)*Spectrum(1) ; Spectrum ; ones(lp,1)*Spectrum(l)];
l2=length(initial_Spectrum);
S=initial_Spectrum;
n=1;
flag1=0;
while flag1==0
n=n+2;
i=(n-1)/2;
[Baseline, stripping]=peak_stripping(S,n);
A(i)=trapz(S-Baseline);
Stripped_Spectrum{i}=Baseline;
S=Baseline;
if i>3
% if A(i-1)<A(i-2) && A(i-1)<A(i) % original code
if (A(i-1)<A(i-2) && A(i-1)<A(i)) || n>=l % mod MN : added condition (n>=l) to avoid error
i_min=i-1;
flag1=1;
end
end
end
Base=Stripped_Spectrum{i_min};
Corrected_Spectrum=initial_Spectrum-Base; Corrected_Spectrum=Corrected_Spectrum(lp+1:lp+l);
Base=Base(lp+1:lp+l);
end
I don't have the Stats Toolbox, but if you have , you could try with Spectral Clustering

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

제품

릴리스

R2024b

질문:

2025년 2월 17일

댓글:

2025년 2월 18일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by