00001 #pragma once
00002 #ifndef OPENGM_GRAPHCUT_HXX
00003 #define OPENGM_GRAPHCUT_HXX
00004
00005 #include <typeinfo>
00006
00007 #include "opengm/operations/adder.hxx"
00008 #include "opengm/operations/maximizer.hxx"
00009 #include "opengm/inference/inference.hxx"
00010 #include "opengm/inference/visitors/visitor.hxx"
00011
00012 namespace opengm {
00013
00017 template<class GM, class ACC, class MINSTCUT>
00018 class GraphCut : public Inference<GM, ACC> {
00019 public:
00020 typedef ACC AccumulationType;
00021 typedef GM GraphicalModelType;
00022 OPENGM_GM_TYPE_TYPEDEFS;
00023 typedef MINSTCUT MinStCutType;
00024 typedef VerboseVisitor<GraphCut<GM,ACC,MINSTCUT> > VerboseVisitorType;
00025 typedef TimingVisitor<GraphCut<GM,ACC,MINSTCUT> > TimingVisitorType;
00026 typedef EmptyVisitor<GraphCut<GM,ACC,MINSTCUT> > EmptyVisitorType;
00027 struct Parameter {
00028 Parameter(const ValueType scale = 1)
00029 : scale_(scale)
00030 {}
00031 ValueType scale_;
00032 };
00033
00034 GraphCut(const GraphicalModelType&, const Parameter& = Parameter(), ValueType = static_cast<ValueType>(0.0));
00035 GraphCut(size_t numVar, std::vector<size_t> numFacDim, const Parameter& = Parameter(), ValueType = static_cast<ValueType>(0.0));
00036 ~GraphCut();
00037
00038 std::string name() const;
00039 const GraphicalModelType& graphicalModel() const;
00040 template<class FACTOR>
00041 void addFactor(const FACTOR& factor);
00042 InferenceTermination infer();
00043 template<class VISITOR>
00044 InferenceTermination infer(VISITOR & visitor);
00045 InferenceTermination arg(std::vector<LabelType>&, const size_t = 1) const;
00046
00047 private:
00048 void addEdgeCapacity(const size_t, const size_t, const ValueType);
00049 size_t tripleId(std::vector<size_t>&);
00050
00051 const GraphicalModelType& gm_;
00052 ValueType tolerance_;
00053 MinStCutType* minStCut_;
00054 Parameter parameter_;
00055 size_t numVariables_;
00056 std::vector<size_t> numFacDim_;
00057 std::list<std::vector<size_t> > tripleList;
00058 std::vector<bool> state_;
00059 std::vector<typename MINSTCUT::ValueType> sEdges_;
00060 std::vector<typename MINSTCUT::ValueType> tEdges_;
00061 };
00062
00063 template<class GM, class ACC, class MINSTCUT>
00064 inline std::string
00065 GraphCut<GM, ACC, MINSTCUT>::name() const {
00066 return "GraphCut";
00067 }
00068
00069 template<class GM, class ACC, class MINSTCUT>
00070 inline const typename GraphCut<GM, ACC, MINSTCUT>::GraphicalModelType&
00071 GraphCut<GM, ACC, MINSTCUT>::graphicalModel() const {
00072 return gm_;
00073 }
00074
00075 template<class GM, class ACC, class MINSTCUT>
00076 inline GraphCut<GM, ACC, MINSTCUT>::GraphCut
00077 (
00078 const size_t numVariables,
00079 std::vector<size_t> numFacDim,
00080 const Parameter& para,
00081 const ValueType tolerance
00082 )
00083 : gm_(GM()),
00084 tolerance_(fabs(tolerance))
00085 {
00086 OPENGM_ASSERT(typeid(ACC) == typeid(opengm::Minimizer) || typeid(ACC) == typeid(opengm::Maximizer));
00087 OPENGM_ASSERT(typeid(typename GM::OperatorType) == typeid(opengm::Adder));
00088 OPENGM_ASSERT(numFacDim_.size() <= 3+1);
00089 parameter_ = para;
00090 numVariables_ = numVariables;
00091 numFacDim_ = numFacDim;
00092 numFacDim_.resize(4);
00093 minStCut_ = new MinStCutType(2 + numVariables_ + numFacDim_[3], 2*numVariables_ + numFacDim_[2] + 3*numFacDim_[3]);
00094 sEdges_.assign(numVariables_ + numFacDim_[3], 0);
00095 tEdges_.assign(numVariables_ + numFacDim_[3], 0);
00096
00097
00098 }
00099
00100 template<class GM, class ACC, class MINSTCUT>
00101 inline GraphCut<GM, ACC, MINSTCUT>::GraphCut
00102 (
00103 const GraphicalModelType& gm,
00104 const Parameter& para,
00105 const ValueType tolerance
00106 )
00107 : gm_(gm),
00108 tolerance_(fabs(tolerance))
00109 {
00110 if(typeid(ACC) != typeid(opengm::Minimizer) && typeid(ACC) != typeid(opengm::Maximizer)) {
00111 throw RuntimeError("This implementation of the graph cut optimizer supports as accumulator only opengm::Minimizer and opengm::Maximizer.");
00112 }
00113 for(size_t j = 0; j < gm.numberOfVariables(); ++j) {
00114 if(gm.numberOfLabels(j) != 2) {
00115 throw RuntimeError("This implementation of the graph cut optimizer supports only binary variables.");
00116 }
00117 }
00118 for(size_t j = 0; j < gm.numberOfFactors(); ++j) {
00119 if(gm[j].numberOfVariables() > 3) {
00120 throw RuntimeError("This implementation of the graph cut optimizer supports only factors of order <= 3.");
00121 }
00122 }
00123
00124 parameter_ = para;
00125 numVariables_ = gm.numberOfVariables();
00126 numFacDim_.resize(4, 0);
00127 for(size_t j = 0; j < gm.numberOfFactors(); ++j) {
00128 ++numFacDim_[gm[j].numberOfVariables()];
00129 }
00130
00131 minStCut_ = new MinStCutType(2 + numVariables_ + numFacDim_[3], 2*numVariables_ + numFacDim_[2] + 3*numFacDim_[3]);
00132 sEdges_.assign(numVariables_ + numFacDim_[3], 0);
00133 tEdges_.assign(numVariables_ + numFacDim_[3], 0);
00134
00135 for(size_t j = 0; j < gm.numberOfFactors(); ++j) {
00136 addFactor(gm[j]);
00137 }
00138
00139 }
00140
00141 template<class GM, class ACC, class MINSTCUT>
00142 inline GraphCut<GM, ACC, MINSTCUT>::~GraphCut()
00143 {
00144 delete minStCut_;
00145 }
00146
00148 template<class GM, class ACC, class MINSTCUT>
00149 template<class FACTOR>
00150 inline void GraphCut<GM, ACC, MINSTCUT>::addFactor
00151 (
00152 const FACTOR& factor
00153 ) {
00154 size_t numberOfVariables = factor.numberOfVariables();
00155 for(size_t i=0; i<numberOfVariables; ++i) {
00156 OPENGM_ASSERT(factor.numberOfLabels(i) == 2);
00157 }
00158
00159 if(numberOfVariables == 0) {
00160
00161 }
00162 else if(numberOfVariables == 1) {
00163 const size_t var = factor.variableIndex(0);
00164 OPENGM_ASSERT(var < numVariables_);
00165 size_t i;
00166 i = 0; const ValueType v0 = factor(&i);
00167 i = 1; const ValueType v1 = factor(&i);
00168 if(typeid(ACC) == typeid(opengm::Minimizer)) {
00169 if(v0 <= v1) {
00170 addEdgeCapacity(0, var + 2, v1 - v0);
00171 }
00172 else {
00173 addEdgeCapacity(var + 2, 1, v0 - v1);
00174 }
00175 }
00176 else {
00177 if(v0 >= v1) {
00178 addEdgeCapacity(0, var + 2, -v1 + v0);
00179 }
00180 else {
00181 addEdgeCapacity(var + 2, 1, -v0 + v1);
00182 }
00183 }
00184 }
00185 else if(numberOfVariables == 2) {
00186 const size_t var0 = factor.variableIndex(0);
00187 const size_t var1 = factor.variableIndex(1);
00188 OPENGM_ASSERT(var0 < numVariables_);
00189 OPENGM_ASSERT(var1 < numVariables_);
00190 size_t i[] = {0, 0}; const ValueType A = factor(i);
00191 i[0] = 0; i[1] = 1; const ValueType B = factor(i);
00192 i[0] = 1; i[1] = 0; const ValueType C = factor(i);
00193 i[0] = 1; i[1] = 1; const ValueType D = factor(i);
00194 if(typeid(ACC) == typeid(opengm::Minimizer)) {
00195
00196 if(C > A)
00197 addEdgeCapacity(0, var0 + 2, C - A);
00198 else if(C < A)
00199 addEdgeCapacity(var0 + 2, 1, A - C);
00200
00201 if(D > C)
00202 addEdgeCapacity(0, var1 + 2, D - C);
00203 else if(D < C)
00204 addEdgeCapacity(var1 + 2, 1, C - D);
00205
00206 ValueType term = B + C - A - D;
00207 if((term < 0) && (term >= -tolerance_))
00208 term = 0.0;
00209
00210
00211
00212 addEdgeCapacity(var0 + 2, var1 + 2, term);
00213 }
00214 else{
00215 if(C < A)
00216 addEdgeCapacity(0, var0 + 2, -C + A);
00217 else if(C > A)
00218 addEdgeCapacity(var0 + 2, 1, -A + C);
00219
00220 if(D < C)
00221 addEdgeCapacity(0, var1 + 2, -D + C);
00222 else if(D > C)
00223 addEdgeCapacity(var1 + 2, 1, -C + D);
00224
00225 ValueType term = B + C - A - D;
00226 if((term > 0) && (term <= tolerance_))
00227 term = 0.0;
00228 addEdgeCapacity(var0 + 2, var1 + 2, -term);
00229
00230
00231
00232 }
00233 }
00234 else if(numberOfVariables == 3) {
00235 const size_t var0 = factor.variableIndex(0);
00236 const size_t var1 = factor.variableIndex(1);
00237 const size_t var2 = factor.variableIndex(1);
00238 OPENGM_ASSERT(var0 < numVariables_);
00239 OPENGM_ASSERT(var1 < numVariables_);
00240 OPENGM_ASSERT(var2 < numVariables_);
00241 size_t i[] = {0, 0, 0}; const ValueType A = factor(i);
00242 i[0] = 0; i[1] = 0; i[2] = 1; const ValueType B = factor(i);
00243 i[0] = 0; i[1] = 1; i[2] = 0; const ValueType C = factor(i);
00244 i[0] = 0; i[1] = 1; i[2] = 1; const ValueType D = factor(i);
00245 i[0] = 1; i[1] = 0; i[2] = 0; const ValueType E = factor(i);
00246 i[0] = 1; i[1] = 0; i[2] = 1; const ValueType F = factor(i);
00247 i[0] = 1; i[1] = 1; i[2] = 0; const ValueType G = factor(i);
00248 i[0] = 1; i[1] = 1; i[2] = 1; const ValueType H = factor(i);
00249
00250 if(typeid(ACC) == typeid(opengm::Minimizer)) {
00251 std::vector<size_t> triple(3);
00252 triple[0] = var0;
00253 triple[1] = var1;
00254 triple[2] = var2;
00255 size_t id = tripleId(triple);
00256 ValueType P = (A + D + F + G)-(B + C + E + H);
00257 if(P >= 0.0) {
00258 if(F-B>=0) addEdgeCapacity(0, var0+2, F - B);
00259 else addEdgeCapacity(var0+2, 1, B - F);
00260 if(G-E>=0) addEdgeCapacity(0, var1+2, G - E);
00261 else addEdgeCapacity(var1+2, 1, E - G);
00262 if(D-C>=0) addEdgeCapacity(0, var2+2, D - C);
00263 else addEdgeCapacity(var2+2, 0, C - D);
00264
00265 addEdgeCapacity(var1+2, var2+2, B + C - A - D);
00266 addEdgeCapacity(var2+2, var0+2, B + E - A - F);
00267 addEdgeCapacity(var0+2, var1+2, C + E - A - G);
00268
00269 addEdgeCapacity(var0 + 2, id + 2, P);
00270 addEdgeCapacity(var1 + 2, id + 2, P);
00271 addEdgeCapacity(var2 + 2, id + 2, P);
00272 addEdgeCapacity(id, 1, P);
00273 }
00274 else {
00275 if(C-G>=0) addEdgeCapacity(var0+2, 1, C - G);
00276 else addEdgeCapacity(0, var0+2, G - C);
00277 if(B-D>=0) addEdgeCapacity(var1+2, 1, B - D);
00278 else addEdgeCapacity(0, var1+2, D - B);
00279 if(E-F>=0) addEdgeCapacity(var2+2, 1, E - F);
00280 else addEdgeCapacity(0, var2+2, F - E);
00281
00282 addEdgeCapacity(var2+2, var1+2, F + G - E - H);
00283 addEdgeCapacity(var0+2, var2+2, D + G - C - H);
00284 addEdgeCapacity(var1+2, var0+2, D + F - B - H);
00285
00286 addEdgeCapacity(id + 2, var0 + 2, -P);
00287 addEdgeCapacity(id + 2, var1 + 2, -P);
00288 addEdgeCapacity(id + 2, var2 + 2, -P);
00289 addEdgeCapacity(0, id + 2, -P);
00290 };
00291 }
00292 else{
00293 throw RuntimeError("This implementation of the graph cut optimizer support 3rd order factors only in connection with opengm::Maximizer.");
00294 }
00295 }
00296 else {
00297 throw RuntimeError("This implementation of the graph cut optimizer does not support factors of order > 3.");
00298 }
00299 }
00300
00301 template<class GM, class ACC, class MINSTCUT>
00302 inline void
00303 GraphCut<GM, ACC, MINSTCUT>::addEdgeCapacity
00304 (
00305 const size_t v,
00306 const size_t w,
00307 const ValueType val
00308 ) {
00309 typedef typename MINSTCUT::ValueType VType;
00310 typedef typename MINSTCUT::node_type NType;
00311 const NType n1 = static_cast<NType>(v);
00312 const NType n2 = static_cast<NType>(w);
00313 const VType cost = static_cast<VType>(parameter_.scale_*val);
00314 if(n1 == 0) {
00315 sEdges_[n2-2] += cost;
00316 }
00317 else if(n2 == 1) {
00318 tEdges_[n1-2] += cost;
00319 }
00320 else {
00321 minStCut_->addEdge(n1, n2, cost);
00322 }
00323 }
00324
00325 template<class GM, class ACC, class MINSTCUT>
00326 inline size_t
00327 GraphCut<GM, ACC, MINSTCUT>::tripleId
00328 (
00329 std::vector<size_t>& triple
00330 ) {
00331
00332 std::list<std::vector<size_t> >::iterator it;
00333 size_t counter = numVariables_;
00334 for(it = tripleList.begin(); it != tripleList.end(); it++) {
00335 if(triple[0] == (*it)[0] && triple[1] == (*it)[1] && triple[2] == (*it)[2]) {
00336 return counter;
00337 }
00338 numVariables_++;
00339 }
00340
00341 tripleList.push_back(triple);
00342 OPENGM_ASSERT(counter - numVariables_ < numFacDim_[3]);
00343 return counter;
00344 }
00345
00346 template<class GM, class ACC, class MINSTCUT>
00347 inline InferenceTermination
00348 GraphCut<GM, ACC, MINSTCUT>::infer() {
00349 EmptyVisitorType v;
00350 return infer(v);
00351 }
00352
00353 template<class GM, class ACC, class MINSTCUT>
00354 template<class VISITOR>
00355 inline InferenceTermination
00356 GraphCut<GM, ACC, MINSTCUT>::infer(VISITOR & visitor) {
00357 visitor.begin(*this);
00358 for(size_t i=0; i<sEdges_.size(); ++i) {
00359 minStCut_->addEdge(0, i+2, sEdges_[i]);
00360 minStCut_->addEdge(i+2, 1, tEdges_[i]);
00361 }
00362 minStCut_->calculateCut(state_);
00363 visitor.end(*this);
00364 return NORMAL;
00365 }
00366
00367 template<class GM, class ACC, class MINSTCUT>
00368 inline InferenceTermination GraphCut<GM, ACC, MINSTCUT>::arg
00369 (
00370 std::vector<LabelType>& arg,
00371 const size_t n
00372 ) const {
00373 if(n > 1) {
00374 return UNKNOWN;
00375 }
00376 else {
00377
00378 if(state_.size() > 2 + numFacDim_[3]) {
00379 arg.resize(state_.size() - 2 - numFacDim_[3]);
00380 }
00381 else {
00382 arg.resize(0);
00383 }
00384
00385 for(size_t j = 0; j < arg.size(); ++j) {
00386 arg[j] = static_cast<LabelType>(state_[j + 2]);
00387 }
00388 return NORMAL;
00389 }
00390 }
00391
00392 }
00393
00394 #endif // #ifndef OPENGM_GRAPHCUT_HXX
00395