/* Estimate segmentation using MaxFlow algorithm */ static void estimateSegmentation( GCGraph<double>& graph, InputArray _img) { Mat img = _img.getMat(); Mat result; result.create(img.size(), CV_8UC1); graph.maxFlow(); Point p; for( p.y = 0; p.y < img.rows; p.y++ ) { for( p.x = 0; p.x < img.cols; p.x++ ) { if( graph.inSourceSegment( p.y*img.cols+p.x /*vertex index*/ ) ) { //printf("1\n"); result.at<uchar>(p) = 0; } else { //printf("2\n"); result.at<uchar>(p) = 255; } } } namedWindow("Image",1); imshow("Image", result); waitKey(); }
/** * Add each pixel as * a node in a graph * * @param graph The graph pointer * @param img The Source image * * * @return Updates the graph */ void GRAPHCUT::addVertices(GCGraph<float>& graph, Mat& img) { for (int r = 0; r < img.rows; r++) for (int c = 0; c < img.cols; c++) { graph.addVtx(); graph.addTermWeights(c + img.cols * r, img.at<float>(r, c), 1 - img.at<float>(r, c)); } }
/* Estimate segmentation using MaxFlow algorithm */ void estimateSegmentation( GCGraph<double>& graph, Mat& mask ) { graph.maxFlow(); Point p; for( p.y = 0; p.y < mask.rows; p.y++ ) { for( p.x = 0; p.x < mask.cols; p.x++ ) { if( mask.at<uchar>(p) == GC_PR_BGD || mask.at<uchar>(p) == GC_PR_FGD ) { if( graph.inSourceSegment( p.y*mask.cols+p.x /*vertex index*/ ) ) mask.at<uchar>(p) = GC_PR_FGD; else mask.at<uchar>(p) = GC_PR_BGD; } } } }
/* Construct GCGraph */ void constructGCGraph( const Mat& img, const Mat& mask, const GMM& bgdGMM, const GMM& fgdGMM, double lambda, const Mat& leftW, const Mat& upleftW, const Mat& upW, const Mat& uprightW, GCGraph<double>& graph ) { int vtxCount = img.cols*img.rows, edgeCount = 2*(4*img.cols*img.rows - 3*(img.cols + img.rows) + 2); graph.create(vtxCount, edgeCount); Point p; for( p.y = 0; p.y < img.rows; p.y++ ) { for( p.x = 0; p.x < img.cols; p.x++) { // add node int vtxIdx = graph.addVtx(); Vec3b color = img.at<Vec3b>(p); // set t-weights double fromSource, toSink; if( mask.at<uchar>(p) == GC_PR_BGD || mask.at<uchar>(p) == GC_PR_FGD ) { fromSource = -log( bgdGMM(color) ); toSink = -log( fgdGMM(color) ); } else if( mask.at<uchar>(p) == GC_BGD ) { fromSource = 0; toSink = lambda; } else // GC_FGD { fromSource = lambda; toSink = 0; } graph.addTermWeights( vtxIdx, fromSource, toSink ); // set n-weights if( p.x>0 ) { double w = leftW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-1, w, w ); } if( p.x>0 && p.y>0 ) { double w = upleftW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-img.cols-1, w, w ); } if( p.y>0 ) { double w = upW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-img.cols, w, w ); } if( p.x<img.cols-1 && p.y>0 ) { double w = uprightW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-img.cols+1, w, w ); } } } }
/** * Convert a Graph * into an image * * @param graph The Source graph * @param rows Image Height * @param cols Image Width * * * @return Converted Image */ Mat GRAPHCUT::graph2img(GCGraph<float>& graph, int rows, int cols) { Mat img(rows, cols, CV_32F); for (int r = 0; r < rows; r++) for (int c = 0; c < cols; c++) img.at<float>(r, c) = graph.inSourceSegment(c + img.cols * r); return img; }
/* Construct GCGraph */ static void constructGCGraph( const Mat& img, double lambda, const Mat& leftW, const Mat& upleftW, const Mat& upW, const Mat& uprightW, GCGraph<double>& graph ) { int vtxCount = img.cols*img.rows, edgeCount = 2*(4*img.cols*img.rows - 3*(img.cols + img.rows) + 2); graph.create(vtxCount, edgeCount); Point p; Mat gray; cvtColor(img, gray, CV_BGR2GRAY); Mat bw; threshold(gray, bw, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); for( p.y = 0; p.y < img.rows; p.y++ ) { for( p.x = 0; p.x < img.cols; p.x++) { // add node int vtxIdx = graph.addVtx(); Vec3b color = img.at<Vec3b>(p); // set t-weights double fromSource, toSink; if(bw.at<uchar>(p) == 0) { fromSource = lambda; toSink = 0; } else { fromSource = 0; toSink = lambda; } graph.addTermWeights( vtxIdx, fromSource, toSink ); // set n-weights if( p.x>0 ) { double w = leftW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-1, w, w ); } if( p.x>0 && p.y>0 ) { double w = upleftW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-img.cols-1, w, w ); } if( p.y>0 ) { double w = upW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-img.cols, w, w ); } if( p.x<img.cols-1 && p.y>0 ) { double w = uprightW.at<double>(p); graph.addEdges( vtxIdx, vtxIdx-img.cols+1, w, w ); } } } }
/** * Add edges between * nodes in a graph * * @param graph The graph pointer * @param img The Source image * @param neighboursWeight Neighbours influence * @param windowSize Neighbours range * * @return Updates the graph */ void GRAPHCUT::addEdges(GCGraph<float>& graph, Mat& img, float neighboursWeight, int windowSize) { for (int r = windowSize; r < img.rows - windowSize; r++) for (int c = windowSize; c < img.cols - windowSize; c++) for (int i = -windowSize; i <= windowSize; i++) for (int j = -windowSize; j <= windowSize; j++) if (i != 0 || j != 0) { float v = abs(img.at<float>(r, c) - img.at<float>(r + i, c + j)) * neighboursWeight; graph.addEdges(c + img.cols * r, (c + j) + img.cols * (r + i), v, v); } }