Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 482 lines (424 sloc) 15.172 kb
e2b66f4 separate 1.0 and 2.0
thouis authored
1 function [level,bw] = CPthresh_tool(im,cmap,defaultLevel) %mainfunction
2 %THRESH_TOOL Interactively select intensity level for image thresholding.
3 % THRESH_TOOL launches a GUI (graphical user interface) for thresholding
4 % an intensity input image, IM. IM is displayed in the top left corner. A
5 % colorbar and IM's histogram are displayed on the bottom. A line on the
6 % histogram indicates the current threshold level. A binary image is
7 % displayed in the top right based on the selected level. To change the
8 % level, click and drag the line. The output image updates automatically.
9 %
10 % There are two ways to use this tool.
11 %
12 %Mode 1 - nonblocking behavior:
13 % THRESH_TOOL(IM) launches GUI tool. You can continue using the MATLAB
14 % Desktop. Since no results are needed, the function does not block
15 % execution of other commands.
16 %
17 % THRESH_TOOL(IM,CMAP) allows the user to specify the colormap, CMAP. If
18 % not specified, the default colormap is used.
19 %
20 % THRESH_TOOL(IM,CMAP,DEFAULTLEVEL) allows the user to specify the
21 % default threshold level. If not specified, DEFAULTLEVEL is determined
22 % by GRAYTHRESH. Valid values for DEFAULTLEVEL must be consistent with
23 % the data type of IM for integer intensity images: uint8 [0,255], uint16
24 % [0,65535], int16 [-32768,32767].
25 %
26 % Example
27 % x = imread('rice.png');
28 % thresh_tool(x) %no return value, so MATLAB keeps running
29 %
30 %Mode 2 - blocking behavior:
31 % LEVEL = THRESH_TOOL(...) returns the user selected level, LEVEL, and
32 % MATLAB waits for the result before proceeding. This blocking behavior
33 % mode allows the tool to be inserted into an image processing algorithm
34 % to support an automated workflow.
35 %
36 % [LEVEL,BW] = THRESH_TOOL(...) also returns the thresholded binary
37 % output image, BW.
38 %
39 % Example
40 % x = imread('rice.png');
41 % lev = thresh_tool(x) %MATLAB waits for GUI tool to finish
42 %
43 %See also COLORMAP, GRAYTHRESH, IM2BW.
44 %
45 % CellProfiler is distributed under the GNU General Public License.
46 % See the accompanying file LICENSE for details.
47 %
48 % Developed by the Whitehead Institute for Biomedical Research.
49 % Copyright 2003,2004,2005.
50 %
51 % Please see the AUTHORS file for credits.
52 %
53 % Website: http://www.cellprofiler.org
54 %
55 % $Revision$
56
57 %defensive programming
58 error(nargchk(1,3,nargin))
59 error(nargoutchk(0,2,nargout))
60
61 %validate defaultLevel within range
62 if nargin>2 %uer specified DEFAULTLEVEL
63 dataType = class(im);
64 switch dataType
65 case 'uint8','uint16','int16'
66 if defaultLevel<intmin(dataType) | defaultLevel>intmax(dataType)
67 error(['Specified DEFAULTLEVEL outside class range for ' dataType])
68 elseif defaultLevel<min(im(:)) | defaultLevel>max(im(:))
69 error('Specified DEFAULTLEVEL outside data range for IM')
70 end
71 case 'double','single'
72 %okay, do nothing
73 otherwise
74 error(['Unsupport image type ' dataType])
75 end %switch
76 end
77
78 max_colors=1000; %practical limit
79
80 %calculate bins centers
81 color_range = double(limits(im));
82 if isa(im,'uint8') %special case [0 255]
83 color_range = [0 255];
84 num_colors = 256;
85 di = 1;
86 elseif isinteger(im)
87 %try direct indices first
88 num_colors = diff(color_range)+1;
89 if num_colors<max_colors %okay
90 di = 1; %inherent bins
91 else %too many levels
92 num_colors = max_colors; %practical limit
93 di = diff(color_range)/(num_colors-1);
94 end
95 else %noninteger
96 %try infering discrete resolution first (intensities often quantized)
97 di = min(diff(sort(unique(im(:)))));
98 num_colors = round(diff(color_range)/di)+1;
99 if num_colors>max_colors %too many levels
100 num_colors = max_colors; %practical limit
101 di = diff(color_range)/(num_colors-1);
102 end
103 end
104 bin_ctrs = [color_range(1):di:color_range(2)];
105 FmtSpec = ['%.' num2str(ceil(-log10(di))) 'f'];
106
107 %new figure - interactive GUI tool for level segmenting
108 h_fig = CPfigure;
109 set(h_fig,'ToolBar','Figure','Color',[0.7,0.7,0.9])
110 if nargin>1 && isstr(cmap) && strmatch(lower(cmap),'gray')
111 full_map = gray(num_colors);
112 elseif nargin>1 && isnumeric(cmap) && length(size(cmap))==2 && size(cmap,2)==3
113 full_map = cmap;
114 else
115 full_map = jet(num_colors);
116 end
117 setappdata(h_fig,'im',im)
118 setappdata(h_fig,'FmtSpec',FmtSpec)
119
120 %top left - input image
121 h_ax1 = axes('unit','norm','pos',[0.05 0.35 0.4 0.60]);
122 rgb = im2rgb(im,full_map);
123 function rgb = im2rgb(im,full_map); %nested
124 %coerce intensities into gray range [0,1]
125 gray = imadjust(im,[],[0 1]);
126 %generate indexed image
127 num_colors = size(full_map,1);
128 ind = gray2ind(gray,num_colors);
129 %convert indexed image to RGB
130 rgb = ind2rgb(ind,full_map);
131 end %im2rgb
132
133 image(rgb), axis image
134 %subimage(im,full_map)
135 axis off, title('Input Image')
136
137 %top right - segmented (eventually)
138 h_ax2 = axes('unit','norm','pos',[0.55 0.35 0.4 0.60]);
139 axis off
140 setappdata(h_fig,'h_ax2',h_ax2)
141
142 %next to bottom - intensity distribution
143 h_hist = axes('unit','norm','pos',[0.05 0.1 0.9 0.2]);
144 n = hist(double(im(:)),bin_ctrs);
145 bar(bin_ctrs,n)
146 if length(n) > 4,
147 axis([color_range limits(n(2:end-1))]); %ignore saturated end scaling
148 else
149 axis([color_range limits(n)]);
150 end
151 set(h_hist,'xtick',[],'ytick',[])
152 title('Intensity Distribution')
153
154 %very bottom - colorbar
155 h_cbar = axes('unit','norm','pos',[0.05 0.05 0.9 0.05],'tag','thresh_tool_cbar');
156 subimage(color_range,[0.5 1.5],1:num_colors,full_map)
157 set(h_cbar,'ytick',[],'xlim',color_range)
158 axis normal
159
160 v=version;
161 if str2num(v(1:3))>=7
162 %link top axes (pan & zoom)
163 linkaxes([h_ax1 h_ax2])
164 %link bottom axes (X only - pan & zoom)
165 linkaxes([h_hist h_cbar],'x')
166 end
167
168 %colorbar tick locations
169 set(h_cbar,'xtick',color_range)
170
171 %threshold level - initial guess (graythresh)
172 if nargin>2 %user specified default level
173 my_level = defaultLevel;
174 else %graythresh default
175 lo = double(color_range(1));
176 hi = double(color_range(2));
177 norm_im = (double(im)-lo)/(hi-lo);
178 norm_level = graythresh(norm_im); %GRAYTHRESH assumes DOUBLE range [0,1]
179 my_level = norm_level*(hi-lo)+lo;
180 end
181
182 %display level as vertical line
183 axes(h_hist)
184 h_lev = vline(my_level,'-');
185 set(h_lev,'LineWidth',2,'color',0.5*[1 1 1],'UserData',my_level)
186 setappdata(h_fig,'h_lev',h_lev)
187
188 %attach draggable behavior for user to change level
189 move_vline(h_lev,@update_plot);
190
191 axes(h_cbar)
192 y_lim = get(h_cbar,'ylim');
193
194 % PLACE TEXT LOCATION ON COLORBAR (Laurens)
195 %h_text = text(my_level,mean(y_lim),num2str(round(my_level)));
196 h_text = text(my_level,mean(y_lim),'dummy','HorizontalAlignment','Center');
197 if nargin<2
198 text_color = 0.5*[1 1 1];
199 else
200 text_color = 'm';
201 end
202 set(h_text,'FontWeight','Bold','color',text_color,'Tag','cbar_text')
203 movex_text(h_text,my_level)
204 %%%%%%%%%%%%%%%%%%%%%%%%
205
206 %segmented image
207 bw = im>my_level;
208 axes(h_ax2)
209 hold on
210 subimage(bw), axis off, axis ij
211 hold off
212 title('Segmented')
213
214 update_plot
215
216 %add reset button (resort to initial guess)
217 h_reset = uicontrol('unit','norm','pos',[0.0 0.95 .1 .05]);
218 set(h_reset,'string','Reset','callback',@ResetOriginalLevel)
219
220 if nargout>0 %return result(s)
221 h_done = uicontrol('unit','norm','pos',[0.9 0.95 0.1 0.05]);
222 set(h_done,'string','Done','callback','delete(gcbo)') %better
223 %inspect(h_fig)
224 set(h_fig,'WindowStyle','modal')
225 waitfor(h_done)
226 if ishandle(h_fig)
227 h_lev = getappdata(gcf,'h_lev');
228 level = mean(get(h_lev,'xdata'));
229 if nargout>1
230 h_im2 = findobj(h_ax2,'type','image');
231 bw = logical(rgb2gray(get(h_im2,'cdata')));
232 end
233 delete(h_fig)
234 else
235 warning('THRESHTOOL:UserAborted','User Aborted - no return value')
236 level = [];
237 end
238 end
239
240 end %thresh_tool (mainfunction)
241
242
243 function ResetOriginalLevel(hObject,varargin) %subfunction
244 h_lev = getappdata(gcf,'h_lev');
245 init_level = get(h_lev,'UserData');
246 set(h_lev,'XData',init_level*[1 1])
247 text_obj = findobj('Type','Text','Tag','cbar_text');
248 movex_text(text_obj,init_level)
249 update_plot
250 end %ResetOriginalLevel (subfunction)
251
252
253 function update_plot %subfunction
254 im = getappdata(gcf,'im');
255 h_lev = getappdata(gcf,'h_lev');
256 my_level = mean(get(h_lev,'xdata'));
257 h_ax2 = getappdata(gcf,'h_ax2');
258 h_im2 = findobj(h_ax2,'type','image');
259 %segmented image
260 bw = (im>my_level);
261 rgb_version = repmat(double(bw),[1 1 3]);
262 set(h_im2,'cdata',rgb_version)
263 end %update_plot (subfunction)
264
265
266 %function rgbsubimage(im,map), error('DISABLED')
267
268
269 %----------------------------------------------------------------------
270 function move_vline(handle,DoneFcn) %subfunction
271 %MOVE_VLINE implements horizontal movement of line.
272 %
273 % Example:
274 % plot(sin(0:0.1:pi))
275 % h=vline(1);
276 % move_vline(h)
277 %
278 %Note: This tools strictly requires MOVEX_TEXT, and isn't much good
279 % without VLINE by Brandon Kuczenski, available at MATLAB Central.
280 %<http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=1039&objectType=file>
281
282 % This seems to lock the axes position
283 set(gcf,'Nextplot','Replace')
284 set(gcf,'DoubleBuffer','on')
285
286 h_ax=get(handle,'parent');
287 h_fig=get(h_ax,'parent');
288 setappdata(h_fig,'h_vline',handle)
289 if nargin<2, DoneFcn=[]; end
290 setappdata(h_fig,'DoneFcn',DoneFcn)
291 set(handle,'ButtonDownFcn',@DownFcn)
292
293 function DownFcn(hObject,eventdata,varargin) %Nested--%
294 set(gcf,'WindowButtonMotionFcn',@MoveFcn) %
295 set(gcf,'WindowButtonUpFcn',@UpFcn) %
296 end %DownFcn------------------------------------------%
297
298 function UpFcn(hObject,eventdata,varargin) %Nested----%
299 set(gcf,'WindowButtonMotionFcn',[]) %
300 DoneFcn=getappdata(hObject,'DoneFcn'); %
301 if isstr(DoneFcn) %
302 eval(DoneFcn) %
303 elseif isa(DoneFcn,'function_handle') %
304 feval(DoneFcn) %
305 end %
306 end %UpFcn--------------------------------------------%
307
308 function MoveFcn(hObject,eventdata,varargin) %Nested------%
309 h_vline=getappdata(hObject,'h_vline'); %
310 h_ax=get(h_vline,'parent'); %
311 cp = get(h_ax,'CurrentPoint'); %
312 xpos = cp(1); %
313 x_range=get(h_ax,'xlim'); %
314 if xpos<x_range(1), xpos=x_range(1); end %
315 if xpos>x_range(2), xpos=x_range(2); end %
316 XData = get(h_vline,'XData'); %
317 XData(:)=xpos; %
318 set(h_vline,'xdata',XData) %
319 %update text %
320 text_obj = findobj('Type','Text','Tag','cbar_text'); %
321 movex_text(text_obj,xpos) %
322 end %MoveFcn----------------------------------------------%
323
324 end %move_vline(subfunction)
325
326
327 %----------------------------------------------------------------------
328 function [x,y] = limits(a) %subfunction
329 % LIMITS returns min & max values of matrix; else scalar value.
330 %
331 % [lo,hi]=LIMITS(a) returns LOw and HIgh values respectively.
332 %
333 % lim=LIMITS(a) returns 1x2 result, where lim = [lo hi] values
334
335 if nargin~=1 | nargout>2 %bogus syntax
336 error('usage: [lo,hi]=limits(a)')
337 end
338
339 siz=size(a);
340
341 if prod(siz)==1 %scalar
342 result=a; % value
343 else %matrix
344 result=[min(a(:)) max(a(:))]; % limits
345 end
346
347 if nargout==1 %composite result
348 x=result; % 1x2 vector
349 elseif nargout==2 %separate results
350 x=result(1); % two scalars
351 y=result(2);
352 else %no result
353 ans=result % display answer
354 end
355
356 end %limits (subfunction)
357
358
359 %----------------------------------------------------------------------
360 function movex_text(h_txt,x_pos) %subfunction
361 FmtSpec=getappdata(get(get(h_txt,'parent'),'parent'),'FmtSpec');
362 msg=sprintf(FmtSpec,x_pos);
363 pos=get(h_txt,'position');
364 pos(1)=x_pos;
365 set(h_txt,'Position',pos,'String',msg)
366 end %movex_text
367
368
369 %--------------------------------------------------------------------------------------------------------------
370 function hhh=vline(x,in1,in2) %subfunction
371 % function h=vline(x, linetype, label)
372 %
373 % Draws a vertical line on the current axes at the location specified by 'x'. Optional arguments are
374 % 'linetype' (default is 'r:') and 'label', which applies a text label to the graph near the line. The
375 % label appears in the same color as the line.
376 %
377 % The line is held on the current axes, and after plotting the line, the function returns the axes to
378 % its prior hold state.
379 %
380 % The HandleVisibility property of the line object is set to "off", so not only does it not appear on
381 % legends, but it is not findable by using findobj. Specifying an output argument causes the function to
382 % return a handle to the line, so it can be manipulated or deleted. Also, the HandleVisibility can be
383 % overridden by setting the root's ShowHiddenHandles property to on.
384 %
385 % h = vline(42,'g','The Answer')
386 %
387 % returns a handle to a green vertical line on the current axes at x=42, and creates a text object on
388 % the current axes, close to the line, which reads "The Answer".
389 %
390 % vline also supports vector inputs to draw multiple lines at once. For example,
391 %
392 % vline([4 8 12],{'g','r','b'},{'l1','lab2','LABELC'})
393 %
394 % draws three lines with the appropriate labels and colors.
395 %
396 % By Brandon Kuczenski for Kensington Labs.
397 % brandon_kuczenski@kensingtonlabs.com
398 % 8 November 2001
399
400 % Downloaded 8/7/03 from MATLAB Central
401 % http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=1039&objectType=file
402
403 if length(x)>1 % vector input
404 for I=1:length(x)
405 switch nargin
406 case 1
407 linetype='r:';
408 label='';
409 case 2
410 if ~iscell(in1)
411 in1={in1};
412 end
413 if I>length(in1)
414 linetype=in1{end};
415 else
416 linetype=in1{I};
417 end
418 label='';
419 case 3
420 if ~iscell(in1)
421 in1={in1};
422 end
423 if ~iscell(in2)
424 in2={in2};
425 end
426 if I>length(in1)
427 linetype=in1{end};
428 else
429 linetype=in1{I};
430 end
431 if I>length(in2)
432 label=in2{end};
433 else
434 label=in2{I};
435 end
436 end
437 h(I)=vline(x(I),linetype,label);
438 end
439 else
440 switch nargin
441 case 1
442 linetype='r:';
443 label='';
444 case 2
445 linetype=in1;
446 label='';
447 case 3
448 linetype=in1;
449 label=in2;
450 end
451
452
453
454
455 g=ishold(gca);
456 hold on
457
458 y=get(gca,'ylim');
459 h=plot([x x],y,linetype);
460 if length(label)
461 xx=get(gca,'xlim');
462 xrange=xx(2)-xx(1);
463 xunit=(x-xx(1))/xrange;
464 if xunit<0.8
465 text(x+0.01*xrange,y(1)+0.1*(y(2)-y(1)),label,'color',get(h,'color'))
466 else
467 text(x-.05*xrange,y(1)+0.1*(y(2)-y(1)),label,'color',get(h,'color'))
468 end
469 end
470
471 if g==0
472 hold off
473 end
474 set(h,'tag','vline','handlevisibility','off')
475 end % else
476
477 if nargout
478 hhh=h;
479 end
480
481 end %vline (subfunction)
Something went wrong with that request. Please try again.