OpenGM  2.3.x
Discrete Graphical Model Library
graphcut.hxx
Go to the documentation of this file.
1 #pragma once
2 #ifndef OPENGM_GRAPHCUT_HXX
3 #define OPENGM_GRAPHCUT_HXX
4 
5 #include <typeinfo>
6 
11 
12 namespace opengm {
13 
17 template<class GM, class ACC, class MINSTCUT>
18 class GraphCut : public Inference<GM, ACC> {
19 public:
20 
21  template<class _GM>
22  struct RebindGm{
24  };
25 
26  template<class _GM,class _ACC>
29  };
30 
31  typedef ACC AccumulationType;
32  typedef GM GraphicalModelType;
34  typedef MINSTCUT MinStCutType;
38  struct Parameter {
39  Parameter(const ValueType scale = 1)
40  : scale_(scale) {
41  }
42 
43  template<class P>
44  Parameter(const P & p)
45  : scale_(p.scale_){
46  }
47 
49  };
50 
51  GraphCut(const GraphicalModelType&, const Parameter& = Parameter(), ValueType = static_cast<ValueType>(0.0));
52  GraphCut(size_t numVar, std::vector<size_t> numFacDim, const Parameter& = Parameter(), ValueType = static_cast<ValueType>(0.0));
53  ~GraphCut();
54 
55  std::string name() const;
56  const GraphicalModelType& graphicalModel() const;
57  template<class FACTOR>
58  void addFactor(const FACTOR& factor);
60  template<class VISITOR>
61  InferenceTermination infer(VISITOR & visitor);
62  InferenceTermination arg(std::vector<LabelType>&, const size_t = 1) const;
63 
64 private:
65  void addEdgeCapacity(const size_t, const size_t, const ValueType);
66  size_t tripleId(std::vector<size_t>&);
67 
68  const GraphicalModelType* gm_;
69  ValueType tolerance_;
70  MinStCutType* minStCut_;
71  Parameter parameter_;
72  size_t numVariables_;
73  std::vector<size_t> numFacDim_;
74  std::list<std::vector<size_t> > tripleList;
75  std::vector<bool> state_;
76  std::vector<typename MINSTCUT::ValueType> sEdges_;
77  std::vector<typename MINSTCUT::ValueType> tEdges_;
78  bool inferenceDone_;
79 };
80 
81 template<class GM, class ACC, class MINSTCUT>
82 inline std::string
84  return "GraphCut";
85 }
86 
87 template<class GM, class ACC, class MINSTCUT>
90  return *gm_;
91 }
92 
93 template<class GM, class ACC, class MINSTCUT>
95 (
96  const size_t numVariables,
97  std::vector<size_t> numFacDim,
98  const Parameter& para,
99  const ValueType tolerance
100 )
101  : gm_((GM*) 0),
102  tolerance_(fabs(tolerance))
103 {
104  OPENGM_ASSERT(typeid(ACC) == typeid(opengm::Minimizer) || typeid(ACC) == typeid(opengm::Maximizer));
105  OPENGM_ASSERT(typeid(typename GM::OperatorType) == typeid(opengm::Adder));
106  OPENGM_ASSERT(numFacDim_.size() <= 3+1);
107  parameter_ = para;
108  numVariables_ = numVariables;
109  numFacDim_ = numFacDim;
110  numFacDim_.resize(4);
111  minStCut_ = new MinStCutType(2 + numVariables_ + numFacDim_[3], 2*numVariables_ + numFacDim_[2] + 3*numFacDim_[3]);
112  sEdges_.assign(numVariables_ + numFacDim_[3], 0);
113  tEdges_.assign(numVariables_ + numFacDim_[3], 0);
114  inferenceDone_=false;
115  //std::cout << parameter_.scale_ <<std::endl;
116 }
117 
118 template<class GM, class ACC, class MINSTCUT>
120 (
121  const GraphicalModelType& gm,
122  const Parameter& para,
123  const ValueType tolerance
124 )
125 : gm_(&gm),
126  tolerance_(fabs(tolerance))
127 {
128  if(typeid(ACC) != typeid(opengm::Minimizer) && typeid(ACC) != typeid(opengm::Maximizer)) {
129  throw RuntimeError("This implementation of the graph cut optimizer supports as accumulator only opengm::Minimizer and opengm::Maximizer.");
130  }
131  for(size_t j = 0; j < gm.numberOfVariables(); ++j) {
132  if(gm.numberOfLabels(j) != 2) {
133  throw RuntimeError("This implementation of the graph cut optimizer supports only binary variables.");
134  }
135  }
136  for(size_t j = 0; j < gm.numberOfFactors(); ++j) {
137  if(gm[j].numberOfVariables() > 3) {
138  throw RuntimeError("This implementation of the graph cut optimizer supports only factors of order <= 3.");
139  }
140  }
141 
142  parameter_ = para;
143  numVariables_ = gm.numberOfVariables();
144  numFacDim_.resize(4, 0);
145  for(size_t j = 0; j < gm.numberOfFactors(); ++j) {
146  ++numFacDim_[gm[j].numberOfVariables()];
147  }
148 
149  minStCut_ = new MinStCutType(2 + numVariables_ + numFacDim_[3], 2*numVariables_ + numFacDim_[2] + 3*numFacDim_[3]);
150  sEdges_.assign(numVariables_ + numFacDim_[3], 0);
151  tEdges_.assign(numVariables_ + numFacDim_[3], 0);
152 
153  for(size_t j = 0; j < gm.numberOfFactors(); ++j) {
154  addFactor(gm[j]);
155  }
156  inferenceDone_=false;
157  //std::cout << parameter_.scale_ <<std::endl;
158 }
159 
160 template<class GM, class ACC, class MINSTCUT>
162 {
163  delete minStCut_;
164 }
165 
167 template<class GM, class ACC, class MINSTCUT>
168 template<class FACTOR>
170 (
171  const FACTOR& factor
172 ) {
173  size_t numberOfVariables = factor.numberOfVariables();
174  for(size_t i=0; i<numberOfVariables; ++i) {
175  OPENGM_ASSERT(factor.numberOfLabels(i) == 2);
176  }
177 
178  if(numberOfVariables == 0) {
179  // do nothing
180  }
181  else if(numberOfVariables == 1) {
182  const size_t var = factor.variableIndex(0);
183  OPENGM_ASSERT(var < numVariables_);
184  size_t i;
185  i = 0; const ValueType v0 = factor(&i);
186  i = 1; const ValueType v1 = factor(&i);
187  if(typeid(ACC) == typeid(opengm::Minimizer)) {
188  if(v0 <= v1) {
189  addEdgeCapacity(0, var + 2, v1 - v0);
190  }
191  else {
192  addEdgeCapacity(var + 2, 1, v0 - v1);
193  }
194  }
195  else { //opengm::Maximizer
196  if(v0 >= v1) {
197  addEdgeCapacity(0, var + 2, -v1 + v0);
198  }
199  else {
200  addEdgeCapacity(var + 2, 1, -v0 + v1);
201  }
202  }
203  }
204  else if(numberOfVariables == 2) {
205  const size_t var0 = factor.variableIndex(0);
206  const size_t var1 = factor.variableIndex(1);
207  OPENGM_ASSERT(var0 < numVariables_);
208  OPENGM_ASSERT(var1 < numVariables_);
209  size_t i[] = {0, 0}; const ValueType A = factor(i);
210  i[0] = 0; i[1] = 1; const ValueType B = factor(i);
211  i[0] = 1; i[1] = 0; const ValueType C = factor(i);
212  i[0] = 1; i[1] = 1; const ValueType D = factor(i);
213  if(typeid(ACC) == typeid(opengm::Minimizer)) {
214  // first variabe
215  if(C > A)
216  addEdgeCapacity(0, var0 + 2, C - A);
217  else if(C < A)
218  addEdgeCapacity(var0 + 2, 1, A - C);
219  // second variable
220  if(D > C)
221  addEdgeCapacity(0, var1 + 2, D - C);
222  else if(D < C)
223  addEdgeCapacity(var1 + 2, 1, C - D);
224  // submodular term
225  ValueType term = B + C - A - D;
226  if((term < 0) && (term >= -tolerance_))
227  term = 0.0;
228  //if(term < 0.0) {
229  // throw RuntimeError("GraphCut<Factor>::addPairwisefactor(): non sub-modular factors cannot be processed.");
230  //}
231  addEdgeCapacity(var0 + 2, var1 + 2, term);
232  }
233  else{
234  if(C < A)
235  addEdgeCapacity(0, var0 + 2, -C + A);
236  else if(C > A)
237  addEdgeCapacity(var0 + 2, 1, -A + C);
238  // second variable
239  if(D < C)
240  addEdgeCapacity(0, var1 + 2, -D + C);
241  else if(D > C)
242  addEdgeCapacity(var1 + 2, 1, -C + D);
243  // submodular term
244  ValueType term = B + C - A - D;
245  if((term > 0) && (term <= tolerance_))
246  term = 0.0;
247  addEdgeCapacity(var0 + 2, var1 + 2, -term);
248  //if(term > 0.0) {
249  // throw RuntimeError("GraphCut<Factor>::addPairwisefactor(): non sub-modular factors cannot be processed.");
250  //}
251  }
252  }
253  else if(numberOfVariables == 3) {
254  const size_t var0 = factor.variableIndex(0);
255  const size_t var1 = factor.variableIndex(1);
256  const size_t var2 = factor.variableIndex(1);
257  OPENGM_ASSERT(var0 < numVariables_);
258  OPENGM_ASSERT(var1 < numVariables_);
259  OPENGM_ASSERT(var2 < numVariables_);
260  size_t i[] = {0, 0, 0}; const ValueType A = factor(i);
261  i[0] = 0; i[1] = 0; i[2] = 1; const ValueType B = factor(i);
262  i[0] = 0; i[1] = 1; i[2] = 0; const ValueType C = factor(i);
263  i[0] = 0; i[1] = 1; i[2] = 1; const ValueType D = factor(i);
264  i[0] = 1; i[1] = 0; i[2] = 0; const ValueType E = factor(i);
265  i[0] = 1; i[1] = 0; i[2] = 1; const ValueType F = factor(i);
266  i[0] = 1; i[1] = 1; i[2] = 0; const ValueType G = factor(i);
267  i[0] = 1; i[1] = 1; i[2] = 1; const ValueType H = factor(i);
268 
269  if(typeid(ACC) == typeid(opengm::Minimizer)) {
270  std::vector<size_t> triple(3);
271  triple[0] = var0;
272  triple[1] = var1;
273  triple[2] = var2;
274  size_t id = tripleId(triple);
275  ValueType P = (A + D + F + G)-(B + C + E + H);
276  if(P >= 0.0) {
277  if(F-B>=0) addEdgeCapacity(0, var0+2, F - B);
278  else addEdgeCapacity(var0+2, 1, B - F);
279  if(G-E>=0) addEdgeCapacity(0, var1+2, G - E);
280  else addEdgeCapacity(var1+2, 1, E - G);
281  if(D-C>=0) addEdgeCapacity(0, var2+2, D - C);
282  else addEdgeCapacity(var2+2, 0, C - D);
283 
284  addEdgeCapacity(var1+2, var2+2, B + C - A - D);
285  addEdgeCapacity(var2+2, var0+2, B + E - A - F);
286  addEdgeCapacity(var0+2, var1+2, C + E - A - G);
287 
288  addEdgeCapacity(var0 + 2, id + 2, P);
289  addEdgeCapacity(var1 + 2, id + 2, P);
290  addEdgeCapacity(var2 + 2, id + 2, P);
291  addEdgeCapacity(id, 1, P);
292  }
293  else {
294  if(C-G>=0) addEdgeCapacity(var0+2, 1, C - G);
295  else addEdgeCapacity(0, var0+2, G - C);
296  if(B-D>=0) addEdgeCapacity(var1+2, 1, B - D);
297  else addEdgeCapacity(0, var1+2, D - B);
298  if(E-F>=0) addEdgeCapacity(var2+2, 1, E - F);
299  else addEdgeCapacity(0, var2+2, F - E);
300 
301  addEdgeCapacity(var2+2, var1+2, F + G - E - H);
302  addEdgeCapacity(var0+2, var2+2, D + G - C - H);
303  addEdgeCapacity(var1+2, var0+2, D + F - B - H);
304 
305  addEdgeCapacity(id + 2, var0 + 2, -P);
306  addEdgeCapacity(id + 2, var1 + 2, -P);
307  addEdgeCapacity(id + 2, var2 + 2, -P);
308  addEdgeCapacity(0, id + 2, -P);
309  };
310  }
311  else{
312  throw RuntimeError("This implementation of the graph cut optimizer support 3rd order factors only in connection with opengm::Maximizer.");
313  }
314  }
315  else {
316  throw RuntimeError("This implementation of the graph cut optimizer does not support factors of order > 3.");
317  }
318 }
319 
320 template<class GM, class ACC, class MINSTCUT>
321 inline void
323 (
324  const size_t v,
325  const size_t w,
326  const ValueType val
327 ) {
328  typedef typename MINSTCUT::ValueType VType;
329  typedef typename MINSTCUT::node_type NType;
330  const NType n1 = static_cast<NType>(v);
331  const NType n2 = static_cast<NType>(w);
332  const VType cost = static_cast<VType>(parameter_.scale_*val);
333  if(n1 == 0) {
334  sEdges_[n2-2] += cost;
335  }
336  else if(n2 == 1) {
337  tEdges_[n1-2] += cost;
338  }
339  else {
340  minStCut_->addEdge(n1, n2, cost);
341  }
342 }
343 
344 template<class GM, class ACC, class MINSTCUT>
345 inline size_t
347 (
348  std::vector<size_t>& triple
349 ) {
350  // search for triple in list
351  std::list<std::vector<size_t> >::iterator it;
352  size_t counter = numVariables_;
353  for(it = tripleList.begin(); it != tripleList.end(); it++) {
354  if(triple[0] == (*it)[0] && triple[1] == (*it)[1] && triple[2] == (*it)[2]) {
355  return counter;
356  }
357  numVariables_++;
358  }
359  // add triple to list
360  tripleList.push_back(triple);
361  OPENGM_ASSERT(counter - numVariables_ < numFacDim_[3]);
362  return counter;
363 }
364 
365 template<class GM, class ACC, class MINSTCUT>
366 inline InferenceTermination
368  EmptyVisitorType v;
369  return infer(v);
370 }
371 
372 template<class GM, class ACC, class MINSTCUT>
373 template<class VISITOR>
374 inline InferenceTermination
376  visitor.begin(*this);
377  for(size_t i=0; i<sEdges_.size(); ++i) {
378  minStCut_->addEdge(0, i+2, sEdges_[i]);
379  minStCut_->addEdge(i+2, 1, tEdges_[i]);
380  }
381  minStCut_->calculateCut(state_);
382  inferenceDone_=true;
383  visitor.end(*this);
384  return NORMAL;
385 }
386 
387 template<class GM, class ACC, class MINSTCUT>
389 (
390  std::vector<LabelType>& arg,
391  const size_t n
392 ) const {
393  if(inferenceDone_==false){
394  arg.resize(numVariables_,0);
395  return UNKNOWN;
396  }
397  if(n > 1) {
398  return UNKNOWN;
399  }
400  else {
401  // skip source and sink
402  if(state_.size() > 2 + numFacDim_[3]) {
403  arg.resize(state_.size() - 2 - numFacDim_[3]);
404  }
405  else {
406  arg.resize(0);
407  }
408 
409  for(size_t j = 0; j < arg.size(); ++j) {
410  arg[j] = static_cast<LabelType>(state_[j + 2]);
411  }
412  return NORMAL;
413  }
414 }
415 
416 } // namespace opengm
417 
418 #endif // #ifndef OPENGM_GRAPHCUT_HXX
419 
const GraphicalModelType & graphicalModel() const
Definition: graphcut.hxx:89
GraphCut< _GM, ACC, MINSTCUT > type
Definition: graphcut.hxx:23
The OpenGM namespace.
Definition: config.hxx:43
GraphCut(const GraphicalModelType &, const Parameter &=Parameter(), ValueType=static_cast< ValueType >(0.0))
Definition: graphcut.hxx:120
Addition as a binary operation.
Definition: adder.hxx:10
InferenceTermination infer()
Definition: graphcut.hxx:367
std::string name() const
Definition: graphcut.hxx:83
visitors::EmptyVisitor< GraphCut< GM, ACC, MINSTCUT > > EmptyVisitorType
Definition: graphcut.hxx:36
#define OPENGM_ASSERT(expression)
Definition: opengm.hxx:77
visitors::TimingVisitor< GraphCut< GM, ACC, MINSTCUT > > TimingVisitorType
Definition: graphcut.hxx:37
MINSTCUT MinStCutType
Definition: graphcut.hxx:34
visitors::VerboseVisitor< GraphCut< GM, ACC, MINSTCUT > > VerboseVisitorType
Definition: graphcut.hxx:35
GraphicalModelType::ValueType ValueType
Definition: inference.hxx:50
Inference algorithm interface.
Definition: inference.hxx:43
InferenceTermination arg(std::vector< LabelType > &, const size_t=1) const
output a solution
Definition: graphcut.hxx:389
void addFactor(const FACTOR &factor)
add a factor of the GraphicalModel to the min st-cut formulation of the solver MinStCutType ...
Definition: graphcut.hxx:170
GraphCut< _GM, _ACC, MINSTCUT > type
Definition: graphcut.hxx:28
GraphicalModelType::LabelType LabelType
Definition: inference.hxx:48
Minimization as a unary accumulation.
Definition: minimizer.hxx:12
Maximization as a unary accumulation.
Definition: maximizer.hxx:10
Parameter(const ValueType scale=1)
Definition: graphcut.hxx:39
OpenGM runtime error.
Definition: opengm.hxx:100
A framework for min st-cut algorithms.
Definition: graphcut.hxx:18
InferenceTermination
Definition: inference.hxx:24