コード例 #1
0
ファイル: example.cpp プロジェクト: netbeen/UncleZhou_UI
////////////////////////////////////////////////////////////////////////////////
// in this version, set data and smoothness terms using arrays
// grid neighborhood is set up "manually"
//
void GeneralGraph_DArraySArray(int width,int height,int num_pixels,int num_labels)
{

	int *result = new int[num_pixels];   // stores result of optimization

	// first set up the array for data costs
	int *data = new int[num_pixels*num_labels];
	for ( int i = 0; i < num_pixels; i++ )
		for (int l = 0; l < num_labels; l++ )
			if (i < 25 ){
				if(  l == 0 ) data[i*num_labels+l] = 0;
				else data[i*num_labels+l] = 10;
			}
			else {
				if(  l == 5 ) data[i*num_labels+l] = 0;
				else data[i*num_labels+l] = 10;
			}
	// next set up the array for smooth costs
	int *smooth = new int[num_labels*num_labels];
	for ( int l1 = 0; l1 < num_labels; l1++ )
		for (int l2 = 0; l2 < num_labels; l2++ )
			smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4  ? (l1-l2)*(l1-l2):4;


	try{
		GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels,num_labels);
		gc->setDataCost(data);
		gc->setSmoothCost(smooth);

		// now set up a grid neighborhood system
		// first set up horizontal neighbors
		for (int y = 0; y < height; y++ )
			for (int  x = 1; x < width; x++ )
				gc->setNeighbors(x+y*width,x-1+y*width);

		// next set up vertical neighbors
		for (int y = 1; y < height; y++ )
			for (int  x = 0; x < width; x++ )
				gc->setNeighbors(x+y*width,x+(y-1)*width);

		printf("\nBefore optimization energy is %d",gc->compute_energy());
		gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
		printf("\nAfter optimization energy is %d",gc->compute_energy());

		for ( int  i = 0; i < num_pixels; i++ )
			result[i] = gc->whatLabel(i);

		delete gc;
	}
	catch (GCException e){
		e.Report();
	}

	delete [] result;
	delete [] smooth;
	delete [] data;

}
コード例 #2
0
ファイル: GCMex.cpp プロジェクト: Wahib/Graph-Cut
void mexFunction(
    int		  nout, 	/* number of expected outputs */
    mxArray	  *out[],	/* mxArray output pointer array */
    int		  nin, 		/* number of inputs */
    const mxArray	  *in[]	/* mxArray input pointer array */
    )
{
   
  enum {IN_CLASS=0,IN_UNARY,IN_PAIRWISE,IN_LABELCOST,IN_EXPANSION} ;
  enum {OUT_LABELS=0, OUT_ENERGY, OUT_ENERGYAFTER} ;

  bool expansion = false;  

  /****************************************************************************
   * ERROR CHECKING
   ***************************************************************************/
  expansion = *mxGetPr(in[IN_EXPANSION]) > 0;
  if (nout > 3)
    mexErrMsgTxt("At most three outputs are allowed.");

  if(mxGetClassID(in[IN_CLASS]) != mxDOUBLE_CLASS)
    mexErrMsgTxt("Class must be a vector of class DOUBLE");
  if(mxGetM(in[IN_CLASS]) != 1 && mxGetN(in[IN_CLASS]) != 1)
    mexErrMsgTxt("Class must be a vector");

  if(mxGetClassID(in[IN_LABELCOST]) != mxSINGLE_CLASS)
    mexErrMsgTxt("Labelcost term must be a matrix of class SINGLE");

  int num_labels = mxGetM(in[IN_UNARY]);
  int num_pixels = mxGetN(in[IN_UNARY]);
  
  if(mxGetM(in[IN_CLASS]) != num_pixels && mxGetN(in[IN_CLASS]) != num_pixels)
    mexErrMsgTxt("Class size does not match cols in Unary term.");
  if(mxGetM(in[IN_LABELCOST]) != mxGetN(in[IN_LABELCOST]) || 
     mxGetM(in[IN_LABELCOST]) != num_labels)
    mexErrMsgTxt("Labelcost is not symmetric or does not match rows in Unary term.");

  if(mxGetM(in[IN_PAIRWISE]) != num_pixels || 
     mxGetN(in[IN_PAIRWISE]) != num_pixels)
    mexErrMsgTxt("Pairwise is not symmetric or does not match cols in Unary term.");


  /* Create output arrays */
  mwSize dims[2] = {1,0};
  out[OUT_ENERGY] = mxCreateNumericArray(1, dims, mxDOUBLE_CLASS, mxREAL);
  out[OUT_ENERGYAFTER] = mxCreateNumericArray(1, dims, mxDOUBLE_CLASS, mxREAL);
  double * energy = mxGetPr(out[OUT_ENERGY]);
  double * energy_after = mxGetPr(out[OUT_ENERGYAFTER]);

  mwSize pdims[2] = {num_pixels,1};
  out[OUT_LABELS] = mxCreateNumericArray(1,pdims,mxDOUBLE_CLASS, mxREAL);
  double * labels = mxGetPr(out[OUT_LABELS]);

  /* Data costs are nlabels rows x npixels cols */
  double * data = (double *)mxGetData(in[IN_UNARY]);
  double * classes = mxGetPr(in[IN_CLASS]);

  if (num_pixels == 1) { /* one pixel is a special case */
    *energy = data[(int)classes[0]];
    int minlabel = (int)classes[0];
    double mincost  = *energy;
    for(int i = 0; i < num_labels; i++)
      if(data[i] < mincost) {
        mincost = data[i];
        minlabel = i;
      }
    labels[0] = minlabel;
    *energy_after = mincost;
    return;
  }

  /****************************************************************************
   * Setup Graph and Perform Optimization
   ***************************************************************************/
  try {
    GCoptimizationGeneralGraph * gc = new GCoptimizationGeneralGraph(num_pixels, num_labels);
 
    for (int i = 0; i < num_pixels; i++) {
      gc->setLabel(i, (int)classes[i]);
    }
    
    gc->setDataCost(data);

	Images imgs;	
	int n_images = *((int*)mxGetData(in[5]));
 
 	imgs.images = new unsigned char* [n_images];
 	for (int i_img = 0; i_img < n_images; i_img++)
 		imgs.images[i_img] =  (unsigned char *)mxGetData(mxGetCell(in[6], i_img));	
 
	gc->setSmoothCost(smooth_cost, (void*)(&imgs));			

    /* Set spatialy varying part of the smoothness cost with the neighborhood 
     */
    mwSize total = 0;
    double * pair = mxGetPr(in[IN_PAIRWISE]);
    mwIndex * ir = mxGetIr(in[IN_PAIRWISE]);
    mwIndex * jc = mxGetJc(in[IN_PAIRWISE]);
    for (int col=0; col < num_pixels; col++) {
      mwIndex starting_row_index = jc[col];
      mwIndex stopping_row_index = jc[col+1];
      if (starting_row_index == stopping_row_index)
        continue;
      
      for (int idx = starting_row_index; idx < stopping_row_index; idx++) {
        /* only set bottom triangle of pairwise, per GC_README */
        if ( ir[idx] > col )
          gc->setNeighbors(ir[idx], col, pair[total]);
        total++;
      }
    }

    *energy = gc->compute_energy();

    /* From GC_README 
     * The expansion algorithm for energy minimization can be used whenever for
     * any 3 labels a,b,c V(a,a) + V(b,c) <= V(a,c)+V(b,a). In other words,
     * expansion algorithm can be used if the binary energy for the expansion
     * algorithm step is regular, using V. Kolmogorov's terminology.
     *
     * The swap algorithm for energy minimization can be used whenever for any 2
     * labels a,b V(a,a) + V(b,b) <= V(a,b)+V(b,a). In other words, swap
     * algorithm can be used if the binary energy for the swap algorithm step is
     * regular, using V. Kolmogorov's terminology.
     */

    if(expansion)
      gc->expansion();
    else
      gc->swap();

    *energy_after = gc->compute_energy();

    for (int i = 0; i < num_pixels; i++ )
      labels[i] = gc->whatLabel(i);

    delete gc;	
	delete[] imgs.images;
  }
  catch (GCException e) {
    mexErrMsgTxt(e.message);
  }

}
//   int smoothFn(int p1, int p2, int l1, int l2)
//   {
//      int length=(float)len[p1][p2];
//      cout<<" Length "<<length<<endl;
//      int diff=1+differ[p1][p2];
//      cout<<" Diff "<<diff<<endl;
//      float xx=((float)length/(float)diff)*100;
//      cout<<xx<<" Smoothfun "<<endl;
//      return xx;
//   }
    vector<int> GeneralGraph_DArraySArray(int width,int height,int num_pixels,int num_labels)
    {
        // int *result = new int[num_pixels];   // stores result of optimization
        cout<<width<<" "<<height<<" "<<num_pixels<<" "<<num_labels <<endl;
        vector<int>result(num_pixels);
        // first set up the array for data costs
        int *data = new int[num_pixels*num_labels];
        for ( int i = 0; i < num_pixels; i++ )
        {
            for (int l = 0; l < num_labels; l++ )
            {
                int temp=prob[i]*1000;
                if(l%2==0)
                {
                    data[i*num_labels+l] =temp;
                }
                else
                {
                    data[i*num_labels+l] =-temp;
                }
            }
        }
        // next set up the array for smooth costs
        int *smooth = new int[num_labels*num_labels];
        smooth[0]=0;
        smooth[1]=0;
        smooth[2]=0;
        smooth[3]=0;
        for(int p1=0; p1<num_pixels; p1++)
        {
            for(int p2=0; p2<num_pixels; p2++)
            {
                for ( int l1 = 0; l1 < num_labels; l1++ )
                {
                    for (int l2 = 0; l2 < num_labels; l2++ )
                    {
                        int length=len[p1][p2];
                        int differ=1+abs(prob[p1]-prob[p2]);
                        float val=((float)length/(float)differ);
                        smooth[l1+l2*num_labels] =smooth[l1+l2*num_labels]+val;
                    }
                }
            }
        }
        try
        {
            GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels,num_labels);
            gc->setDataCost(data);
            gc->setSmoothCost(smooth);

//          now set up a grid neighborhood system
//          first set up horizontal neighbors
            for (int x = 0; x < num_pixels; x++ )
            {
                for (int  y = 0; y < num_pixels; y++ )
                {
                    if(GR[x][y]==1 && x!=y)
                    {
                        gc->setNeighbors(x,y);
                    }
                }
            }
            printf("\nBefore optimization energy is %d",gc->compute_energy());
            gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
            printf("\nAfter optimization energy is %d",gc->compute_energy());

            for ( int  i = 0; i < num_pixels; i++ )
                result[i] = gc->whatLabel(i);

            delete gc;
            return result;
        }
        catch (GCException e)
        {
            e.Report();
        }
        delete [] smooth;
        delete [] data;
        vector<int>xx;
        return xx;
    }
コード例 #4
0
	int main(int argc, char **argv)
	{
		/** Argumetns. */
		std::string path	= argv[1];
		int ID_IMG_i		= std::stoi(argv[2]);
		int ID_IMG_e		= std::stoi(argv[3]);
		
		/**
		*	label = 0		// Reliabel ok
		*	label = 1		// No-Reliabel missing occluder
		*	label = 2		// No-Reliabel extra occluder
		*	label = 3		// No geometry
		*/
		int N_LABELS = 4;
		if (argc == 5) N_LABELS = std::stoi(argv[4]);		

		/** Big containers. */
		float *sdepth, *descEr;
		int	*neigh, *color;

		/** Set width and height */
		int w, h;
		sdepth = new float[2000*2000];			// TODO: find a better way to get w and h
		read_sdepth(path + Utils::sprint("/labeling_cues/%08d.depth", ID_IMG_i), sdepth, w, h);
		delete[] sdepth; 
				
		int N_IMGS		= ID_IMG_e - ID_IMG_i + 1;
		int N_NODES		= N_IMGS*w*h;					// N pixels
		int *result		= new int[N_NODES];				// Stores result of optimization
	
		sdepth	= new float[N_NODES];
		descEr	= new float[N_NODES * 2];
		neigh	= new int[N_NODES*N_NEIGHS];
		color	= new int[N_NODES];
	
		/**--------------------- Loading labeling cues ----------------------*/
		memset(sdepth, 0,	sizeof(float)*N_NODES);
		memset(descEr, 0,	sizeof(float)*N_NODES * 2);
		memset(neigh, 0,	sizeof(int)*N_NODES * N_NEIGHS);
		memset(color, 0,	sizeof(int)*N_NODES);

		for (int i = 0; i <N_IMGS; i++)
		{			
			int ID = ID_IMG_i + i;

			// Read cues
			std::string sdepth_name		= path + Utils::sprint("/labeling_cues/%08d.depth", ID);
			std::string conf_name		= path + Utils::sprint("/labeling_cues/%08d.conf", ID);
			std::string conf_neig		= path + Utils::sprint("/labeling_cues/%08d.neig", ID);
			std::string color_name		= path + Utils::sprint("/labeling_cues/%08d.color", ID);
			
			read_sdepth(sdepth_name, &sdepth[ i*h*w ], w, h);
			read_descErr(conf_name, &descEr[ i*h*w*2 ], w, h);
			read_neighbor(conf_neig, &neigh[ i*h*w*N_NEIGHS ], w, h);
			read_color(color_name, &color[ i*h*w ], w, h);
		}

		float mean_good, std_good, mean_bad, std_bad;
		std::string di_filename	= path + Utils::sprint("/labeling_cues/di_distribution.txt");			
		read_di_distr(di_filename, mean_good, std_good, mean_bad, std_bad	);
		
		/**-------------------------------------------------------------------*/

		try{
			GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph( N_NODES, N_LABELS);
		
			// set up the needed data to pass to cost functions
			Img_cues cues;
			cues.numLab = N_LABELS;
			cues.w = w;
			cues.h = h;
			cues.sdepth = sdepth;
			cues.desc_er = descEr;
			//cues.neigh = neigh;
			cues.color = color;
			cues.mean_good = mean_good;
			cues.std_good = std_good;
			cues.mean_bad = mean_bad;
			cues.std_bad = std_bad;

			if (N_LABELS == 4)
			{
				gc->setDataCost(&dataFn_4, &cues);							
				gc->setSmoothCost(&smoothFn_4, &cues);				// smoothness comes from function pointer
			}
			else
			{
				gc->setDataCost(&dataFn_3, &cues);				
				gc->setSmoothCost(&smoothFn_3, &cues);				// smoothness comes from function pointer
			}

			/** ********************* Set up a grid neighborhood system ********************* */

			// first set up horizontal neighbors
			for (int im_id = 0; im_id < N_IMGS; im_id++)
				for (int y = 0; y < h; y++ )
					for (int  x = 1; x < w; x++ )
						gc->setNeighbors(x + y*w + im_id*w*h, x - 1 + y*w + im_id*w*h);

			// next set up vertical neighbors
			for (int im_id = 0; im_id < N_IMGS; im_id++)
				for (int y = 1; y < h; y++ )
					for (int  x = 0; x < w; x++ )
						gc->setNeighbors(x + y*w + im_id*w*h, x + (y - 1)*w + im_id*w*h);
				
			// next set MV neighs
			for (int im_id = 0; im_id < N_IMGS; im_id++)
			{
				for (int y = STARTING_PADDING; y < h; y = y + MAX_PADDING)
				{
					for (int x = STARTING_PADDING; x < w; x = x + MAX_PADDING)
					{
						for (int layer_id = 0; layer_id < N_VIEWS_DAISY_ERR; layer_id ++)
						{
							int id_curr_px	= x + y*w + im_id*w*h;
							int id_mv_px	= neigh[x + y*w + im_id*w*h*N_NEIGHS + layer_id*w*h];
							id_mv_px		= id_mv_px - ID_IMG_i*w*h;									// Remap the node id according 
							if (id_mv_px < 0 || id_mv_px >= N_NODES) 
								break;	// No more neighbors								
									
							gc->setNeighbors(id_curr_px, id_mv_px);
			}}}}
			delete[] neigh;

			//--------------------------------------------------------------------------------------

			printf("\nBefore optimization energy is %d", gc->compute_energy());
			gc->expansion(3);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
			//gc->expansion(-1);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
			//gc->swap(2);
			//gc->swap(-1);
				
			printf("\nAfter optimization energy is %d", gc->compute_energy());

			for (int i = 0; i < N_NODES; i++)
				result[i] = gc->whatLabel(i);
			
			std::string labels_name = path + Utils::sprint("/labeling_cues/labels%u_from_%u_to_%u.bin", N_LABELS, ID_IMG_i, ID_IMG_e);
			write_labels(labels_name, result, N_LABELS, w, h, N_IMGS, N_NODES);

			delete gc;
		}
		catch (GCException e){
			e.Report();
		}

		delete[] result;
		delete[] sdepth;
		delete[] descEr;
		delete[] color;
		
		printf("\n  Finished %d (%d) clock per sec %d", clock() / CLOCKS_PER_SEC, clock(), CLOCKS_PER_SEC);
			
		return 0;
	}
コード例 #5
0
ファイル: GraphFitting.cpp プロジェクト: cxf476/uwo
long long CGraphFitting::fastFitting()
{
	int num_pixels=pImg3D->foreNum+1;
	int num_labels=getValidNum();
	////////////////////////////////////////////////////////////
	int *data = new int[num_pixels*num_labels];
	int curIndex=0;

	int slice=pImg3D->getS();
	int width=pImg3D->getW();
	int height=pImg3D->getH();

	for(int z = 0;z<slice;++z)
		for(int y=0;y<height;++y)
			for(int x=0;x<width;++x)
			{
				bool vessel=pImg3D->isVessel(x,y,z);
				if(vessel)
				{
					for (int l=0; l < num_labels; l++ )
					{
						if(l==num_labels-1)
							data[curIndex*num_labels+l]=5000;//INFINIT;
						else
							data[curIndex*num_labels+l]=models[l].compEnergy(x,y,z,*pImg3D);
					}
					curIndex++;
				}
			}
	for (int l=0; l < num_labels; l++ )
	{
		if(l==num_labels-1)
			data[curIndex*num_labels+l]=0;
		else
			data[curIndex*num_labels+l]=INFINIT;
	}

	//////////////////////////////////////////////////////////////////
	int *label = new int[num_labels];
	for(int k=0;k<num_labels;++k)		label[k]=LABELCOST;
	/////////////////////////////////////////////////////////////////
	int *smooth = new int[num_labels*num_labels];
	memset(smooth,0,sizeof(int)*num_labels*num_labels);
	for( int i=0; i<num_labels; i++ ) 
		for ( int j=0; j<num_labels; j++ ) 
			smooth[ i*num_labels+j ] = smooth[ i+j*num_labels ] =SMOOTHCOST* int(i!=j);
	long long energy=0;
	try{
		GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels,num_labels);
		gc->setDataCost(data);
		gc->setLabelCost(label);

#ifdef USE_SMOOTHCOST
		gc->setSmoothCost(smooth);
		for(int z = 0;z<slice;++z)
			for(int y=0;y<height;++y)
				for(int x=0;x<width;++x)
				{
					if(!pImg3D->isVessel(x,y,z))	continue;

					int numHoles=0;
					//////////////////////////////////////////////////////////////////////////////////
					if(inRange(Voxel(x+1,y,z)))//right neighbour
					{
						if(pImg3D->isVessel(x+1,y,z))	
							gc->setNeighbors(pImg3D->getRealPos(x,y,z),pImg3D->getRealPos(x+1,y,z));
						else
							++numHoles;
					}
					//////////////////////////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////
					if(inRange(Voxel(x,y+1,z)))//top neighbour
					{
						if(pImg3D->isVessel(x,y+1,z))	
							gc->setNeighbors(pImg3D->getRealPos(x,y,z),pImg3D->getRealPos(x,y+1,z));
						else
							++numHoles;
					}
					//////////////////////////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////
					if(inRange(Voxel(x,y,z+1)))//front neighbour
					{
						if(pImg3D->isVessel(x,y,z+1))	
							gc->setNeighbors(pImg3D->getRealPos(x,y,z),pImg3D->getRealPos(x,y,z+1));
						else
							++numHoles;
					}
					//////////////////////////////////////////////////////////////////////////////////
					if(inRange(Voxel(x-1,y,z))&& !pImg3D->isVessel(x-1,y,z) )	++numHoles;//left hole
					if(inRange(Voxel(x,y-1,z))&& !pImg3D->isVessel(x,y-1,z) )	++numHoles;//down hole
					if(inRange(Voxel(x,y,z-1))&& !pImg3D->isVessel(x,y,z-1) )	++numHoles;//back hole

					if(numHoles>0)
						gc->setNeighbors(pImg3D->getRealPos(x,y,z),num_pixels-1,numHoles);
				}
#endif
		//printf("\nBefore optimization energy is %d",gc->compute_energy());
		//std::cout<<"\nBefore optimization energy is "<<gc->compute_energy();
		energy=gc->compute_energy();
		gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
		//printf("\nAfter optimization energy is %d",gc->compute_energy());
		//std::cout<<"\nAfter optimization energy is "<<gc->compute_energy();
		gc->compute_energy();

		for ( int  i = 0; i < num_pixels; i++ )
		{
			int tag = gc->whatLabel(i);
			models[tag].addSupport();
			pLabels[i]=tag;
			//if(result[i]!=num_labels-1)	printf("%d ",result[i]);
		}
		////////////////////////////////////////////////////////////////////////////////////
		for(int i=0;i<num_labels;++i)
		{
			int sp=models[i].getSupport();
			models[i].setValid(sp>0);
			if(i==num_labels-1)//last model ,must be valid
				models[i].setValid(true);
		}
		///////////////////////////////////////////////
		for(int i=0;i<num_labels-1;++i)
		{
			if(models[i].isValid())
			{
				fitLine(i,gc);
			}
		}
		delete gc;
	}
	catch (GCException e){
		e.Report();
	}

	delete [] smooth;
	delete []label;
	delete [] data;
	return energy;
}
コード例 #6
0
ファイル: mex_gc.cpp プロジェクト: ppletscher/mpe_inference
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Check for proper number of arguments
    if ( (nrhs < NR_IN) || (nrhs > NR_IN + NR_IN_OPT) || \
            (nlhs < NR_OUT) || (nlhs > NR_OUT + NR_OUT_OPT) ) {
        mexErrMsgTxt("Wrong number of arguments.");
    }

    // dimensionality checks
    size_t num_nodes = mxGetN(POTENTIAL_UNARY_IN);
    num_edges = mxGetN(EDGES_IN);
    if ( mxGetM(POTENTIAL_UNARY_IN) != 2 ) {
        mexErrMsgTxt("Only support binary problems!");
    }
    if ( mxGetM(EDGES_IN) != 2 ) {
        mexErrMsgTxt("Edges array has wrong size!");
    }
    if ( (mxGetM(POTENTIAL_PAIR_IN) != 4) || (mxGetN(POTENTIAL_PAIR_IN) != num_edges) ) {
        mexErrMsgTxt("Inconsistent size of the pairwise potentials.");
    }

    // read the inputs
    double* potential_unary = mxGetPr(POTENTIAL_UNARY_IN);
    double* edges = mxGetPr(EDGES_IN); // TODO: convert to int32? Or require it to be int32??
    potential_pair = mxGetPr(POTENTIAL_PAIR_IN);
            
    // unaries and function pointer for the pairwise
    GCoptimizationGeneralGraph* gco = new GCoptimizationGeneralGraph(num_nodes, 2);
    gco->setDataCost(potential_unary);
    gco->setSmoothCost(&smoothCost);

    // an edge lookup table for the pairwise potentials (for within smoothcost)
    std::vector< std::map<int,int> > edge_lookup;
    edge_lookup.resize(num_nodes);
    edge_lookup_ptr = &edge_lookup;
    for (int i = 0; i < (int)(num_edges); i++) {
        int s = int(edges[2*i])-1;
        int d = int(edges[2*i+1])-1;

        gco->setNeighbors(s, d);
        edge_lookup[s].insert(std::make_pair(d,i));
        edge_lookup[d].insert(std::make_pair(s,i));

        // submodularity check
        if (potential_pair[i*4]+potential_pair[i*4+3] > potential_pair[i*4+1]+potential_pair[i*4+2]) {
            mexErrMsgTxt("The energy is not submodular!");
        }
    }

    // solve the graphcut problem
    double energy = gco->expansion(1);

    // return the labeling and the energy
    double *ptr;
    if (nlhs > 1) {
        ENERGY_OUT = mxCreateDoubleMatrix(1, 1, mxREAL);
        ptr = mxGetPr(ENERGY_OUT);
        *ptr = energy;
    }

    LABEL_OUT = mxCreateDoubleMatrix(1, num_nodes, mxREAL);
    ptr = mxGetPr(LABEL_OUT);    
    for(size_t i = 0; i < num_nodes; i++) {
        ptr[i] = gco->whatLabel(i);
    }

    delete gco;
}