Finding peaks MATLAB

2019-01-26 19:42发布

问题:

I have a vector which includes a gray levels of pixels in a one line of an image. vec=IM(:,65); I showed the parts of the array I want to detect. These parts will be my objects' piksels.

How can I detect these object pixels?

Plot of vec: The vector is here: vec

回答1:

This can easily be solved using findpeaks from the Signal Processing Toolbox. Specifically, for your data I had to call it this way:

[pks, locs] = findpeaks(max(vec)-vec, 'minpeakdistance', 160, 'minpeakheight', 22);

findpeaks only finds positive peaks (local maxima). As such, what we need to do is invert this so that all of the local minima become local maxima. I did this by taking the maximum value of the vector and subtracting with the vector. Because there are so many local peaks, the minpeakdistance field allows you to find peaks that are at least separated by this much in between each peak. I tuned this to 160. Also, the minimum peak height finds peaks that are greater than a certain number, which I tuned to be 22. pks finds the actual peak values and locs gives you the locations of the peaks in your signal. We need to use locs to find the actual peak data because we performed this on the mirror reflected version of your signal. As such, to get the actual peak data, do this:

pks_final = vecs(loc);

As a demonstration, let's plot this signal as well as the peaks that were located by findpeaks:

plot(1:numel(vec), vec, locs, vec(locs), 'r.');

The original data is plotted in blue while the detected peaks are plotted in red. This is what I get:


Good luck!



回答2:

There are different ways to find local peaks, here i use the deviation from the local average, then separating the regions, and scanning each region for minimum.

clear
close all

load a

std_a=std( a(a~=0) );

SMOOTH_SIZE=131;% depend on data size
THRESHOLD=0.7*std_a;

smooth_a = conv(a,ones(SMOOTH_SIZE,1)/SMOOTH_SIZE,'same'); %ma filter

deviation_a=a-smooth_a; 
negdev_a=deviation_a.*(deviation_a<-THRESHOLD); %deviation in negative region (minimum)

negdev_a_left=[negdev_a(2:end) 0]; % helper to find starting index point
negdev_a_right=[0 negdev_a(1:end-1)]; % helper to find end index point

negdev_a(1)=0; negdev_a(end)=0; % make sure that we have zero point
indfrom=find(negdev_a==0 & negdev_a_left~=0); %start index per region
indto=find(negdev_a==0 & negdev_a_right~=0); %start index per region

if(length(indfrom)~=length(indto)), error('error in regions');end

peak_indexes=zeros(1,length(indfrom)); %number of regions
peak_counter = 0;

for i=1:length(indfrom)
  [center_min, min_idx]=min( a( indfrom(i):indto(i) ) );
  real_min_idx=indfrom(i)-1+min_idx; % convert back to original array index
  if( real_min_idx==indfrom(i) || real_min_idx==indto(i) ), continue; end
  left_max=max(a( indfrom(i):real_min_idx-1)); %helper to check for real minimum
  right_max=max(a( real_min_idx+1:indto(i)));  %helper to check for real minimum

  if(center_min<left_max && center_min<right_max) % check if this is real minimum
       peak_counter=peak_counter+1;
       peak_indexes(peak_counter)=real_min_idx;
  end
     % if you need subpixel accuracy you can do some weighted average in the min region
end
peak_indexes=peak_indexes(1:peak_counter); %narrow to found indexes

figure; plot(a); hold on; plot(smooth_a, 'k'); hold off;
figure; plot(deviation_a);hold on;  plot(negdev_a,'r.');hold off;
figure; plot(a);hold on; plot(peak_indexes, a(peak_indexes),'rO');hold off; %result

Hope this help, Mendi