/* Copyright Olga Veksler, Ramin Zabih, Vladimir Kolmogorov, and Daniel Scharstein * Send any questions to schar@middlebury.edu */ #ifndef __MRF_H__ #define __MRF_H__ #include class EnergyFunction; class MRF { public: // *********** CONSTRUCTORS/DESTRUCTOR // Constructor. After you call this, you must call setData and setSmoothness // Use this constructor for 2D grid graphs of size width by height Standard 4-connected // neighborhood system is assumed. Labels are in the range 0,1,...nLabels - 1 // Width is in the range 0,1,...width-1 and height is in the range 0,1,...height-1 // Input parameter eng specifies the data and smoothness parts of the energy // For 2D grids, since 4 connected neighborhood structure is assumed, this // fully specifies the energy MRF(int width, int height, int nLabels, EnergyFunction *eng); // Use this constructor for a general neighborhood system. Pixels are in the range // 0,1,..nPixels-1, and labels are in the range 0,1,...,nLabels-1 // Input parameter eng specifies the data and smoothness parts of the energy // after this constructor you need to call setNeighbors() to specify the neighborhood system MRF(int nPixels, int nLabels, EnergyFunction *eng); virtual ~MRF() { } // Returns true if energy function has been specified, returns false otherwise // By default, it always returns true. Can be modified by the supplier of // optimization algorithm virtual int isValid(){return true;}; // *********** EVALUATING THE ENERGY typedef int Label; typedef float EnergyVal; /* The total energy of a labeling */ typedef float CostVal; /* costs of individual terms of the energy */ EnergyVal totalEnergy(); /* returns energy of current labeling */ virtual EnergyVal dataEnergy() = 0; /* returns the data part of the energy */ virtual EnergyVal smoothnessEnergy() = 0; /* returns the smoothness part of the energy */ //Functional representation for data costs typedef CostVal (*DataCostFn)(int pix, Label l); // Functional representation for the general cost function type typedef CostVal (*SmoothCostGeneralFn)(int pix1, int pix2, Label l1, Label l2); // For general smoothness functions, some implementations try to cache all function values in an array // for efficiency. To prevent this, call the following function before calling initialize(): void dontCacheSmoothnessCosts() {m_allocateArrayForSmoothnessCostFn = false;} // Use this function only for non-grid graphs. Sets pix1 and pix2 to be neighbors // with the specified weight. Can be called ONLY once for each pair of pixels // That is if pixel1 and pixel2 are neihbors, call either setNeighbors(pixel1,pixel2,weight) // or setNeighbors(pixel2,pixel1,weight), but NOT BOTH virtual void setNeighbors(int pix1, int pix2, CostVal weight)= 0; void initialize(); // Runs optimization for nIterations. Input parameter time returns the time it took to // perform nIterations of optimization void optimize(int nIterations, float& time); virtual void optimizeAlg(int nIterations)=0; // *********** ACCESS TO SOLUTION // Returns pointer to array of size nPixels. Client may then read/write solution (but not deallocate array). virtual Label* getAnswerPtr()= 0; // returns the label of the input pixel virtual Label getLabel(int pixel)= 0; // sets label of a pixel virtual void setLabel(int pixel,Label label)= 0; // sets all the labels to zero virtual void clearAnswer() = 0; // use this function to pass any parameters to optimization algorithm. // The first argument is the number of passed, parameters and // the second argument is the pointer to the array of parameters virtual void setParameters(int numParam, void *param) = 0; // This function returns lower bound computed by the algorithm (if any) // By default, it returns 0. virtual double lowerBound(){return((double) 0);}; // Returns 0 if the energy is not suitable for current optimization algorithm // Returns 1 if the energy is suitable for current optimization algorithm // Returns 2 if current optimizaiton algorithm does not check the energy virtual char checkEnergy(); typedef enum { FUNCTION, ARRAY, THREE_PARAM, NONE } InputType; protected: int m_width, m_height; // width and height of a grid,if graph is a grid int m_nPixels; // number of pixels, for both grid and non-grid graphs int m_nLabels; // number of labels, for both grid and non-grid graphs bool m_grid_graph; // true if the graph is a 2D grid bool m_varWeights; // true if weights are spatially varying. To be used only with 2D grids bool m_initialized; // true if array m_V is allocated memory. EnergyFunction *m_e; InputType m_dataType; InputType m_smoothType; // *********** SET THE DATA COSTS // Following 2 functions set the data costs virtual void setData(DataCostFn dcost)=0; virtual void setData(CostVal* data)=0; // *********** SET THE SMOOTHNESS COSTS // following 3 functions set the smoothness costs // there are 2 ways to represent the smoothness costs, one with array, one with function // In addition, for 2D grid graphs spacially varying weights can be specified by 2 arrays // Smoothness cost depends on labels V(l1,l2) for all edges (except for a multiplier - see setCues() ). // V must be symmetric: V(l1,l2) = V(l2,l1) // V must be an array of size nLabels*nLabels. It is NOT copied into internal memory virtual void setSmoothness(CostVal* V)=0; // General smoothness cost can be specified by passing pointer to a function virtual void setSmoothness(SmoothCostGeneralFn cost)=0; // To prevent implementations from caching all general smoothness costs values, the flag below // can be set to false by calling dontCacheSmoothnessCosts() before calling initialize(): bool m_allocateArrayForSmoothnessCostFn; // Use if the smoothness is V(l1,l2) = lambda * min ( |l1-l2|^m_smoothExp, m_smoothMax ) // Can also add optional spatially varying weights for 2D grid graphs using setCues() virtual void setSmoothness(int smoothExp,CostVal smoothMax, CostVal lambda)=0; // You are not required to call setCues, in which case there is no multiplier. // Function below cannot be called for general cost function. // This function can be only used for a 2D grid graph // hCue and vCue must be arrays of size width*height in row major order. // They are NOT copied into internal memory. // hCue(x,y) holds the variable weight for edge between pixels (x+1,y) and (x,y) // vCue(x,y) holds the variable weight for edge between pixels (x,y+1) and (x,y) virtual void setCues(CostVal* hCue, CostVal* vCue)=0; virtual void initializeAlg()=0; // called by initialize() void commonInitialization(EnergyFunction *e); void checkArray(CostVal *V); }; // *********** This class is for data costs // Data costs can be specified eithe by an array or by a pointer to a function // If specified by an array, use constructor DataCost(cost) where // cost is the array of type CostVal. The cost of pixel p and label l is // stored at cost[p*nLabels+l] where nLabels is the number of labels // If data costs are to be specified by a function, pass // a pointer to a function // CostVal costFn(int pix, Label lab) // which returns the // data cost of pixel pix to be assigned label lab class DataCost { friend class MRF; public: typedef MRF::CostVal CostVal; typedef MRF::DataCostFn DataCostFn; DataCost(CostVal *cost){m_costArray = cost;m_type = MRF::ARRAY; }; DataCost(DataCostFn costFn){m_costFn = costFn;m_type = MRF::FUNCTION;}; private: MRF::CostVal *m_costArray; MRF::DataCostFn m_costFn; MRF::InputType m_type; }; // ***************** This class represents smoothness costs // If the smoothness is V(l1,l2) = lambda * min ( |l1-l2|^m_smoothExp, m_smoothMax ) // use constructor SmoothnessCost(smoothExp,smoothMax,lambda) // If, in addition, there are spacially varying weights use constructor // SmoothnessCost(smoothExp,smoothMax,lambda,hWeights,vWeights) // hWeights and vWeights can be only used for a 2D grid graph // hWeights and vWeights must be arrays of size width*height in row major order. // They are NOT copied into internal memory. // hWeights(x,y) holds the variable weight for edge between pixels (x+1,y) and (x,y) // vWeights(x,y) holds the variable weight for edge between pixels (x,y+1) and (x,y) // If the smoothness costs are specified by input array V of type CostVal and // size nLabels*nLabels, use consructor SmoothnessCost(V). // If in addition, there are // are spacially varying weights use constructor SmoothnessCost(V,hWeights,vWeights) // Note that array V must be of size nLabels*nLabels, and be symmetric. // That is V[i*nLabels+j] = V[j*nLabels+i] // Finally, if the smoothness term is specified by a general function, use // constructor SmoothnessCost(costFn) class SmoothnessCost { friend class MRF; public: typedef MRF::CostVal CostVal; // Can be used for 2D grids and for general graphs // In case if used for 2D grids, the smoothness term WILL NOT be spacially varying SmoothnessCost(int smoothExp,CostVal smoothMax,CostVal lambda) {m_type=MRF::THREE_PARAM;m_smoothMax = smoothMax;m_smoothExp = smoothExp;m_lambda=lambda;m_varWeights=false;}; // Can be used only for 2D grids // the smoothness term WILL BE be spacially varying SmoothnessCost(int smoothExp,CostVal smoothMax,CostVal lambda,CostVal *hWeights, CostVal *vWeights) {m_type=MRF::THREE_PARAM;m_smoothMax = smoothMax;m_smoothExp = smoothExp;m_lambda=lambda; m_varWeights = true;m_hWeights = hWeights; m_vWeights = vWeights;}; // Can be used 2D grids and for general graphs // In case if used for 2D grids, the smoothness term WILL NOT be spacially varying SmoothnessCost(CostVal *V){m_V = V;m_type = MRF::ARRAY;m_varWeights=false;}; // Can be used only for 2D grids // the smoothness term WILL BE be spacially varying SmoothnessCost(CostVal *V,CostVal *hWeights, CostVal *vWeights ) {m_V = V;m_hWeights = hWeights; m_vWeights = vWeights; m_varWeights = true; m_type=MRF::ARRAY;}; // Can be used 2D grids and for general graphs SmoothnessCost(MRF::SmoothCostGeneralFn costFn){m_costFn = costFn;m_type = MRF::FUNCTION;m_varWeights=false;}; private: CostVal *m_V,*m_hWeights, *m_vWeights; MRF::SmoothCostGeneralFn m_costFn; MRF::InputType m_type; int m_smoothExp; CostVal m_smoothMax,m_lambda; bool m_varWeights; EnergyFunction *m_eng; }; class EnergyFunction { public: EnergyFunction(DataCost *dataCost,SmoothnessCost *smoothCost) {m_dataCost = dataCost;m_smoothCost = smoothCost;}; DataCost *m_dataCost; SmoothnessCost *m_smoothCost; }; #endif /* __MRF_H__ */ /* virtual EnergyVal dataEnergy() = 0; virtual EnergyVal smoothnessEnergy() = 0; virtual void setNeighbors(int pix1, int pix2, CostVal weight)= 0; virtual void optimizeAlg(int nIterations)=0; virtual Label* getAnswerPtr()= 0; virtual Label getLabel(int pixel)= 0; virtual void setLabel(int pixel,Label label)= 0; virtual void clearAnswer() = 0; virtual void setParameters(int numParam, void *param) = 0; virtual void setData(DataCostFn dcost)=0; virtual void setData(CostVal* data)=0; virtual void setSmoothness(CostVal* V)=0; virtual void setSmoothness(SmoothCostGeneralFn cost)=0; virtual void setCues(CostVal* hCue, CostVal* vCue)=0; virtual void setSmoothness(int smoothExp,CostVal smoothMax, CostVal lambda); virtual EnergyVal lowerBound(){return((EnergyVal) 0);}; */