//Performs MST based segmentation as described by Pedro and Hutt
        //k - theshold. larger values make fewer components
        //min-size - smallest size of a component
        int Segment_Image(double k, int minsize, IReadAsDoubleGrid src,
																						 IReadAsDoubleGrid dst, 
																							EdgeCostFunction f)
        {
            int width = src.Width;
            int height = src.Height;
            this.edgeCostFunction = f;
            ds.Clear();
            clusters.Clear();
            for (int i = 0; i < width; i++)
                setmap[i] = -1;

            //build the graph we are going to segment over...
            //this is an 8 connected graph (carindal and subcardinal 1 neighbors)

            int numEdges = 0;
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (x < width - 1) //right neighbor
                        graph[numEdges++] = new Edge(y * width + x, y * width + (x + 1), edgeCostFunction(src, x, y, x + 1, y));
                    if (y > 0) //up neighbor
                        graph[numEdges++] = new Edge(y * width + x, (y - 1) * width + x, edgeCostFunction(src, x, y, x, y - 1));
                    if ((x < width - 1) && (y > 0)) //up and right neibor
                        graph[numEdges++] = new Edge(y * width + x, (y - 1) * width + (x + 1), edgeCostFunction(src, x, y, x + 1, y - 1));
                    if ((x < width - 1) && (y < height - 1)) //down and right neighbor
                        graph[numEdges++] = new Edge(y * width + x, (y + 1) * width + (x + 1), edgeCostFunction(src, x, y, x + 1, y + 1));
                }
            }

            //now sort the edges
            graph.Sort();

            //ok graph is built - do some segmentation!

            //initalize the tresholds to their initial values (see discussion in loop)
            for (int i = 0; i < width * height; i++)
                thresholds[i] = ThresholdFunction(k, 1);

            //traverse the graph in increasing edge weight order...
            //the goal here is to try to assemble cohesive sets using the
            //union.
            for (int i = 0; i < numEdges; i++)
            {
                //the a node is the current pixel, the b node is the neighbor
                int aID = ds.FindSetRoot(graph[i].aNode);
                int bID = ds.FindSetRoot(graph[i].bNode);

                //if these are two distinct clusters, can we merge them?
                if (aID != bID)
                {
                    //merge if both the aID and bID thesholds are bigger than this current elements weight
                    if ((graph[i].weight <= thresholds[aID]) && (graph[i].weight <= thresholds[bID]))
                    {
                        //join the clusters
                        ds.Union(aID, bID);

                        //update the theshold of the newly formed cluster
                        aID = ds.FindSetRoot(aID); //i think this can be optimized...

                        //normalize the added theshold weight by the size of this new bigger cluster
                        //from the paper: this threshold function is a function of the size of the component.
                        // this ends up making small components require stronger evidence for a boundary
                        thresholds[aID] = graph[i].weight + ThresholdFunction(k, ds.NumElements(aID));
                    }
                }

            }

            // post process small components
            for (int i = 0; i < numEdges; i++)
            {
                int aID = ds.FindSetRoot(graph[i].aNode);
                int bID = ds.FindSetRoot(graph[i].bNode);
                if ((aID != bID) && ((ds.NumElements(aID) < minsize) || (ds.NumElements(bID) < minsize)))
                    ds.Union(aID, bID);
            }

            int sets = ds.NumSets();
            clusters = new List<List<int>>(sets);

            int mapIndex = 0;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    int point = y * width + x;
                    int comp = ds.FindSetRoot(point);

                    //try to get the setmap...
                    //first check is this a root?
                    if (setmap[comp] == -1)
                    {
                        setmap[comp] = mapIndex;

                        clusters.Add(new List<int>(ds.NumElements(comp)));
                        clusters[mapIndex].Add(point);
                        mapIndex++;
                    }
                    else
                    {
                        clusters[setmap[comp]].Add(point);
                    }
                }
            }

            return sets;
        }
        //Performs MST based segmentation as described by Pedro and Hutt
        //k - theshold. larger values make fewer components
        //min-size - smallest size of a component
        int Segment_Image(double k, int minsize, IReadAsDoubleGrid src,
                          IReadAsDoubleGrid dst,
                          EdgeCostFunction f)
        {
            int width  = src.Width;
            int height = src.Height;

            this.edgeCostFunction = f;
            ds.Clear();
            clusters.Clear();
            for (int i = 0; i < width; i++)
            {
                setmap[i] = -1;
            }

            //build the graph we are going to segment over...
            //this is an 8 connected graph (carindal and subcardinal 1 neighbors)

            int numEdges = 0;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (x < width - 1)                     //right neighbor
                    {
                        graph[numEdges++] = new Edge(y * width + x, y * width + (x + 1), edgeCostFunction(src, x, y, x + 1, y));
                    }
                    if (y > 0)                     //up neighbor
                    {
                        graph[numEdges++] = new Edge(y * width + x, (y - 1) * width + x, edgeCostFunction(src, x, y, x, y - 1));
                    }
                    if ((x < width - 1) && (y > 0))                     //up and right neibor
                    {
                        graph[numEdges++] = new Edge(y * width + x, (y - 1) * width + (x + 1), edgeCostFunction(src, x, y, x + 1, y - 1));
                    }
                    if ((x < width - 1) && (y < height - 1))                     //down and right neighbor
                    {
                        graph[numEdges++] = new Edge(y * width + x, (y + 1) * width + (x + 1), edgeCostFunction(src, x, y, x + 1, y + 1));
                    }
                }
            }

            //now sort the edges
            graph.Sort();


            //ok graph is built - do some segmentation!


            //initalize the tresholds to their initial values (see discussion in loop)
            for (int i = 0; i < width * height; i++)
            {
                thresholds[i] = ThresholdFunction(k, 1);
            }

            //traverse the graph in increasing edge weight order...
            //the goal here is to try to assemble cohesive sets using the
            //union.
            for (int i = 0; i < numEdges; i++)
            {
                //the a node is the current pixel, the b node is the neighbor
                int aID = ds.FindSetRoot(graph[i].aNode);
                int bID = ds.FindSetRoot(graph[i].bNode);

                //if these are two distinct clusters, can we merge them?
                if (aID != bID)
                {
                    //merge if both the aID and bID thesholds are bigger than this current elements weight
                    if ((graph[i].weight <= thresholds[aID]) && (graph[i].weight <= thresholds[bID]))
                    {
                        //join the clusters
                        ds.Union(aID, bID);

                        //update the theshold of the newly formed cluster
                        aID = ds.FindSetRoot(aID);                         //i think this can be optimized...

                        //normalize the added theshold weight by the size of this new bigger cluster
                        //from the paper: this threshold function is a function of the size of the component.
                        // this ends up making small components require stronger evidence for a boundary
                        thresholds[aID] = graph[i].weight + ThresholdFunction(k, ds.NumElements(aID));
                    }
                }
            }


            // post process small components
            for (int i = 0; i < numEdges; i++)
            {
                int aID = ds.FindSetRoot(graph[i].aNode);
                int bID = ds.FindSetRoot(graph[i].bNode);
                if ((aID != bID) && ((ds.NumElements(aID) < minsize) || (ds.NumElements(bID) < minsize)))
                {
                    ds.Union(aID, bID);
                }
            }



            int sets = ds.NumSets();

            clusters = new List <List <int> >(sets);

            int mapIndex = 0;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    int point = y * width + x;
                    int comp  = ds.FindSetRoot(point);

                    //try to get the setmap...
                    //first check is this a root?
                    if (setmap[comp] == -1)
                    {
                        setmap[comp] = mapIndex;

                        clusters.Add(new List <int>(ds.NumElements(comp)));
                        clusters[mapIndex].Add(point);
                        mapIndex++;
                    }
                    else
                    {
                        clusters[setmap[comp]].Add(point);
                    }
                }
            }


            return(sets);
        }