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); } }