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