graphcut.hxx

Go to the documentation of this file.
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    //std::cout << parameter_.scale_ <<std::endl;
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    //std::cout << parameter_.scale_ <<std::endl;
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       // do nothing
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 { //opengm::Maximizer
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          // first variabe
00196          if(C > A)
00197             addEdgeCapacity(0, var0 + 2, C - A);
00198          else if(C < A)
00199             addEdgeCapacity(var0 + 2, 1, A - C);
00200          // second variable
00201          if(D > C)
00202             addEdgeCapacity(0, var1 + 2, D - C);
00203          else if(D < C)
00204             addEdgeCapacity(var1 + 2, 1, C - D);
00205          // submodular term
00206          ValueType term = B + C - A - D;
00207          if((term < 0) && (term >= -tolerance_))
00208             term = 0.0;
00209          //if(term < 0.0) {
00210          //  throw RuntimeError("GraphCut<Factor>::addPairwisefactor(): non sub-modular factors cannot be processed.");
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          // second variable
00220          if(D < C)
00221             addEdgeCapacity(0, var1 + 2, -D + C);
00222          else if(D > C)
00223             addEdgeCapacity(var1 + 2, 1, -C + D);
00224          // submodular term
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          //if(term > 0.0) {
00230          //  throw RuntimeError("GraphCut<Factor>::addPairwisefactor(): non sub-modular factors cannot be processed.");
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    // search for triple in list
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    // add triple to list
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       // skip source and sink
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 } // namespace opengm
00393 
00394 #endif // #ifndef OPENGM_GRAPHCUT_HXX
00395 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Mon Jun 17 16:31:02 2013 for OpenGM by  doxygen 1.6.3