/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2013 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLMath/src/ICLMath/GraphCutter.cpp ** ** Module : ICLMath ** ** Authors: Andre Ueckermann ** ** ** ** ** ** GNU LESSER GENERAL PUBLIC LICENSE ** ** This file may be used under the terms of the GNU Lesser General ** ** Public License version 3.0 as published by the ** ** ** ** Free Software Foundation and appearing in the file LICENSE.LGPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the license requirements will ** ** be met: http://www.gnu.org/licenses/lgpl-3.0.txt ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** ********************************************************************/ #include namespace icl{ namespace math{ float GraphCutter::minCut(DynMatrix &adjacencyMatrix, std::vector &subset1, std::vector &subset2){ //Please note: it is possible to add an additional adjacency matrix for faster lookup with values pointing to the edgeList IDs. //Find minimal cut cost for a single node (initial lambda) int lambda_id = -1; float lambda_score = initialLambda(adjacencyMatrix, lambda_id); //create edge list and edge costs std::vector edgeList; std::vector edgeCosts; createEdgeList(adjacencyMatrix, edgeList, edgeCosts); //initial single nodes std::vector > subsets = createInitialNodes(adjacencyMatrix); //merge to a graph with 2 nodes bool noQFound=false; while(subsets.size()>2 && noQFound==false){ //calculate lower bounds std::vector q = capforest(edgeList, edgeCosts, subsets.size()); noQFound=true; for(unsigned int j=0; j initial cost of single node if((q[j]>lambda_score)||(q[j]>=lambda_score && edgeList[j].x!=lambda_id && edgeList[j].y!=lambda_id)){//the two nodes can be merged noQFound=false; //merge lambda_score = merge(edgeList, edgeCosts, q, subsets, lambda_score, j, lambda_id); j=0;//start searching q from beginning (due to q-updates for merging) } } } if(subsets.size()!=2){ //lambda_id is already min-cut subset1 = subsets[lambda_id]; subset2.clear(); for(unsigned int i=0; i > GraphCutter::thresholdCut(DynMatrix &adjacencyMatrix, float threshold){ std::vector > subgraphs = findUnconnectedSubgraphs(adjacencyMatrix); std::vector > children(subgraphs.size());//children IDs (empty = none) for(unsigned int i=0; i1){ DynMatrix subMatrix = createSubMatrix(adjacencyMatrix, subgraphs[i]); std::vector subset1; std::vector subset2; float cost = math::GraphCutter::minCut(subMatrix, subset1, subset2); if(cost mappedSet1; std::vector mappedSet2; for(unsigned int j=0; j c; c.push_back(subgraphs.size()-2); c.push_back(subgraphs.size()-1); children[i]=c; } } } for(unsigned int i=0; i0){ subgraphs.erase(subgraphs.begin()+i); children.erase(children.begin()+i); i--; } } return subgraphs; } std::vector > GraphCutter::thresholdCut(DynMatrix &adjacencyMatrix, float threshold){ math::DynMatrix probabilities = calculateProbabilityMatrix(adjacencyMatrix, true); return thresholdCut(probabilities, threshold); } std::vector GraphCutter::hierarchicalCut(DynMatrix &adjacencyMatrix){ std::vector > subsets = findUnconnectedSubgraphs(adjacencyMatrix); std::vector cutNodes(subsets.size()); for(unsigned int i=0; i1){//inner nodes DynMatrix subMatrix = createSubMatrix(adjacencyMatrix, cutNodes[i].subset); std::vector subset1; std::vector subset2; float cost = math::GraphCutter::minCut(subMatrix, subset1, subset2); std::vector mappedSet1; std::vector mappedSet2; for(unsigned int j=0; j c; c.push_back(cutNodes.size()-2); c.push_back(cutNodes.size()-1); cutNodes[i].children=c;//set new nodes as children cutNodes[i].cost=cost;//set costs in parent }else{//leaf nodes cutNodes[i].cost=0; } } return cutNodes; } std::vector GraphCutter::hierarchicalCut(DynMatrix &adjacencyMatrix){ math::DynMatrix probabilities = calculateProbabilityMatrix(adjacencyMatrix, true); return hierarchicalCut(probabilities); } std::vector GraphCutter::capforest(std::vector &edgeList, std::vector &edgeCosts, int subsetsSize){ //calculate the lower bounds q(e) std::vector vVisited(subsetsSize, false); std::vector eVisited(edgeList.size(), false); std::vector r(subsetsSize, 0); std::vector q(edgeList.size(), 0); unsigned int unvisitedV = subsetsSize; while(unvisitedV>0){//while there exist an unvisited vertex //choose unvisited vertex with largest r float maxR=-10; int maxV=-1; for(unsigned int j=0; jmaxR){ maxR=r[j]; maxV=j; } } //for each unvisited adjacent node to maxV //please note: here a lookup would help to reduce the calls (check vertices instead of edges) for(unsigned j=0; j=0){//adjacent r[neighbour]+=edgeCosts[j]; q[j]=r[neighbour]; eVisited[j]=true; } } } vVisited[maxV] = true; unvisitedV--; } return q; } float GraphCutter::initialLambda(DynMatrix &adjacencyMatrix, int &lambda_id){ float lambda_score = 1000000; for(unsigned int j=0; j &adjacencyMatrix, std::vector &edgeList, std::vector &edgeCosts){ for(unsigned int j=0; j0){ utils::Point p(j,k); edgeList.push_back(p); edgeCosts.push_back(adjacencyMatrix(j,k)); } } } } std::vector > GraphCutter::createInitialNodes(DynMatrix &adjacencyMatrix){ std::vector > subsets; for(unsigned int j=0; j sg; sg.push_back(j); subsets.push_back(sg); } return subsets; } float GraphCutter::merge(std::vector &edgeList, std::vector &edgeCosts, std::vector &q, std::vector > &subsets, float lambda_score, int j, int &lambda_id){ int x=edgeList[j].x; int y=edgeList[j].y; edgeList.erase(edgeList.begin()+j);//delete the merging edge edgeCosts.erase(edgeCosts.begin()+j); q.erase(q.begin()+j); std::vector > sameIds(subsets.size());//merge edges for(unsigned int k=0; k1){// two edges connecting the same pair of vertices float maxQ = q[sameIds[k][0]];//update q with highest cost of merged edges for(unsigned int l=1; lmaxQ) maxQ=q[sameIds[k][l]]; //update q } q[sameIds[k][0]]=maxQ;//new q is the max of all merged q´s } } //delete merged edges (edges, costs, and q´s) std::vector merged; for(unsigned int k=0; k1){ for(unsigned int l=1; ly) edgeList[k].x--; if(edgeList[k].y>y) edgeList[k].y--; } if(cxy){//decrease lambda-id (due to vertex relabeling) lambda_id--; } return lambda_score; } std::vector > GraphCutter::findUnconnectedSubgraphs(DynMatrix &adjacencyMatrix){ std::vector > subgraphs; std::vector visited(adjacencyMatrix.rows(),false); unsigned int visitCount=0; while(visitCount subgraph;//create new subgraph int next=0; for(unsigned int i=0; i0 && visited[j]==false){//add node if not assigned and edge exists visited[j]=true; visitCount++; subgraph.push_back(j); } } } subgraphs.push_back(subgraph);//add subgraph } return subgraphs; } DynMatrix GraphCutter::createSubMatrix(DynMatrix &adjacencyMatrix, std::vector &subgraph){ math::DynMatrix subMatrix(subgraph.size(),subgraph.size()); for(unsigned int j=0; j GraphCutter::calculateProbabilityMatrix(math::DynMatrix &initialMatrix, bool symmetry){ math::DynMatrix probabilities=math::DynMatrix(initialMatrix.rows(),initialMatrix.cols(),0.0); for(unsigned int a=0; a &dst, DynMatrix &src){ if(src.rows()!=dst.rows()){ throw utils::ICLException("unequal sizes"); } for(unsigned int i=0; i &dst, DynMatrix &featureMatrix, float weight){ if(featureMatrix.rows()!=dst.rows()){ throw utils::ICLException("unequal sizes"); } for(unsigned int i=0; i