3 #include "GCoptimization.h"
\r
4 #include "GraphCut.h"
\r
8 void SetLabels(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
\r
9 void GetLabels(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
\r
10 void ABswaps(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
\r
11 void Expand(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
\r
12 void Energy(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
\r
13 void Truncate(GCoptimization *MyGraph, int nout, mxArray *pout[], int nin, const mxArray *pin[]);
\r
14 GCoptimization* GetGCHandle(const mxArray *x); /* extract ahndle from mxArry */
\r
18 * Matlab wrapper for Weksler graph cut implementation
\r
20 * GCoptimization cde by Olga Veksler.
\r
21 * Wrapper code by Shai Bagon.
\r
24 * Performing Graph Cut operations on a 2D grid.
\r
27 * [gch ...] = GraphCutMex(gch, mode ...);
\r
30 * 1. Data types are crucial!
\r
31 * 2. The embedded implementation treat matrices as a row stack, while
\r
32 * matlab treats them as column stack; thus there is a need to
\r
33 * transpose the label matrices and the indices passed to expand
\r
37 * - gch: a valid Graph Cut handle (use GraphCutConstr to create a handle).
\r
38 * - mode: a char specifying mode of operation. See details below.
\r
41 * - gch: A handle to the constructed graph. Handle this handle with care
\r
42 * and don't forget to close it in the end!
\r
47 * [gch] = GraphCutMex(gch, 's', labels)
\r
50 * - labels: a width*height array of type int32, containing a
\r
51 * label per pixel. note that labels values must be is range
\r
52 * [0..num_labels-1].
\r
54 * - 'g': Get current labeling
\r
55 * [gch labels] = GraphCutMex(gch, 'g')
\r
58 * - labels: a width*height array of type int32, containing a
\r
59 * label per pixel. note that labels values must be is range
\r
60 * [0..num_labels-1].
\r
62 * - 'n': Get current values of energy terms
\r
63 * [gch se de] = GraphCutMex(gch, 'n')
\r
66 * - se: Smoothness energy term.
\r
67 * - de: Data energy term.
\r
69 * - 'e': Perform labels expansion
\r
70 * [gch labels] = GraphCutMex(gch, 'e')
\r
71 * [gch labels] = GraphCutMex(gch, 'e', iter)
\r
72 * [gch labels] = GraphCutMex(gch, 'e', [], label)
\r
73 * [gch labels] = GraphCutMex(gch, 'e', [], label, indices)
\r
75 * When no inputs are provided, GraphCut performs expansion steps
\r
76 * until it converges.
\r
79 * - iter: a double scalar, the maximum number of expand
\r
80 * iterations to perform.
\r
81 * - label: int32 scalar denoting the label for which to perfom
\r
83 * - indices: int32 array of linear indices of pixels for which
\r
84 * expand step is computed. indices _MUST_ be zero offset and not
\r
85 * one offset like matlab usuall indexing system, i.e., to include
\r
86 * the first pixel in the expand indices array must contain 0 and
\r
90 * - labels: a width*height array of type int32, containing a
\r
91 * label per pixel. note that labels values must be is range
\r
92 * [0..num_labels-1].
\r
94 * - 'a': Perform alpha - beta swappings
\r
95 * [gch labels] = GraphCutMex(gch, 'a')
\r
96 * [gch labels] = GraphCutMex(gch, 'a', iter)
\r
97 * [gch labels] = GraphCutMex(gch, 'a', label1, label2)
\r
99 * When no inputs are provided, GraphCut performs alpha - beta swaps steps
\r
100 * until it converges.
\r
103 * - iter: a double scalar, the maximum number of swap
\r
104 * iterations to perform.
\r
105 * - label1, label2: int32 scalars denoting two labels for swap
\r
109 * - labels: a width*height array of type int32, containing a
\r
110 * label per pixel. note that labels values must be is range
\r
111 * [0..num_labels-1].
\r
113 * - 'c': Close the graph and release allocated resources.
\r
114 * [gch] = GraphCutMex(gch,'c');
\r
120 * This wrapper for Matlab was written by Shai Bagon (shai.bagon@weizmann.ac.il).
\r
121 * Department of Computer Science and Applied Mathmatics
\r
122 * Wiezmann Institute of Science
\r
123 * http://www.wisdom.weizmann.ac.il/
\r
125 * The core cpp application was written by Veksler Olga:
\r
127 * [1] Efficient Approximate Energy Minimization via Graph Cuts
\r
128 * Yuri Boykov, Olga Veksler, Ramin Zabih,
\r
129 * IEEE transactions on PAMI, vol. 20, no. 12, p. 1222-1239, November 2001.
\r
131 * [2] What Energy Functions can be Minimized via Graph Cuts?
\r
132 * Vladimir Kolmogorov and Ramin Zabih.
\r
133 * To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI).
\r
134 * Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002.
\r
136 * [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms
\r
137 * for Energy Minimization in Vision.
\r
138 * Yuri Boykov and Vladimir Kolmogorov.
\r
139 * In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI),
\r
142 * [4] Matlab Wrapper for Graph Cut.
\r
144 * in www.wisdom.weizmann.ac.il/~bagon, December 2006.
\r
146 * This software can be used only for research purposes, you should cite
\r
147 * the aforementioned papers in any resulting publication.
\r
148 * If you wish to use this software (or the algorithms described in the aforementioned paper)
\r
149 * for commercial purposes, you should be aware that there is a US patent:
\r
151 * R. Zabih, Y. Boykov, O. Veksler,
\r
152 * "System and method for fast approximate energy minimization via graph cuts ",
\r
153 * United Stated Patent 6,744,923, June 1, 2004
\r
156 * The Software is provided "as is", without warranty of any kind.
\r
161 int nlhs, /* number of expected outputs */
\r
162 mxArray *plhs[], /* mxArray output pointer array */
\r
163 int nrhs, /* number of inputs */
\r
164 const mxArray *prhs[] /* mxArray input pointer array */
\r
167 /* building graph is only call without gch */
\r
168 GCoptimization *MyGraph = NULL;
\r
171 mexErrMsgIdAndTxt("GraphCut","Too few input arguments");
\r
174 /* get graph handle */
\r
175 MyGraph = GetGCHandle(prhs[0]);
\r
178 GetScalar(prhs[1], mode);
\r
182 case 'c': /* close */
\r
183 delete MyGraph; /* ->~GCoptimization(); /* explicitly call the destructor */
\r
186 case 's': /* set labels */
\r
187 /* setting the labels: we have an extra parameter - int32 array of size w*l
\r
188 * containing the new labels */
\r
189 SetLabels(MyGraph, nlhs, plhs, nrhs, prhs);
\r
191 case 'g': /* get labels */
\r
192 GetLabels(MyGraph, nlhs, plhs, nrhs, prhs);
\r
194 case 'a': /* a-b swaps */
\r
195 ABswaps(MyGraph, nlhs, plhs, nrhs, prhs);
\r
197 case 'e': /* expand steps */
\r
198 Expand(MyGraph, nlhs, plhs, nrhs, prhs);
\r
200 case 'n': /* get the current labeling energy */
\r
201 Energy(MyGraph, nlhs, plhs, nrhs, prhs);
\r
203 case 't': /* truncation */
\r
204 Truncate(MyGraph, nlhs, plhs, nrhs, prhs);
\r
207 mexErrMsgIdAndTxt("GraphCut:mode","unrecognized mode");
\r
209 /* update the gch output handle */
\r
211 plhs[0] = mxCreateNumericMatrix(1, 1, MATLAB_POINTER_TYPE, mxREAL);
\r
212 pgh = (GraphHandle*) mxGetData(plhs[0]);
\r
213 *pgh = (GraphHandle)(MyGraph);
\r
215 /**************************************************************************************/
\r
216 /* set user defined labels to graph */
\r
217 void SetLabels(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
\r
219 /* we need exactly 3 input arguments: gch, mode, labels */
\r
221 mexErrMsgIdAndTxt("GraphCut:SetLabels","Wrong number of input arguments");
\r
222 if ( mxGetClassID(prhs[2]) != mxINT32_CLASS )
\r
223 mexErrMsgIdAndTxt("GraphCut:SetLabels","labels array not int32");
\r
224 if ( mxGetNumberOfElements(prhs[2]) != MyGraph->GetNumPixels() )
\r
225 mexErrMsgIdAndTxt("GraphCut:SetLabels","wrong number of elements in labels array");
\r
227 /* verify only one output parameter */
\r
229 mexErrMsgIdAndTxt("GraphCut:SetLabels","wrong number of output parameters");
\r
231 MyGraph->SetAllLabels( (GCoptimization::LabelType*) mxGetData(prhs[2]) );
\r
233 /**************************************************************************************/
\r
234 /* set user defined labels to graph */
\r
235 void GetLabels(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
\r
237 /* exactly two input arguments */
\r
239 mexErrMsgIdAndTxt("GraphCut:GetLabels","Wrong number of input arguments");
\r
241 /* we need exactly 2 output arguments: gch, labels */
\r
243 mexErrMsgIdAndTxt("GraphCut:GetLabels","Wrong number of output arguments");
\r
245 /* transposed result */
\r
246 plhs[1] = mxCreateNumericMatrix(MyGraph->GetWidth(), MyGraph->GetNumPixels() / MyGraph->GetWidth(), mxINT32_CLASS, mxREAL);
\r
247 MyGraph->ExportLabels( (GCoptimization::LabelType*) mxGetData(plhs[1]) );
\r
249 /**************************************************************************************/
\r
250 /* support several kinds of a/b swaps:
\r
251 * 1. defualt - swap till convergence (no extra parameters)
\r
252 * 2. #iterations - performs #iterations: GraphCut(gch, mode, #iteration)
\r
253 * 3. swap two labels - GraphCut(gch, mode, l1, l2)
\r
255 void ABswaps(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
\r
257 int max_iterations(0), li(0);
\r
258 GCoptimization::LabelType label[2] = { 0, 1};
\r
259 GCoptimization::PixelType *indices = NULL;
\r
264 /* default - expand till convergence */
\r
268 /* number of iterations */
\r
269 GetScalar(prhs[2], max_iterations);
\r
270 if ( max_iterations == 1 )
\r
271 MyGraph->oneSwapIteration();
\r
273 MyGraph->swap(max_iterations);
\r
276 for ( li = 2; li<4;li++) {
\r
277 GetScalar(prhs[li], label[li-2]);
\r
278 if ( label[li-2] < 0 || label[li-2] >= MyGraph->GetNumLabels() )
\r
279 mexErrMsgIdAndTxt("GraphCut:swap","invalid label value");
\r
281 MyGraph->alpha_beta_swap(label[0], label[1]);
\r
284 mexErrMsgIdAndTxt("GraphCut:swap","Too many input arguments");
\r
287 /* output: at least one (gch) can output the labels as well */
\r
289 mexErrMsgIdAndTxt("GraphCut:swap","too many output arguments");
\r
291 /* output labels */
\r
293 /* set the lables */
\r
295 /* transposed result */
\r
296 plhs[1] = mxCreateNumericMatrix(MyGraph->GetWidth(), MyGraph->GetNumPixels() / MyGraph->GetWidth(), mxINT32_CLASS, mxREAL);
\r
297 MyGraph->ExportLabels( (GCoptimization::LabelType*) mxGetData(plhs[1]) );
\r
302 /**************************************************************************************/
\r
303 /* support several kinds of expansion
\r
304 * 1. default - expand untill convergence no extra parameters
\r
305 * 2. #iterations - performs #iterations: GraphCut(gch, mode, #iteration)
\r
306 * 3. expand label - expand specific label GraphCut(gch, mode, [], label)
\r
307 * 4. expand label at specific indices GraphCut(gch, mode, [], label, indices) indices start with zero and not 1 like usuall matlab inices!!
\r
309 void Expand(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
\r
311 int num(0), max_iterations(0);
\r
312 GCoptimization::LabelType label(0);
\r
313 GCoptimization::PixelType *indices = NULL;
\r
318 /* default - expand till convergence */
\r
319 MyGraph->expansion();
\r
322 /* number of iterations */
\r
323 GetScalar(prhs[2], max_iterations);
\r
324 if ( max_iterations == 1 )
\r
325 MyGraph->oneExpansionIteration();
\r
327 MyGraph->expansion(max_iterations);
\r
331 if (mxGetClassID(prhs[4]) != mxINT32_CLASS)
\r
332 mexErrMsgIdAndTxt("GraphCut:Expand","indices must be int32");
\r
333 num = mxGetNumberOfElements(prhs[4]);
\r
334 if (num < 0 || num > MyGraph->GetNumPixels())
\r
335 mexErrMsgIdAndTxt("GraphCut:Expand","too many indices");
\r
336 indices = (GCoptimization::PixelType*)mxGetData(prhs[4]);
\r
338 /* expand specific label */
\r
339 if (mxGetNumberOfElements(prhs[2]) != 0)
\r
340 mexErrMsgIdAndTxt("GraphCut:Expand","third argument must empty");
\r
341 GetScalar(prhs[3], label);
\r
343 if ( indices != NULL ) {
\r
344 /* expand specific label at specific indices */
\r
345 MyGraph->alpha_expansion(label, indices, num);
\r
347 MyGraph->alpha_expansion(label);
\r
351 mexErrMsgIdAndTxt("GraphCut:Expand","Too many input arguments");
\r
354 /* output: at least one (gch) can output the labels as well */
\r
356 mexErrMsgIdAndTxt("GraphCut:Expand","too many output arguments");
\r
358 /* output labels */
\r
360 /* set the lables */
\r
362 /* transposed result */
\r
363 plhs[1] = mxCreateNumericMatrix(MyGraph->GetWidth(), MyGraph->GetNumPixels() / MyGraph->GetWidth(), mxINT32_CLASS, mxREAL);
\r
364 MyGraph->ExportLabels( (GCoptimization::LabelType*) mxGetData(plhs[1]) );
\r
369 /**************************************************************************************/
\r
370 /* extract energy of labeling
\r
371 * [gch se de] = GraphCut(gch, 'n');
\r
373 void Energy(GCoptimization *MyGraph, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
\r
376 mexErrMsgIdAndTxt("GraphCut:Energy","Too many input arguments");
\r
378 mexErrMsgIdAndTxt("GraphCut:Energy","wrong number of output arguments");
\r
380 GCoptimization::EnergyType *e;
\r
382 plhs[1] = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);
\r
383 e = (GCoptimization::EnergyType *)mxGetData(plhs[1]);
\r
384 *e = MyGraph->giveSmoothEnergy();
\r
386 plhs[2] = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);
\r
387 e = (GCoptimization::EnergyType *)mxGetData(plhs[2]);
\r
388 *e = MyGraph->giveDataEnergy();
\r
390 /**************************************************************************************/
\r
391 /* get/set truncation flag
\r
392 * [gch tf] = GraphCut(gch, 'truncate', [ntf])
\r
394 void Truncate(GCoptimization *MyGraph, int nout, mxArray *pout[], int nin, const mxArray *pin[])
\r
399 tf = MyGraph->GetTruncateState();
\r
401 } else if ( nin == 3 ) {
\r
403 if ( mxIsComplex(pin[2]) || mxIsSparse(pin[2]) || mxGetNumberOfElements(pin[2])!=1 )
\r
404 mexErrMsgIdAndTxt("GraphCut:Truncate","wrong truncate_flag");
\r
406 tf = (mxGetScalar(pin[2]) != 0);
\r
408 mexPrintf("Set truncate %d\n",tf);
\r
410 MyGraph->SetTruncateState(tf);
\r
412 mexErrMsgIdAndTxt("GraphCut:Truncate","wrong number of input arguments");
\r
415 mexErrMsgIdAndTxt("GraphCut:Truncate","wrong number of output arguments");
\r
417 pout[1] = mxCreateDoubleScalar( static_cast<double>(tf) );
\r
420 /**************************************************************************************/
\r
421 GCoptimization* GetGCHandle(const mxArray *x)
\r
423 GraphHandle gch = 0;
\r
424 GCoptimization* MyGraph = 0;
\r
426 if ( mxGetNumberOfElements(x) != 1 ) {
\r
427 mexErrMsgIdAndTxt("GraphCut:handle",
\r
428 "Too many GC handles");
\r
430 if ( mxGetClassID(x) != MATLAB_POINTER_TYPE ) {
\r
431 mexErrMsgIdAndTxt("GraphCut:handle",
\r
432 "GC handle argument is not of proper type");
\r
434 gch = (GraphHandle*)mxGetData(x);
\r
435 MyGraph = (GCoptimization*)(*(POINTER_CAST*)gch);
\r
436 if ( MyGraph==NULL || ! MyGraph->IsClassValid() ) {
\r
437 mexErrMsgIdAndTxt("GraphCut:handle",
\r
438 "GC handle is not valid");
\r
444 /**************************************************************************************/
\r