1+ function obj = tfm_PeakFinder2(obj )
2+ % tfm_PeakFinder2 - Interactive interface to for the peak finding routine
3+ %
4+ % syntax: obj = tfm_PeakFinder2(obj)
5+ % Input:
6+ % obj - StatSTEM structure
7+ % Output:
8+ % obj - StatSTEM structure
9+
10+ % --------------------------------------------------------------------------
11+ % This file is part of StatSTEM
12+ %
13+ % Copyright: 2019, EMAT, University of Antwerp
14+ % Author: Thomas Friedrich
15+ % License: Open Source under GPLv3
16+ % Contact: sandra.vanaert@uantwerpen.be
17+ % --------------------------------------------------------------------------
18+ global thr d_min sigma xy hpf gr_cm cdat_0
19+ obs = obj .obs ;
20+ [ny ,nx ] = size(obs );
21+
22+ thr = 0 ;
23+ sigma = 10 ;
24+ d_min = 0 ;
25+
26+ % %%%%%%%%%%%%%%%%%
27+ % Figure Window %
28+ % %%%%%%%%%%%%%%%%%
29+
30+ % Create a new figure with given size and minimum size
31+ screensize = get(0 , ' Screensize' );
32+ s = round(screensize(3 : 4 )*0.8 );
33+ hpf.fig = figure(' units' ,' pixels' ,' outerposition' ,[screensize(3 )/2 - s(1 )/2 screensize(4 )/2 - s(2 )/2 s(1 ) s(2 )],' Name' ,' Peak Finder' ,' NumberTitle' ,' off' ,' Visible' ,' on' ,' Resize' ,' on' ,' DeleteFCN' ,@deleteFigure ,' MenuBar' ,' none' ,' ToolBar' ,' figure' );
34+ figRSfun = @(~,~) set(hpf .fig , ' position' , max([0 0 900 550 ], hpf .fig .Position ));
35+ hpf.fig.SizeChangedFcn = figRSfun ;
36+
37+ % Normalized vertical panel split position and border width
38+ v_sec = 0.22 ;
39+ br = 0.01 ;
40+
41+ % Create two sub-panels
42+ % Image Panel & Axis
43+ hpf.image.pan = uipanel(' Parent' ,hpf .fig ,' units' ,' normalized' ,' Position' ,[br v_sec 1 - br * 2 1 - br * 2 - v_sec ],' ShadowColor' ,[0 0 0 ],' ForegroundColor' ,[0 0 0 ],' HighlightColor' ,[0.95 0.95 0.95 ],' BackgroundColor' ,[0.8 0.8 0.8 ]);
44+ hpf.image.ax1 = subplot(1 ,2 ,1 ,' Parent' ,hpf .image .pan );
45+ hpf.image.ax2 = subplot(1 ,2 ,2 ,' Parent' ,hpf .image .pan );
46+
47+ % Parameter Panel
48+ hpf.par.pan = uipanel(' Parent' ,hpf .fig ,' units' ,' normalized' ,' Position' ,[br br * 2 1 - br * 2 v_sec - br ],' ShadowColor' ,[0 0 0 ],' ForegroundColor' ,[0 0 0 ],' HighlightColor' ,[0.95 0.95 0.95 ],' BackgroundColor' ,[0.8 0.8 0.8 ]);
49+ hpf.par.wb = axes(' Parent' ,hpf .par .pan ,' Position' ,[1 - 0.38 br * 6 .38 - br .15 ]);
50+ % Makeshift Waitbar
51+ gr_cm = [linspace(0 ,0.1 ,64 )' linspace(0 ,0.5 ,64 )' linspace(0 ,1 ,64 )' ];
52+ cdat_0 = zeros(1 ,128 );
53+ cdat = cdat_0 ;
54+ cdat(1 : 32 ) = sin(linspace(0 ,pi ,32 ));
55+ imagesc(hpf .par .wb ,cdat ); axis off ; colormap(gr_cm ); caxis([0 1 ]);
56+ hpf.par.wb.Toolbar = [];
57+
58+ % Info panel
59+ hpf.help.pan = uipanel(' Parent' ,hpf .par .pan ,' units' ,' normalized' ,' Position' ,[0.62 0.3 0.38 - br 0.6 ],' ShadowColor' ,[0 0 0 ],' ForegroundColor' ,[0 0 0 ],' HighlightColor' ,[0.95 0.95 0.95 ],' BackgroundColor' ,[0.8 0.8 0.8 ]);
60+ str = ' To help the peak finder program to detect the correct local maxima, set the approximate radius and minimum distance of the atomic columns in pixel units. Further, you can filter the peaks by a threshold value (normalized). The radius value alters the noise filter and is the most critical parameter. Rerun the Peak finder manually after changing this value!' ;
61+ hpf.help.text = uicontrol(' Parent' ,hpf .help .pan ,' Style' ,' text' ,' String' ,str ,' units' ,' normalized' ,' Position' ,[0 0 1 1 ],' FontSize' ,10 ,' BackgroundColor' ,[0.8 0.8 0.8 ],' horizontalAlignment' , ' left' );
62+
63+ % %%%%%%%%%%%%%%%%%%%%%%%
64+ % Interactive Elements %
65+ % %%%%%%%%%%%%%%%%%%%%%%%
66+
67+
68+ % Slider & Label %
69+ % %%%%%%%%%%%%%%%%%
70+ % Sigma
71+ est_lim_s = mean(nx ,ny )*0.1 ;
72+ SliderSi = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' slider' ,' units' ,' normalized' ,' Position' ,[br 0.38 0.2 0.15 ],' Min' ,3 ,' Max' ,est_lim_s );
73+ uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' text' ,' String' ,' Estimated Radius (px):' ,' units' ,' normalized' ,' Position' ,[br 0.8 0.2 0.15 ],' FontSize' ,10 ,' HorizontalAlignment' ,' left' ,' BackgroundColor' ,[0.8 0.8 0.8 ]);
74+ % uicontrol('Parent',hpf.par.pan,'Style','text','units','normalized','Position',[br 0.27 0.01 0.1],'String',num2str(3,0),'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right');
75+ % uicontrol('Parent',hpf.par.pan,'Style','text','units','normalized','Position',[0.2 0.27 0.01 0.1],'String',num2str(est_lim_s,1),'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left');
76+
77+ % Threshold
78+ SliderTh = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' slider' ,' units' ,' normalized' ,' Position' ,[br + 0.2 0.38 0.2 0.15 ],' Min' ,0 ,' Max' ,1 );
79+ uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' text' ,' String' ,' Threshold value:' ,' units' ,' normalized' ,' Position' ,[br + 0.2 0.8 0.2 0.15 ],' FontSize' ,10 ,' HorizontalAlignment' ,' left' ,' BackgroundColor' ,[0.8 0.8 0.8 ]);
80+ % uicontrol('Parent',hpf.par.pan,'Style','text','units','normalized','Position',[br+0.2 0.27 0.01 0.1],'String','0','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right');
81+ % uicontrol('Parent',hpf.par.pan,'Style','text','units','normalized','Position',[0.4 0.27 0.01 0.1],'String','1','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left');
82+
83+ % Peak Distance
84+ est_lim_d = mean(nx ,ny )*0.1 ;
85+ SliderDm = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' slider' ,' units' ,' normalized' ,' Position' ,[br + 0.4 0.38 0.2 0.15 ],' Min' ,0 ,' Max' ,est_lim_d );
86+ uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' text' ,' String' ,' Minimum Distance (px):' ,' units' ,' normalized' ,' Position' ,[br + 0.4 0.8 0.2 0.15 ],' FontSize' ,10 ,' HorizontalAlignment' ,' left' ,' BackgroundColor' ,[0.8 0.8 0.8 ]);
87+ % uicontrol('Parent',hpf.par.pan,'Style','text','units','normalized','Position',[br+0.4 0.27 0.01 0.1],'String','0','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right');
88+ % uicontrol('Parent',hpf.par.pan,'Style','text','units','normalized','Position',[0.6 0.27 0.01 0.1],'String','1','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left');
89+
90+ % Textboxes %
91+ % %%%%%%%%%%%%%%%%%
92+ txt_sig = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' edit' ,' String' ,num2str(thr ),' units' ,' normalized' ,' Position' ,[br 0.6 0.2 0.15 ],' FontSize' ,10 );
93+ txt_th = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' edit' ,' String' ,num2str(sigma ),' units' ,' normalized' ,' Position' ,[0.2 + br 0.6 0.2 0.15 ],' FontSize' ,10 );
94+ txt_d_min = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' edit' ,' String' ,num2str(d_min ),' units' ,' normalized' ,' Position' ,[0.4 + br 0.6 0.2 0.15 ],' FontSize' ,10 );
95+
96+ % Buttons %
97+ % %%%%%%%%%%%%%%%%%
98+ btn_width = 1 /(5 + br * 7 );
99+ hpf.par.findPeaks = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' pushbutton' ,' String' ,' Run peak finder' ,' units' ,' normalized' ,' Position' ,[br br * 6 btn_width 0.2 ],' FontSize' ,10 );
100+ hpf.close = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' pushbutton' ,' String' ,' Cancel' ,' units' ,' normalized' ,' Position' ,[br + btn_width br * 6 btn_width 0.2 ],' FontSize' ,10 );
101+ hpf.storeClose = uicontrol(' Parent' ,hpf .par .pan ,' Style' ,' pushbutton' ,' String' ,' Confirm values' ,' units' ,' normalized' ,' Position' ,[br + btn_width * 2 br * 6 btn_width 0.2 ],' FontSize' ,10 );
102+
103+
104+
105+ % %%%%%%%%%%%%%%%%%%%%%%%
106+ % Set & Draw %
107+ % %%%%%%%%%%%%%%%%%%%%%%%
108+
109+ % Textbox & Slider Values
110+ set(SliderTh ,' Value' ,thr )
111+ set(txt_th ,' String' ,num2str(thr ))
112+ set(SliderSi ,' Value' ,sigma )
113+ set(txt_sig ,' String' ,num2str(sigma ))
114+ set(SliderDm ,' Value' ,d_min )
115+ set(txt_d_min ,' String' ,num2str(d_min ))
116+
117+ % Callbacks
118+ set(txt_th ,' Callback' ,{@upTXTbox ,SliderTh ,1 ,hpf })
119+ set(SliderTh ,' Callback' ,{@slideThres ,txt_th ,1 ,hpf })
120+ set(txt_sig ,' Callback' ,{@upTXTbox ,SliderSi ,2 ,hpf })
121+ set(SliderSi ,' Callback' ,{@slideThres ,txt_sig ,2 ,hpf })
122+ set(txt_d_min ,' Callback' ,{@upTXTbox ,SliderDm ,3 ,hpf })
123+ set(SliderDm ,' Callback' ,{@slideThres ,txt_d_min ,3 ,hpf })
124+
125+ set(hpf .close ,' Callback' ,{@closeFig ,hpf .fig })
126+ set(hpf .storeClose ,' Callback' ,{@closeStoreFig ,hpf .fig })
127+ set(hpf .par .findPeaks ,' Callback' ,{@findPeaks ,obs ,hpf })
128+
129+ % Draw
130+ drawnow();
131+
132+ % Show the images, initial peak finding
133+ findPeaks([],[],obs ,hpf )
134+ uiwait(hpf .fig )
135+
136+ % %%%%%%%%%%%%%%%%%%%%%%%
137+ % Functions %
138+ % %%%%%%%%%%%%%%%%%%%%%%%
139+
140+
141+ function slideThres(hObject ,~,h_valThres ,prm ,hpf )
142+ switch prm
143+ case 1
144+ thr = get(hObject ,' Value' );
145+ set(h_valThres ,' String' ,num2str(thr ))
146+ findPeaks([],[],obs , hpf )
147+ case 2
148+ tim = run_waitbar(hpf .par .wb ,cdat );
149+ sigma = get(hObject ,' Value' );
150+ set(h_valThres ,' String' ,num2str(sigma ))
151+ obs_fil = tfm_find_peaks_2d(obs , sigma , thr , d_min );
152+ xy = [];
153+ updatePlot(hpf ,obs_fil )
154+ stop(tim );
155+ delete(tim );
156+ waitbar_out
157+ case 3
158+ d_min = get(hObject ,' Value' );
159+ set(h_valThres ,' String' ,num2str(d_min ))
160+ findPeaks([],[],obs , hpf )
161+ end
162+ end
163+
164+ function upTXTbox(hObject ,~,h_slidThres ,prm , hpf )
165+ switch prm
166+ case 1
167+ thr = str2double(get(hObject ,' String' ));
168+ set(h_slidThres ,' Value' ,thr )
169+ findPeaks([],[],obs , hpf )
170+ case 2
171+ tim = run_waitbar(hpf .par .wb ,cdat );
172+ sigma = str2double(get(hObject ,' String' ));
173+ set(h_slidThres ,' Value' ,sigma )
174+ obs_fil = tfm_find_peaks_2d(obs , sigma , thr , d_min );
175+ xy = [];
176+ updatePlot(hpf ,obs_fil )
177+ stop(tim );
178+ delete(tim );
179+ waitbar_out
180+ case 3
181+ d_min = str2double(get(hObject ,' String' ));
182+ set(h_slidThres ,' Value' ,d_min )
183+ findPeaks([],[],obs , hpf )
184+ end
185+
186+ updatePlot(hpf ,obs_fil )
187+ end
188+
189+ function updatePlot(hpf ,obs_fil )
190+
191+ subplot(hpf .image .ax1 );
192+ imagesc(obs );colormap gray ;axis equal off ;
193+
194+ subplot(hpf .image .ax2 );
195+ imagesc(obs_fil );colormap gray ;axis equal off ;
196+
197+ if ~isempty(xy )
198+ hold on ;
199+ plot(xy(: ,1 ),xy(: ,2 ),' .r' )
200+ hold off ;
201+ end
202+
203+ waitbar_out ;
204+
205+ end
206+
207+ function findPeaks(~,~,obs ,hpf )
208+
209+ tim = run_waitbar(hpf .par .wb ,cdat );
210+
211+ [obs_fil , xy ] = tfm_find_peaks_2d(obs , sigma , thr , d_min );
212+
213+ updatePlot(hpf ,obs_fil )
214+
215+ stop(tim );
216+ delete(tim );
217+
218+ waitbar_out ;
219+ end
220+
221+ function closeStoreFig(~,~,fig )
222+ obj.coordinates = [xy * obj .dx ,ones(length(xy ),1 )];
223+ close(fig )
224+ end
225+
226+ function closeFig(~,~,fig )
227+ close(fig )
228+ end
229+
230+ function deleteFigure(hObject ,~)
231+ uiresume(hObject )
232+ delete(hObject )
233+ end
234+
235+
236+ function waitbar_out()
237+ hpf.par.wb.Children.CData = cdat_0 ;
238+ set(hpf .par .wb ,' visible' ,' off' )
239+ hpf.par.wb.Colormap = gr_cm ;
240+ drawnow ;
241+ end
242+
243+ function timerObject = run_waitbar(wb_axis ,cdat )
244+
245+ timerDat.axes = wb_axis ;
246+ timerDat.im_dat = cdat ;
247+ timerDat.n_tick = 1 ;
248+ timerObject = timer(' TimerFcn' ,@tick ,...
249+ ' ExecutionMode' ,' fixedRate' ,...
250+ ' Period' ,0.01 ,...
251+ ' UserData' , timerDat );
252+ start(timerObject );
253+
254+ function tick(timerObj ,event )
255+
256+ timerData = get(timerObj , ' UserData' );
257+ im = timerData .im_dat ;
258+ im = circshift(im ,timerData .n_tick ,2 );
259+ timerData.axes.Children.CData = im ;
260+ timerData.axes.Colormap = gr_cm ;
261+ timerData.n_tick = timerData .n_tick + 1 ;
262+ set(timerObj , ' UserData' , timerData );
263+ drawnow
264+ end
265+ end
266+ end
0 commit comments