2014-12-11 5 views
3

У меня есть вектор, который содержит серые уровни пикселей в одной строке изображения. vec=IM(:,65); Я показал части массива, которые хочу обнаружить. Эти части будут пикелями моих объектов.Поиск пиков MATLAB

Как определить эти пиксели объектов?

Участок VEC: enter image description here Вектор здесь: vec

+0

Вы попробовали метод 'findpeaks'? У него есть параметры для фильтрации, я бы попробовал сначала «MinPeakprominence» – Daniel

+0

Согласен с Даниэлем. Используйте «findpeaks» на негативе ваших данных. – rayryeng

+0

Я скоро напишу ответ, если никто ничего не написал – rayryeng

ответ

3

Существуют различные способы поиска локальных пиков, здесь я использую отклонение от местной средней, то, разделяющая области, и сканирование каждого региона для минимума.

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 

Result Надеюсь, что это поможет, Менди

+0

Можете ли вы показать нам, какие результаты будут использовать ваш алгоритм, учитывая данные ОП? Можно ли найти эти пики и ** только ** те пики, которые указаны в примере OP? Судя по вашему коду, он находит все локальные пики, но не изолирует желаемые пики, указанные OP – rayryeng

+0

Очень приятно! Отличная работа. Тем не менее, я нахожу это навязчивым, поскольку вам нужно загрузить дополнительный файл, который не является частью собственного MATLAB. – rayryeng

+0

ОК я удалил внешний файл и добавил код для скользящего среднего фильтра. –

4

Это может быть легко решена с помощью findpeaks из обработки сигналов Toolbox. В частности, для данных я должен был назвать это таким образом:

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

findpeaks находит только положительные пики (локальные максимумы). Таким образом, нам нужно сделать так, чтобы все локальные минимумы становились локальными максимумами. Я сделал это, взяв максимальное значение вектора и вычитая с вектором. Поскольку существует так много локальных пиков, поле minpeakdistance позволяет находить пики, которые, по крайней мере, разделены между этими пиками. Я настроил это на 160. Кроме того, минимальная высота пика обнаруживает пики, которые превышают определенное число, которое я настроил как 22. pks находит фактические пиковые значения, а locs дает вам местоположения пиков в вашем сигнале. Нам нужно использовать locs, чтобы найти фактические пиковые данные, потому что мы выполнили это на зеркальной отраженной версии вашего сигнала. Таким образом, чтобы получить фактический пик данных, выполните следующие действия:

pks_final = vecs(loc); 

В качестве демонстрации, давайте построить этот сигнал, а также пики, которые были расположены на findpeaks:

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

Исходные данные нанесены в синий цвет, а обнаруженные пики - красным. Это то, что я получаю:

enter image description here


Удачи!

+0

@rayryend отличная идея. +1 для этого. Но один qn: почему бы не findpeaks (-vec, 'minpeakdistance', 160, 'minpeakheight', 22); зачем нужно max (vec) -vec? – lakesh

+1

@lakesh - Выполнение '-vec' отменяет все значения данных, а' minpeakheight' работает только для ** положительных ** значений. Если данные были центрированы на нуле, то '-vec' будет работать, но обратите внимание, что все точки выше 0. Если вы попробуете свое предложение, вы получите предупреждение, указывающее, что я сказал, и вы не найдете пиков. – rayryeng

+0

@lakesh - BTW, спасибо за ваш +1. – rayryeng

Смежные вопросы