1 function [gch, varargout] = GraphCut(mode, varargin)
\r
3 % Performing Graph Cut energy minimization operations on a 2D grid.
\r
6 % [gch ...] = GraphCut(mode, ...);
\r
10 % - mode: a string specifying mode of operation. See details below.
\r
13 % - gch: A handle to the constructed graph. Handle this handle with care
\r
14 % and don't forget to close it in the end!
\r
17 % - 'open': Create a new graph object
\r
18 % [gch] = GraphCut('open', DataCost, SmoothnessCost);
\r
19 % [gch] = GraphCut('open', DataCost, SmoothnessCost, vC, hC);
\r
20 % [gch] = GraphCut('open', DataCost, SmoothnessCost, SparseSmoothness);
\r
23 % - DataCost a height by width by num_labels matrix where
\r
24 % Dc(r,c,l) equals the cost for assigning label l to pixel at (r,c)
\r
25 % Note that the graph dimensions, and the number of labels are deduced
\r
26 % form the size of the DataCost matrix.
\r
27 % When using SparseSmoothness Dc is of (L)x(P) where L is the
\r
28 % number of labels and P is the number of nodes/pixels in the
\r
30 % - SmoothnessCost a #labels by #labels matrix where Sc(l1, l2)
\r
31 % is the cost of assigning neighboring pixels with label1 and
\r
32 % label2. This cost is spatialy invariant
\r
33 % - vC, hC:optional arrays defining spatialy varying smoothness cost.
\r
34 % Single precission arrays of size width*height.
\r
35 % The smoothness cost is computed using:
\r
36 % V_pq(l1, l2) = V(l1, l2) * w_pq
\r
37 % where V is the SmoothnessCost matrix
\r
38 % w_pq is spatialy varying parameter:
\r
39 % if p=(r,c) and q=(r+1,c) then w_pq = vCue(r,c)
\r
40 % if p=(r,c) and q=(r,c+1) then w_pq = hCue(r,c)
\r
41 % (therefore in practice the last column of vC and
\r
42 % the last row of vC are not used).
\r
43 % - SparseSmoothness: a sparse matrix defining both the graph
\r
44 % structure (might be other than grid) and the spatialy varying
\r
45 % smoothness term. Must be real positive sparse matrix of size
\r
46 % num_pixels by num_pixels, each non zero entry (i,j) defines a link
\r
47 % between pixels i and j with w_pq = SparseSmoothness(i,j).
\r
49 % - 'set': Set labels
\r
50 % [gch] = GraphCut('set', gch, labels)
\r
53 % - labels: a width by height array containing a label per pixel.
\r
54 % Array should be the same size of the grid with values
\r
58 % - 'get': Get current labeling
\r
59 % [gch labels] = GraphCut('get', gch)
\r
62 % - labels: a height by width array, containing a label per pixel.
\r
63 % note that labels values are in range [0..num_labels-1].
\r
66 % - 'energy': Get current values of energy terms
\r
67 % [gch se de] = GraphCut('energy', gch)
\r
68 % [gch e] = GraphCut('energy', gch)
\r
71 % - se: Smoothness energy term.
\r
72 % - de: Data energy term.
\r
76 % - 'expand': Perform labels expansion
\r
77 % [gch labels] = GraphCut('expand', gch)
\r
78 % [gch labels] = GraphCut('expand', gch, iter)
\r
79 % [gch labels] = GraphCut('expand', gch, [], label)
\r
80 % [gch labels] = GraphCut('expand', gch, [], label, indices)
\r
82 % When no inputs are provided, GraphCut performs expansion steps
\r
83 % until it converges.
\r
86 % - iter: a double scalar, the maximum number of expand
\r
87 % iterations to perform.
\r
88 % - label: scalar denoting the label for which to perfom
\r
89 % expand step (labels are [0..num_labels-1]).
\r
90 % - indices: array of linear indices of pixels for which
\r
91 % expand step is computed.
\r
94 % - labels: a width*height array of type int32, containing a
\r
95 % label per pixel. note that labels values must be is range
\r
96 % [0..num_labels-1].
\r
99 % - 'swap': Perform alpha - beta swappings
\r
100 % [gch labels] = GraphCut('swap', gch)
\r
101 % [gch labels] = GraphCut('swap', gch, iter)
\r
102 % [gch labels] = GraphCut('swap', gch, label1, label2)
\r
104 % When no inputs are provided, GraphCut performs alpha - beta swaps steps
\r
105 % until it converges.
\r
108 % - iter: a double scalar, the maximum number of swap
\r
109 % iterations to perform.
\r
110 % - label1, label2: int32 scalars denoting two labels for swap
\r
114 % - labels: a width*height array of type int32, containing a
\r
115 % label per pixel. note that labels values must be is range
\r
116 % [0..num_labels-1].
\r
119 % - 'truncate': truncating (or not) violating expansion terms
\r
120 % (see Rother etal. Digital Tapestry, CVPR2005)
\r
121 % [gch truncate_flag] = GraphCut('truncate', gch, trancate_flag);
\r
123 % When no truncate_flag is provided the function returns the current
\r
124 % state of truncation
\r
127 % - trancate_flag: set truncate_flag to this state
\r
130 % - trancate_flag: current state (after modification if
\r
133 % - 'close': Close the graph and release allocated resources.
\r
134 % [gch] = GraphCut('close', gch);
\r
138 % This wrapper for Matlab was written by Shai Bagon (shai.bagon@weizmann.ac.il).
\r
139 % Department of Computer Science and Applied Mathmatics
\r
140 % Wiezmann Institute of Science
\r
141 % http://www.wisdom.weizmann.ac.il/
\r
143 % The core cpp application was written by Olga Veksler
\r
144 % (available from http://www.csd.uwo.ca/faculty/olga/code.html):
\r
146 % [1] Efficient Approximate Energy Minimization via Graph Cuts
\r
147 % Yuri Boykov, Olga Veksler, Ramin Zabih,
\r
148 % IEEE transactions on PAMI, vol. 20, no. 12, p. 1222-1239, November
\r
151 % [2] What Energy Functions can be Minimized via Graph Cuts?
\r
152 % Vladimir Kolmogorov and Ramin Zabih.
\r
153 % IEEE Transactions on Pattern Analysis and Machine Intelligence
\r
154 % (PAMI), vol. 26, no. 2,
\r
155 % February 2004, pp. 147-159.
\r
157 % [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms
\r
158 % for Energy Minimization in Vision.
\r
159 % Yuri Boykov and Vladimir Kolmogorov.
\r
160 % In IEEE Transactions on Pattern Analysis and Machine Intelligence
\r
162 % vol. 26, no. 9, September 2004, pp. 1124-1137.
\r
164 % [4] Matlab Wrapper for Graph Cut.
\r
166 % in www.wisdom.weizmann.ac.il/~bagon, December 2006.
\r
168 % This software can be used only for research purposes, you should cite ALL of
\r
169 % the aforementioned papers in any resulting publication.
\r
170 % If you wish to use this software (or the algorithms described in the
\r
171 % aforementioned paper)
\r
172 % for commercial purposes, you should be aware that there is a US patent:
\r
174 % R. Zabih, Y. Boykov, O. Veksler,
\r
175 % "System and method for fast approximate energy minimization via
\r
177 % United Stated Patent 6,744,923, June 1, 2004
\r
180 % The Software is provided "as is", without warranty of any kind.
\r
186 % open a new graph cut
\r
188 error('GraphCut:Open: wrong number of output arguments');
\r
191 gch = OpenGraph(varargin{:});
\r
193 case {'c', 'close'}
\r
194 % close the GraphCut handle - free memory.
\r
196 error('GraphCut:Close: Too many inputs');
\r
199 [gch] = GraphCutMex(gch, 'c');
\r
202 % get current labeling
\r
205 error('GraphCut:GetLabels: wrong number of outputs');
\r
207 [gch labels] = GetLabels(varargin{:});
\r
209 varargout{1} = labels;
\r
212 % set user defined labeling
\r
214 error('GraphCut:SetLabels: Too many outputs');
\r
217 [gch] = SetLabels(varargin{:});
\r
219 case {'en', 'n', 'energy'}
\r
220 % get current energy values
\r
222 error('GraphCut:GetEnergy: too many input arguments');
\r
225 [gch se de] = GraphCutMex(gch, 'n');
\r
228 varargout{1} = se+de;
\r
234 error('GraphCut:GetEnergy: wrong number of output arguments')
\r
238 case {'e', 'ex', 'expand'}
\r
239 % use expand steps to minimize energy
\r
241 error('GraphCut:Expand: too many output arguments');
\r
243 [gch labels] = Expand(varargin{:});
\r
245 varargout{1} = labels;
\r
248 case {'sw', 'a', 'ab', 'swap'}
\r
249 % use alpha beta swapping to minimize energy
\r
251 error('GraphCut:Expand: too many output arguments');
\r
253 [gch labels] = Swap(varargin{:});
\r
255 varargout{1} = labels;
\r
260 if numel(varargin) == 2
\r
262 [gch tf] = GraphCutMex(gch, 't', varargin{2});
\r
263 elseif numel(varargin) == 1
\r
265 [gch tf] = GraphCutMex(gch, 't');
\r
267 error('GraphCut:Truncate: wrong number of input arguments');
\r
270 error('GraphCut:Truncate: too many output arguments');
\r
277 error('GraphCut: Unrecognized mode %s', mode);
\r
280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\r
284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\r
285 function gch = OpenGraph(varargin)
\r
286 % Usage [gch] = OpenGraph(Dc, Sc, [vC, hC]) - 2D grid
\r
287 % or [gch] = OpenGraph(Dc, Sc, [Contrast]) -3D grid
\r
288 % or [gch] = GraphCut(DataCost, SmoothnessCost, SparseSmoothness) - any graph
\r
289 nin = numel(varargin);
\r
290 if (nin~=2) && (nin ~= 3) && (nin~=4)
\r
291 error('GraphCut:Open: wrong number of inputs');
\r
298 [R C Z L] = size(Dc);
\r
299 if ~strcmp(class(Dc),'single')
\r
302 Dc = permute(Dc,[4 1 2 3]);
\r
307 if any( size(Sc) ~= [L L] )
\r
308 error('GraphCut:Open: smoothness cost has incorrect size');
\r
310 if ~strcmp(class(Sc),'single')
\r
315 Contrast = varargin{3};
\r
316 if any( size(Contrast) ~= [R C Z] )
\r
317 error('GraphCut:Open: Contrast term is of wrong size');
\r
319 if ~strcmp(class(Contrast),'single')
\r
320 Contrast = single(Contrast);
\r
322 Contrast = Contrast(:);
\r
324 gch = GraphCut3dConstr(R, C, Z, L, Dc, Sc, Contrast);
\r
326 gch = GraphCut3dConstr(R, C, Z, L, Dc, Sc);
\r
328 error('GraphCut:Open: wrong number of inputs for 3D graph');
\r
330 elseif ndims(Dc) == 3
\r
332 [h w l] = size(Dc);
\r
333 if ~strcmp(class(Dc),'single')
\r
336 Dc = permute(Dc,[3 2 1]);
\r
341 if any( size(Sc) ~= [l l] )
\r
342 error('GraphCut:Open: smoothness cost has incorrect size');
\r
344 if ~strcmp(class(Sc),'single')
\r
351 if any( size(vC) ~= [h w] )
\r
352 error('GraphCut:Open: vertical cue size incorrect');
\r
354 if ~strcmp(class(vC),'single')
\r
360 if any( size(hC) ~= [h w] )
\r
361 error('GraphCut:Open: horizontal cue size incorrect');
\r
363 if ~strcmp(class(hC),'single')
\r
367 gch = GraphCutConstr(w, h, l, Dc, Sc, vC(:), hC(:));
\r
369 gch = GraphCutConstr(w, h, l, Dc, Sc);
\r
371 error('GraphCut:Open: wrong number of input for 2D grid');
\r
373 elseif ndims(Dc) == 2
\r
374 %%% arbitrary graph
\r
376 error('GraphCut:Open', 'incorect number of inputs');
\r
379 [nl np] = size(Dc);
\r
381 if any(size(Sc) ~= [nl nl])
\r
382 error('GraphCut:Open', 'Wrong size of Dc or Sc');
\r
385 SparseSc = varargin{3};
\r
386 if any(size(SparseSc) ~= [np np])
\r
387 error('GraphCut:Open', 'Wrong size of SparseSc');
\r
390 gch = GraphCutConstrSparse(single(Dc(:)), single(Sc(:)), SparseSc);
\r
393 %%% Unknown dimensionality...
\r
394 error('GraphCut:Open: data cost has incorect dimensionality');
\r
397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\r
398 function [gch] = SetLabels(varargin)
\r
399 % usgae [gch] = SetLabels(gch, labels)
\r
402 error('GraphCut:SetLabels: wrong number of inputs');
\r
405 labels = varargin{2};
\r
407 if ~strcmp(class(labels), 'int32')
\r
408 labels = int32(labels);
\r
411 [gch] = GraphCutMex(gch, 's', labels(:));
\r
413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\r
414 function [gch labels] = GetLabels(varargin)
\r
417 error('GraphCut:GetLabels: wrong number of inputs');
\r
420 [gch labels] = GraphCutMex(gch, 'g');
\r
423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\r
424 function [gch labels] = Expand(varargin)
\r
428 [gch labels] = GraphCutMex(gch, 'e');
\r
430 [gch labels] = GraphCutMex(gch, 'e', varargin{2});
\r
432 [gch labels] = GraphCutMex(gch, 'e', varargin{2}, varargin{3});
\r
435 ind = int32(ind(:)-1)'; % convert to int32
\r
436 [gch labels] = GraphCutMex(gch, 'e', varargin{2}, varargin{3}, ind);
\r
438 error('GraphCut:Expand: wrong number of inputs');
\r
442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\r
443 function [gch labels] = Swap(varargin)
\r
447 [gch labels] = GraphCutMex(gch, 'a');
\r
449 [gch labels] = GraphCutMex(gch, 'a', varargin{2});
\r
451 [gch labels] = GraphCutMex(gch, 'a', varargin{2}, varargin{3});
\r
453 error('GraphCut:Swap: wrong number of inputarguments');
\r
457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\r