//Test the quantization, connected components on different color layers, and output the descriptor
        private void OutputPatterns_Click(object sender, RoutedEventArgs e)
        {
            //Create output directories
            Directory.CreateDirectory(outdir + "\\cc\\");
            Directory.CreateDirectory(outdir + "\\quantized\\");
            Directory.CreateDirectory(outdir + "\\mesh\\");

            //read in the patterns and save out their layers
            String[]           files    = System.IO.Directory.GetFiles(System.IO.Path.Combine(imagedir));
            List <PatternItem> patterns = PatternIO.GetPatterns(imagedir);

            foreach (PatternItem p in patterns)
            {
                Bitmap image    = new Bitmap(p.FullPath);
                String basename = p.Name;

                //TODO: sometimes keys are not found in patterns.csv...will need to look into recovering missing info. For now, just ignore those patterns
                if (!palettes.ContainsKey(basename))
                {
                    continue;
                }

                PaletteData palette = palettes[basename];

                ColorTemplate template = new ColorTemplate(image, palette);

                //output the template descriptor
                SegmentMesh mesh = new SegmentMesh(template);
                PatternIO.SaveMesh(mesh, p, Path.Combine(outdir, "mesh"));

                if (outputDebugImages)
                {
                    Bitmap result = template.DebugQuantization();
                    PatternIO.SavePattern(result, p, Path.Combine(outdir, "quantized"), "_quantized");
                    PatternIO.SavePattern(result, p, Path.Combine(outdir, "quantized"), "_original");

                    //save the connected components
                    UnionFind <Color> uf = new UnionFind <Color>((a, b) => (a.GetHashCode() == b.GetHashCode()));
                    Color[,] resultArray = Util.BitmapToArray(result);
                    int[,] cc            = uf.ConnectedComponentsNoiseRemoval(resultArray);

                    int numColors = palette.colors.Count();
                    for (int i = 0; i < numColors; i++)
                    {
                        Bitmap debug = uf.RenderComponents(cc, resultArray, palette.colors[i]);
                        PatternIO.SavePattern(debug, p, Path.Combine(outdir, "cc"), "_" + i);
                        debug.Dispose();
                    }
                    result.Dispose();
                }
                image.Dispose();
            }
        }
        public SegmentMesh(ColorTemplate template)
        {
            int numGroups = template.NumSlots();

            imageWidth  = template.Width();
            imageHeight = template.Height();

            groups   = new List <SegmentGroup>();
            segments = new List <Segment>();

            //now populate the segments and segment groups
            //filter out groups that have no members (due to quantization)
            Dictionary <int, int> slotToGroup = new Dictionary <int, int>();

            for (int i = 0; i < numGroups; i++)
            {
                if (template.PixelsInSlot(i) > 0)
                {
                    slotToGroup.Add(i, groups.Count());
                    groups.Add(new SegmentGroup(template.OriginalSlotColor(i)));
                }
            }

            UnionFind <Color> uf    = new UnionFind <Color>((a, b) => (a.GetHashCode() == b.GetHashCode()));
            Bitmap            image = template.DebugQuantization();

            assignments = uf.ConnectedComponentsNoiseRemoval(Util.BitmapToArray(image));


            Dictionary <int, Segment> idToSegment            = new Dictionary <int, Segment>();
            int totalAdjacencyPerimeter                      = 0;
            Dictionary <int, HashSet <Point> > idToPerimeter = new Dictionary <int, HashSet <Point> >();

            //populate segments
            int width  = image.Width;
            int height = image.Height;

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    int id = assignments[i, j];
                    if (!idToSegment.ContainsKey(id))
                    {
                        idToSegment.Add(id, new Segment(id));
                        idToPerimeter.Add(id, new HashSet <Point>());
                    }

                    idToSegment[id].points.Add(new Point(i, j));
                    idToSegment[id].groupId = slotToGroup[template.GetSlotId(i, j)];

                    //look for 8-neighbor adjacencies, 2 pixels away
                    //TODO: measure adjacency strength and filter?
                    for (int dx = -2; dx <= 2; dx++)
                    {
                        for (int dy = -2; dy <= 2; dy++)
                        {
                            int x = i + dx;
                            int y = j + dy;
                            if (x >= 0 && x < width && y >= 0 && y < height)
                            {
                                int nid = assignments[x, y];
                                if (nid != id)
                                {
                                    idToSegment[id].adjacencies.Add(nid);

                                    //keep track of the total perimeter, and individual segment perimeters
                                    //don't double count the same point for each segment
                                    if (!idToPerimeter[id].Contains(new Point(x, y)))
                                    {
                                        idToPerimeter[id].Add(new Point(x, y));
                                        totalAdjacencyPerimeter++;

                                        //keep track of the adjacecy strength per segment
                                        if (!idToSegment[id].adjacencyStrength.ContainsKey(nid))
                                        {
                                            idToSegment[id].adjacencyStrength.Add(nid, 0);
                                        }
                                        idToSegment[id].adjacencyStrength[nid]++;
                                    }
                                    else
                                    {
                                        Console.WriteLine("Point already counted");
                                    }
                                }
                            }
                            else
                            {
                                //might as well be consistent here, and take into account the borders of the image when determining
                                //enclosure. We don't need to do this for the totalAdjacencyPerimeter, because that is just a normalization
                                //for the adjacency strengths of segments within the image
                                if (!idToPerimeter[id].Contains(new Point(x, y)))
                                {
                                    idToPerimeter[id].Add(new Point(x, y));
                                }
                            }
                        }
                    }
                }
            }

            //finalize segment list and adjacency list
            Dictionary <int, int> idToIdx = new Dictionary <int, int>();

            foreach (int id in idToSegment.Keys)
            {
                segments.Add(idToSegment[id]);
                idToIdx.Add(id, segments.Count() - 1);
            }

            //finalize adjacencies
            for (int i = 0; i < segments.Count(); i++)
            {
                SortedSet <int> renamedAdj = new SortedSet <int>();
                foreach (int a in segments[i].adjacencies)
                {
                    renamedAdj.Add(idToIdx[a]);
                }
                segments[i].adjacencies = renamedAdj;

                //finalize adjacency strengths
                int sid = assignments[segments[i].points.First().X, segments[i].points.First().Y];

                Dictionary <int, double> renamedAdjStrength = new Dictionary <int, double>();
                foreach (int nid in segments[i].adjacencyStrength.Keys)
                {
                    double pixelsAdj = segments[i].adjacencyStrength[nid];
                    renamedAdjStrength.Add(idToIdx[nid], pixelsAdj / totalAdjacencyPerimeter);
                    segments[i].enclosureStrength.Add(idToIdx[nid], new Tuple <double, double>(pixelsAdj / idToPerimeter[sid].Count(), pixelsAdj / idToPerimeter[nid].Count()));
                }
                segments[i].adjacencyStrength = renamedAdjStrength;
            }

            //finalize groups
            for (int i = 0; i < segments.Count(); i++)
            {
                int groupId = segments[i].groupId;
                groups[groupId].members.Add(i);
            }

            //finalize segment list

            ClassifySegments();

            foreach (Segment s in segments)
            {
                ComputeFeatures(s);
            }

            foreach (SegmentGroup g in groups)
            {
                ComputeFeatures(g);
            }
        }
        public SegmentMesh(ColorTemplate template)
        {
            int numGroups = template.NumSlots();
            imageWidth = template.Width();
            imageHeight = template.Height();

            groups = new List<SegmentGroup>();
            segments = new List<Segment>();

            //now populate the segments and segment groups
            //filter out groups that have no members (due to quantization)
            Dictionary<int, int> slotToGroup = new Dictionary<int, int>();
            for (int i = 0; i < numGroups; i++)
            {
                if (template.PixelsInSlot(i) > 0)
                {
                    slotToGroup.Add(i, groups.Count());
                    groups.Add(new SegmentGroup(template.OriginalSlotColor(i)));
                }
            }

            UnionFind<Color> uf = new UnionFind<Color>((a, b) => (a.GetHashCode() == b.GetHashCode()));
            Bitmap image = template.DebugQuantization();
            assignments = uf.ConnectedComponentsNoiseRemoval(Util.BitmapToArray(image));

            Dictionary<int, Segment> idToSegment = new Dictionary<int, Segment>();
            int totalAdjacencyPerimeter = 0;
            Dictionary<int, HashSet<Point>> idToPerimeter = new Dictionary<int, HashSet<Point>>();

            //populate segments
            int width = image.Width;
            int height = image.Height;
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    int id = assignments[i, j];
                    if (!idToSegment.ContainsKey(id))
                    {
                        idToSegment.Add(id, new Segment(id));
                        idToPerimeter.Add(id, new HashSet<Point>());
                    }

                    idToSegment[id].points.Add(new Point(i, j));
                    idToSegment[id].groupId = slotToGroup[template.GetSlotId(i, j)];

                    //look for 8-neighbor adjacencies, 2 pixels away
                    //TODO: measure adjacency strength and filter?
                    for (int dx = -2; dx <= 2; dx++)
                    {
                        for (int dy = -2; dy <= 2; dy++)
                        {
                            int x = i + dx;
                            int y = j + dy;
                            if (x >= 0 && x < width && y >= 0 && y < height)
                            {
                                int nid = assignments[x, y];
                                if (nid != id)
                                {
                                    idToSegment[id].adjacencies.Add(nid);

                                    //keep track of the total perimeter, and individual segment perimeters
                                    //don't double count the same point for each segment
                                    if (!idToPerimeter[id].Contains(new Point(x, y)))
                                    {
                                        idToPerimeter[id].Add(new Point(x, y));
                                        totalAdjacencyPerimeter++;

                                        //keep track of the adjacecy strength per segment
                                        if (!idToSegment[id].adjacencyStrength.ContainsKey(nid))
                                            idToSegment[id].adjacencyStrength.Add(nid, 0);
                                        idToSegment[id].adjacencyStrength[nid]++;
                                    }
                                    else
                                    {
                                        Console.WriteLine("Point already counted");
                                    }
                                }
                            }
                            else
                            {
                                //might as well be consistent here, and take into account the borders of the image when determining
                                //enclosure. We don't need to do this for the totalAdjacencyPerimeter, because that is just a normalization
                                //for the adjacency strengths of segments within the image
                                if (!idToPerimeter[id].Contains(new Point(x,y)))
                                {
                                    idToPerimeter[id].Add(new Point(x,y));
                                }
                            }
                        }
                    }
                }
            }

            //finalize segment list and adjacency list
            Dictionary<int, int> idToIdx = new Dictionary<int, int>();
            foreach (int id in idToSegment.Keys)
            {
                segments.Add(idToSegment[id]);
                idToIdx.Add(id, segments.Count() - 1);
            }

            //finalize adjacencies
            for (int i = 0; i < segments.Count(); i++)
            {
                SortedSet<int> renamedAdj = new SortedSet<int>();
                foreach (int a in segments[i].adjacencies)
                    renamedAdj.Add(idToIdx[a]);
                segments[i].adjacencies = renamedAdj;

                //finalize adjacency strengths
                int sid = assignments[segments[i].points.First().X, segments[i].points.First().Y];

                Dictionary<int, double> renamedAdjStrength = new Dictionary<int, double>();
                foreach (int nid in segments[i].adjacencyStrength.Keys)
                {
                    double pixelsAdj = segments[i].adjacencyStrength[nid];
                    renamedAdjStrength.Add(idToIdx[nid], pixelsAdj / totalAdjacencyPerimeter);
                    segments[i].enclosureStrength.Add(idToIdx[nid], new Tuple<double, double>(pixelsAdj / idToPerimeter[sid].Count(), pixelsAdj / idToPerimeter[nid].Count()));
                }
                segments[i].adjacencyStrength = renamedAdjStrength;

            }

            //finalize groups
            for (int i = 0; i < segments.Count(); i++)
            {
                int groupId = segments[i].groupId;
                groups[groupId].members.Add(i);
            }

            //finalize segment list

            ClassifySegments();

            foreach (Segment s in segments)
            {
                ComputeFeatures(s);
            }

            foreach (SegmentGroup g in groups)
            {
                ComputeFeatures(g);
            }
        }
        //Test the quantization, connected components on different color layers, and output the descriptor
        private void OutputPatterns_Click(object sender, RoutedEventArgs e)
        {
            //Create output directories
            Directory.CreateDirectory(outdir + "\\cc\\");
            Directory.CreateDirectory(outdir + "\\quantized\\");
            Directory.CreateDirectory(outdir + "\\mesh\\");

            //read in the patterns and save out their layers
            String[] files = System.IO.Directory.GetFiles(System.IO.Path.Combine(imagedir));
            List<PatternItem> patterns = PatternIO.GetPatterns(imagedir);

            foreach (PatternItem p in patterns)
            {
                Bitmap image= new Bitmap(p.FullPath);
                String basename = p.Name;

                //TODO: sometimes keys are not found in patterns.csv...will need to look into recovering missing info. For now, just ignore those patterns
                if (!palettes.ContainsKey(basename))
                    continue;

                PaletteData palette = palettes[basename];

                ColorTemplate template = new ColorTemplate(image, palette);

                //output the template descriptor
                SegmentMesh mesh = new SegmentMesh(template);
                PatternIO.SaveMesh(mesh, p, Path.Combine(outdir, "mesh"));

                if (outputDebugImages)
                {
                    Bitmap result = template.DebugQuantization();
                    PatternIO.SavePattern(result, p, Path.Combine(outdir, "quantized"), "_quantized");
                    PatternIO.SavePattern(result, p, Path.Combine(outdir, "quantized"), "_original");

                    //save the connected components
                    UnionFind<Color> uf = new UnionFind<Color>((a, b) => (a.GetHashCode() == b.GetHashCode()));
                    Color[,] resultArray = Util.BitmapToArray(result);
                    int[,] cc = uf.ConnectedComponentsNoiseRemoval(resultArray);

                    int numColors = palette.colors.Count();
                    for (int i = 0; i < numColors; i++)
                    {
                        Bitmap debug = uf.RenderComponents(cc, resultArray, palette.colors[i]);
                        PatternIO.SavePattern(debug, p, Path.Combine(outdir, "cc"), "_" + i);
                        debug.Dispose();
                    }
                    result.Dispose();
                }
                image.Dispose();

            }
        }