source: prextra/impatch.m

Last change on this file was 5, checked in by bduin, 14 years ago
File size: 9.6 KB
RevLine 
[5]1function lab = impatch(fig,action,varargin)
2%IMPATCH Create and change a polygon label overlay on an image
3%
4%      OUT = IMPATCH(H,ACTION,VARARGIN)
5%
6% Draw some patches as overlay over an image, given by the handle H.
7% Possible actions are:
8%
9%  Press left button to draw lines, right button to end the patch.
10% >> impatch(h,'label',2,[0 0 1])    defines label 2 in blue
11% >> impatch(h,'label',3,'g')        defines label 2 in blue
12% >> impatch(h,'label',1)            set active label to 1
13% >> out = impatch(h,'get')          get the labels out.
14%  Press ESC to cancel drawing and deleting the polygon.
15%
16% When H is not given, it will take the current active figure.
17%
18% Example (when you have dipimage in your path):
19%   im = laplace;
20%   impaint                % now click somewhere in the image,
21%                           % use leftclick to add more lines
22%                           % use rightclick to close the polygon
23%   impaint('label',2,'b') % make a second label, in blue
24%   impaint('label',3,[0 1 0]) %make third label in green
25%   out = impaint('get')   % get the label image out
26
27% Copyright: D.M.J. Tax, D.M.J.Tax@prtools.org
28% Faculty EWI, Delft University of Technology
29% P.O. Box 5031, 2600 GA Delft, The Netherlands
30
31if nargin<2
32        action = [];
33end
34if nargin<1
35        fig = gcbf;
36end
37% If the figure handle is not given, add it and move all other
38% arguments:
39if ischar(fig)
40        varargin = {action varargin{:}};
41        action = fig;
42        fig = gcbf;
43end
44if ~ishandle(fig) & isnumeric(fig) % we forgot to put 'label' ???
45        varargin = {fig action varargin{:}};
46        action = 'label';
47        fig = gcf;
48end
49
50
51% First check if the figure has already some patches:
52if isempty(fig)
53        fig = gcf;
54        UD = get(fig,'userdata');
55        if isempty(UD) | ~isfield(UD,'impatch')
56                % OK, now we have to initialize it...
57                % maybe for speedup??:
58                set(fig,'busyaction','cancel','doublebuffer','on');
59                UD.impatch = [];
60                % initialize
61                UD.impatch.mode = 'start';
62                UD.impatch.curr = 0;  % current polygon
63                UD.impatch.currlab = 1;  % current label
64                UD.impatch.clrs = [1 0 0];
65                UD.impatch.nrp = 0;   % no polygons defined
66                UD.impatch.h = [];
67                UD.impatch.hlab = [];
68                % take care of the position and size
69                % check if there is an axes object:
70                hh = get(fig,'children');
71                for i=length(hh)
72                        isax(i) = strcmp('axes',get(hh(i),'type'));
73                end
74                if sum(isax)==0
75                        error('I cannot find an axes!');
76                end
77                if sum(isax)>1
78                        error('There are several axes defined:-(');
79                end
80                hax = hh(find(isax));
81                UD.impatch.units = get(hax,'units');
82                set(hax,'units','normalized');
83                UD.impatch.pos = get(hax,'position');
84                him = get(hax,'children');
85                % for recomputing the coordinates:
86                UD.impatch.sz = size(get(him,'cdata'));
87                UD.impatch.W = UD.impatch.sz(2)./UD.impatch.pos(3);
88                UD.impatch.H = UD.impatch.sz(1)./UD.impatch.pos(4);
89                UD.impatch.pos(3) = UD.impatch.pos(3)+UD.impatch.pos(1);
90                UD.impatch.pos(4) = UD.impatch.pos(4)+UD.impatch.pos(2);
91
92                % take care for the callback function:
93                %get(fig,'windowbuttondownfcn')  %DXD
94                UD.impatch.olddownfcn = get(fig,'windowbuttondownfcn');
95                UD.impatch.oldmotionfcn = get(fig,'windowbuttonmotionfcn');
96                UD.impatch.oldkeypressfcn = get(fig,'keypressfcn');
97                set(fig,'userdata',UD);
98               
99                set(fig,'WindowButtonDownFcn','impatch');
100                set(fig,'KeyPressFcn','impatch(''character'')');
101        end
102end
103
104% The special case that we get direct actions, instead of mouse events:
105if ~isempty(action)
106        switch action
107        case 'get'     % we want to get the label image out
108                % set up:
109                UD = get(gcf,'userdata');
110                % go over all the patches:
111                lab = zeros(UD.impatch.sz);
112                [X,Y] = meshgrid(1:UD.impatch.sz(2), 1:UD.impatch.sz(1));
113                for i=1:length(UD.impatch.h)
114                        vx = get(UD.impatch.h(i),'xdata');
115                        vy = get(UD.impatch.h(i),'ydata');
116                        im = inpolygon(X,Y,vx,vy);
117                        I = find(im);
118                        lab(I) = UD.impatch.hlab(i);
119                        %lab = im;
120                end
121                return
122        case 'label'   % add a new label or change active label
123                % set up:
124                UD = get(gcf,'userdata');
125                newnr = varargin{1};
126                if newnr>size(UD.impatch.clrs,1)  % add a new label
127                        if length(varargin)<2
128                                error('I am expecting now a colour definition');
129                        end
130                        if (newnr>size(UD.impatch.clrs,1)+1)
131                                newnr=size(UD.impatch.clrs,1)+1;
132                        end
133                        % check if the color definition is acceptable:
134                        newclr = checkcolour(varargin{2});
135                        % and commit:
136                        UD.impatch.currlab = newnr;
137                        UD.impatch.clrs(newnr,:) = newclr;
138                else                             % change the active label
139                        if newnr>0
140                                UD.impatch.currlab = newnr;
141                        end
142                end
143                % Save the results:
144                set(gcf,'userdata',UD);
145                return;
146        case 'off'  % remove all traces from the figure
147                UD = get(gcf,'userdata');
148                if ~isempty(UD) & isfield(UD,'impatch')
149                        set(gcf,'windowbuttondownfcn',UD.impatch.olddownfcn);
150                        set(gcf,'windowbuttonmotionfcn',UD.impatch.oldmotionfcn);
151                        set(gcf,'keypressfcn',UD.impatch.oldkeypressfcn);
152                        delete(UD.impatch.h);
153                        UD = rmfield(UD,'impatch');
154                        if size(fieldnames(UD),1)==0, UD = []; end
155                        set(gcf,'userdata',UD);
156                        return
157                end
158        case 'character'   % A user pressed a key
159                ch = double(get(gcf,'currentcharacter'));
160                if isempty(ch), return, end
161                UD = get(gcf,'userdata');
162                switch ch
163                case 27 % ESCAPE
164%                       switch UD.impatch.mode
165%                       case 'draw'  % cancel this complete line
166                                UD.impatch.hlab(UD.impatch.curr) = [];
167                                delete(UD.impatch.h(UD.impatch.curr));
168                                UD.impatch.h(UD.impatch.curr) = [];
169                                UD.impatch.nrp = UD.impatch.nrp-1;
170                                UD.impatch.curr = 0;
171                                UD.impatch.mode = 'start';
172                                set(gcf,'userdata',UD);
173                                set(fig,'windowbuttonmotionfcn',UD.impatch.oldmotionfcn);
174%                       case 'move'  % cancel the movement of the node
175%                       end
176                end
177                return
178
179        end
180end
181
182% Get the userdata
183UD = get(fig,'userdata');
184% Check if the cursor position is inside the image:
185set(fig,'units','normalized');
186pos = get(fig,'currentpoint');
187if pos(1)<UD.impatch.pos(1) | pos(1)>UD.impatch.pos(3) | ...
188        pos(2)<UD.impatch.pos(2) | pos(2)>UD.impatch.pos(4)
189        return
190end
191% Compute the position:
192pos(1) = round((pos(1)-UD.impatch.pos(1))*UD.impatch.W);
193pos(2) = round(UD.impatch.sz(1) - (pos(2)-UD.impatch.pos(2))*UD.impatch.H);
194
195% Now do the actions that need the position of the cursor:
196if strcmp(action,'move');
197        switch UD.impatch.mode
198        case 'draw'
199                h = UD.impatch.h(UD.impatch.curr);
200                xd = get(h,'xdata'); yd = get(h,'ydata');
201                xd(end) = pos(1);    yd(end) = pos(2);
202                set(h,'xdata',xd);   set(h,'ydata',yd);
203        case 'move' % we want to move a node...
204                minnode = UD.impatch.currnode;
205                hh = UD.impatch.h(UD.impatch.curr);
206                xd = get(hh,'xdata'); yd = get(hh,'ydata');
207                xd(minnode) = pos(1); yd(minnode) = pos(2);
208                set(hh,'xdata',xd);   set(hh,'ydata',yd);
209        end
210        % Save the results:
211        set(fig,'userdata',UD);
212        return
213end
214
215% Otherwise we have to check mouse buttons
216switch UD.impatch.mode
217case 'start'   % start a new line
218        switch get(fig,'selectiontype')
219        case 'alt'
220                if length(UD.impatch.h)==0
221                        return;
222                end
223                % Find nearest node
224                mind = inf; minp = 0; minnode = 0;
225                for i=1:length(UD.impatch.h)
226                        hh = UD.impatch.h(i);
227                        coord = [get(hh,'xdata') get(hh,'ydata')];
228                        N = size(coord,1);
229                        diff = repmat(pos,N,1) - coord;
230                        [diff,nodenr] = min(sum(diff.*diff,2));
231                        if diff<mind
232                                mind = diff;
233                                minp = i;
234                                minnode = nodenr;
235                        end
236                end
237                % If we are close enough, we should move the node...
238                if mind<100  % magic distance
239                        UD.impatch.curr = minp;
240                        UD.impatch.currnode = minnode;
241                        hh = UD.impatch.h(minp);
242                        xd = get(hh,'xdata'); yd = get(hh,'ydata');
243                        xd(minnode) = pos(1); yd(minnode) = pos(2);
244                        set(hh,'xdata',xd);   set(hh,'ydata',yd);
245                        UD.impatch.mode = 'move';
246                        set(fig,'WindowButtonMotionFcn','impatch(''move'')');
247                end
248        case 'normal'
249                % Set the number of the current polygon
250                UD.impatch.nrp = UD.impatch.nrp+1;
251                UD.impatch.curr = UD.impatch.nrp;
252                % Define the colour for this line
253                thisclr = UD.impatch.clrs(UD.impatch.currlab,:);
254                UD.impatch.h(UD.impatch.curr) = line([pos(1) pos(1)],[pos(2) pos(2)]);
255                UD.impatch.hlab(UD.impatch.curr) = UD.impatch.currlab;
256                set(UD.impatch.h(UD.impatch.curr),'color',thisclr);
257                UD.impatch.mode = 'draw';
258                set(fig,'WindowButtonMotionFcn','impatch(''move'')');
259        end
260        % Save the results:
261        set(fig,'userdata',UD);
262        return
263case 'draw'
264        switch get(fig,'selectiontype')
265        case 'normal' % extend the line with a new node
266                h = UD.impatch.h(UD.impatch.curr);
267                xd = get(h,'xdata'); yd = get(h,'ydata');
268                xd(end+1) = pos(1);    yd(end+1) = pos(2);
269                set(h,'xdata',xd);   set(h,'ydata',yd);
270        case 'alt'    % end the line, and fill the polygon
271                h = UD.impatch.h(UD.impatch.curr);
272                xd = get(h,'xdata'); yd = get(h,'ydata');
273                % get rid of the last point, that was only glued to the pointer:
274                xd(end) = []; yd(end) = [];
275                delete(h);  % will this be OK??
276                myclr = UD.impatch.clrs(UD.impatch.hlab(UD.impatch.curr),:);
277                h = patch(xd,yd, myclr);
278                set(h,'facealpha',0.5);
279                UD.impatch.h(UD.impatch.curr) = h;
280                UD.impatch.curr = 0;
281                UD.impatch.mode = 'start';
282                set(fig,'windowbuttonmotionfcn',UD.impatch.oldmotionfcn);
283        end
284case 'move'
285        minnode = UD.impatch.currnode;
286        hh = UD.impatch.h(UD.impatch.curr);
287        xd = get(hh,'xdata'); yd = get(hh,'ydata');
288        xd(minnode) = pos(1); yd(minnode) = pos(2);
289        set(hh,'xdata',xd);   set(hh,'ydata',yd);
290        UD.impatch.mode = 'start';
291end
292
293% Save the results:
294set(fig,'userdata',UD);
295
296return
297
298function newclr = checkcolour(newclr)
299
300if ischar(newclr)
301        if length(newclr)>1
302                error('I am expecting a single character');
303        end
304        defclrchar = 'rbgymc';
305        defclrs = [1 0 0; 0 0 1; 0 1 0; 1 1 0; 1 0 1; 0 1 1];
306        newclr = find(defclrchar==newclr);
307        if isempty(newclr)
308                error('Not a legal colour definition');
309        end
310        newclr = defclrs(newclr,:);
311else
312        newclr = newclr(:)';
313        if length(newclr)~=3
314                error('The colour definition should have R G and B');
315        end
316        if any(newclr<0)
317                error('Colour values should be larger than 0.');
318        end
319        if any(newclr>1)
320                error('Colour values should be smaller than 1.');
321        end
322end
323return
Note: See TracBrowser for help on using the repository browser.