public override HashSet<ChunkContainer> GetChunks(LocationPool locationPool) { HashSet<ChunkContainer> result = new HashSet<ChunkContainer>(); if (Locations.Count == 0) { return result; } if (IsRectangle()) { TransparentRectangleChunk rectangleChunk = new TransparentRectangleChunk(); rectangleChunk.Origin = BoundingBox.UpperLeft; rectangleChunk.Width = BoundingBox.Width(); rectangleChunk.Height = BoundingBox.Height(); TransparentRectangleChunkContainer container = new TransparentRectangleChunkContainer(); container.Chunk = rectangleChunk; container.Locations = Locations; result.Add(container); return result; } TransparentBitPlaneChunk transparentChunk = new TransparentBitPlaneChunk(); transparentChunk.Origin = BoundingBox.UpperLeft; transparentChunk.Width = BoundingBox.Width(); transparentChunk.Height = BoundingBox.Height(); transparentChunk.Initialize(); TransparentBitPlaneChunkContainer transparentChunkContainer = new TransparentBitPlaneChunkContainer(); transparentChunkContainer.Chunk = transparentChunk; transparentChunkContainer.Locations = Locations; foreach (Location location in Locations) { transparentChunk.SetColor(location.Point.X, location.Point.Y); } result.Add(transparentChunkContainer); return result; }
/// <summary> /// Region growing to encode the source image data. /// </summary> /// <param name="locationPool"></param> /// <param name="maximumDistance"></param> /// <param name="type"></param> /// <returns></returns> private static HashSet<Region> Process(LocationPool locationPool, double maximumDistance, RegionType type) { HashSet<Region> result = new HashSet<Region>(); List<Location> todoList = new List<Location>(); //let's process pixels into regions Region region = null; HashSet<Location> alreadyChecked = new HashSet<Location>(); while (!locationPool.Empty()) { alreadyChecked.Clear(); Location seed = locationPool.RandomLocation(); //Console.WriteLine("Have seed " + seed); if (type == RegionType.MonoRegion) { region = new MonoRegion(); } else if (type == RegionType.MultiColorRegion) { MultiColorRegion multiColorRegion = new MultiColorRegion(maximumDistance); region = multiColorRegion; } region.Add(seed); region.Origin = seed.Point; seed.Region = region; locationPool.SetMarked(seed); alreadyChecked.Add(seed); AddNeighbors(seed, todoList, alreadyChecked); todoList.Sort((x, y) => (int)(SxzColor.GetColorDistance(seed.Color, x.Color) - SxzColor.GetColorDistance(seed.Color, y.Color))); int sortCounter = 0; //inner loop while (todoList.Count != 0) { //Console.WriteLine("Unmarked total " + locationPool.Unmarked.Count + " and todolist total " + todoList.Count); seed = todoList[0]; todoList.RemoveAt(0); sortCounter++; if (seed.Marked) { throw new Exception("Location already marked!"); } if (!region.IsValid(seed)) { //we can process non-adjacent pixels by adding neighbors here and sorting before returning but limit the distance from an already //validated location continue; } //Console.WriteLine("Parsed pixel " + seed); //we have a winner! region.Add(seed); locationPool.SetMarked(seed); AddNeighbors(seed, todoList, alreadyChecked); //if (todoList.Count < 1000) if (todoList.Count < 1000 || sortCounter > 1000) { //let's limit the number to be sorted for performance sake todoList.Sort((x1, y1) => (int)(SxzColor.GetColorDistance(seed.Color, x1.Color) - SxzColor.GetColorDistance(seed.Color, y1.Color))); sortCounter = 0; } } result.Add(region); } return result; }
public Container Parse(string filename, SxzColor backgroundColor, bool useMostCommonColor, bool parseBackground, BackgroundType backgroundType, double bitsPerPixel, double maximumDistance) { int width = 0; int height = 0; //now we can act on our pixel byte array to get pixels out //and also histogram because it is informative if nothing else LocationPool locationPool = null; Dictionary<SxzColor, int> histogram = new Dictionary<SxzColor, int>(); TransparentRegion transparentRegion = new TransparentRegion(); //Parse all the pixels into the locationpool, histogram and remove the fully transparent pixels into the transparentregion using (System.Drawing.Bitmap bitMap = new System.Drawing.Bitmap(filename)) { width = bitMap.Width; height = bitMap.Height; locationPool = new LocationPool(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { System.Drawing.Color pixel = bitMap.GetPixel(x, y); Location location = new Location(); location.Color = new SxzColor(pixel.R, pixel.G, pixel.B); location.Point.X = x; location.Point.Y = y; //Don't put transparent colors into the histogram if (pixel.A == 0) { transparentRegion.Add(location); locationPool.SetLocation(location, x, y); locationPool.SetMarked(location); continue; } if (histogram.ContainsKey(location.Color)) { int count = histogram[location.Color]; histogram[location.Color] = count + 1; } else { histogram.Add(location.Color, 1); } locationPool.SetLocation(location, x, y); } } } Console.WriteLine("Total pixel count " + (width * height)); Console.WriteLine("Total transparent pixel count " + transparentRegion.Locations.Count); //Remove all the transparent locations //foreach (Location location in transparentRegion.Locations) //{ // locationPool.SetMarked(location); //} //set the neighbors after removing transparent pixels to save time since those aren't needed anymore locationPool.SetNeighbors(); Console.WriteLine("Done removing transparent pixels"); //Sort the colors by frequency List<KeyValuePair<SxzColor, int>> colorList = histogram.ToList(); colorList.Sort((first, second) => { return first.Value == second.Value ? (int)(SxzColor.GetColorDistance(second.Key, new SxzColor(0, 0, 0)) - SxzColor.GetColorDistance(first.Key, new SxzColor(0, 0, 0))) : second.Value.CompareTo(first.Value); }); //Find the most commonly used color SxzColor mostCommonColor = colorList[0].Key; if (useMostCommonColor) { backgroundColor = mostCommonColor; } //always start with a palette, register empty palette and fill as we go Console.WriteLine("Processing the most common color"); DefaultPaletteChunk defaultPaletteChunk = new DefaultPaletteChunk(); Palette defaultPalette = new Palette(defaultPaletteChunk); //Initialization overhead List<PaletteContainer> paletteContainers = new List<PaletteContainer>(); PaletteContainer initialPaletteContainer = new PaletteContainer(); initialPaletteContainer.Initial = true; initialPaletteContainer.Palette = defaultPalette; paletteContainers.Add(initialPaletteContainer); HashSet<Location> locations = locationPool.GetByColor(backgroundColor); if (parseBackground && locations.Count > 0) { if (backgroundType == BackgroundType.Background) { Console.WriteLine("Creating background chunk"); BackgroundChunk backgroundChunk = new BackgroundChunk(); BackgroundChunkContainer backgroundChunkContainer = new BackgroundChunkContainer(); backgroundChunkContainer.Chunk = backgroundChunk; backgroundChunkContainer.Color = backgroundColor; //pull out all the pixels with the most common color and throw them into a backgroundchunk if (!initialPaletteContainer.Contains(backgroundColor)) { Console.WriteLine("Background chunk in it's own palette"); //not in default palette so create a new palette Palette palette = new Palette(); palette.Add(backgroundColor); PaletteContainer paletteContainer = new PaletteContainer(); paletteContainer.Palette = palette; paletteContainers.Add(paletteContainer); paletteContainer.Add(backgroundChunkContainer); backgroundChunk.Palette = palette.GetPaletteChunk(); } else { backgroundChunk.Palette = defaultPaletteChunk; initialPaletteContainer.Add(backgroundChunkContainer); } //AddChunk(paletteContainers, backgroundContainer, mostCommonColor); backgroundChunkContainer.Locations = locations; } else if (backgroundType == BackgroundType.Rectangle) { MonoRectangleChunk rectangleChunk = new MonoRectangleChunk(); rectangleChunk.Origin = new SxzPoint(0, 0); rectangleChunk.Width = width; rectangleChunk.Height = height; MonoRectangleChunkContainer rectangleContainer = new MonoRectangleChunkContainer(); rectangleContainer.Color = backgroundColor; rectangleContainer.Chunk = rectangleChunk; if (!initialPaletteContainer.Contains(backgroundColor)) { Console.WriteLine("Background chunk in it's own palette"); //not in default palette so create a new palette Palette palette = new Palette(); palette.Add(backgroundColor); PaletteContainer paletteContainer = new PaletteContainer(); paletteContainer.Palette = palette; paletteContainers.Add(paletteContainer); paletteContainer.Add(rectangleContainer); rectangleChunk.Palette = palette.GetPaletteChunk(); } else { rectangleChunk.Palette = defaultPaletteChunk; initialPaletteContainer.Add(rectangleContainer); } //AddChunk(paletteContainers, backgroundContainer, mostCommonColor); rectangleContainer.Locations = locations; } //Remove the pixels with the background color from the location pool foreach (Location location in locations) { locationPool.SetMarked(location); } } Console.WriteLine("Done processing the most common color"); Console.WriteLine("Parsing monocolor regions"); //Pull out all regions with the same color in mono regions that were not pulled by the most common color if any HashSet<Region> monoRegions = Process(locationPool, maximumDistance, RegionType.MonoRegion); Console.WriteLine("Have mono region count " + monoRegions.Count); foreach (Region region in monoRegions) { HashSet<ChunkContainer> potentialContainers = region.GetChunks(locationPool); PaletteContainer paletteContainer = GetPaletteContainer(paletteContainers, region.GetColors()); foreach (ChunkContainer chunkContainer in potentialContainers) { //filter out chunks that are not storage sufficient, putting the unused locations //back into the location pool //... if (!chunkContainer.IsValid(bitsPerPixel)) { PrintTossedChunk(chunkContainer); foreach (Location location in chunkContainer.Locations) { locationPool.Unmark(location); } continue; } if (paletteContainer == null) { paletteContainer = new PaletteContainer(); paletteContainer.Palette = new Palette(); paletteContainers.Add(paletteContainer); } paletteContainer.Add(chunkContainer); paletteContainer.AddColors(region.GetColors()); } } Console.WriteLine("Done processing monocolor regions"); Console.WriteLine("Parsing multicolor regions"); HashSet<Region> colorRegions = Process(locationPool, maximumDistance, RegionType.MultiColorRegion); Console.WriteLine("Have multi color region count " + colorRegions.Count); foreach (Region region in colorRegions) { HashSet<ChunkContainer> potentialContainers = region.GetChunks(locationPool); PaletteContainer paletteContainer = GetPaletteContainer(paletteContainers, region.GetColors()); if (paletteContainer == null) { paletteContainer = new PaletteContainer(); paletteContainer.Palette = new Palette(); paletteContainers.Add(paletteContainer); } foreach (ChunkContainer chunkContainer in potentialContainers) { paletteContainer.Add(chunkContainer); paletteContainer.AddColors(region.GetColors()); } } Console.WriteLine("Done processing multicolor regions"); Console.WriteLine("Histogram count " + colorList.Count); Console.WriteLine("Majority color " + mostCommonColor + " with count " + colorList[0].Value); //alrighty, let's get some output going Container container = new Container(); Frame frame = new Frame(); container.Frames.Add(frame); foreach (PaletteContainer paletteContainer in paletteContainers) { PaletteChunk paletteChunk = paletteContainer.Palette.GetPaletteChunk(); if (paletteChunk == null) { paletteChunk = defaultPaletteChunk; } if (!paletteContainer.Initial) { paletteChunk.Colors.Sort(new PaletteChunk.ColorSorter()); frame.Chunks.Add(paletteChunk); } foreach (ChunkContainer chunkContainer in paletteContainer.ChunkContainers) { int count = chunkContainer.Chunk.GetData().Count; PrintKeptChunk(chunkContainer); chunkContainer.SetIndex(paletteChunk); chunkContainer.Chunk.Palette = paletteChunk; frame.Chunks.Add(chunkContainer.Chunk); } } return container; }
public override HashSet<ChunkContainer> GetChunks(LocationPool locationPool) { HashSet<ChunkContainer> result = new HashSet<ChunkContainer>(); if (Locations.Count == 0) { return result; } if (Palette.Count() == 1) { if (IsRectangle()) { MonoRectangleChunk rectangleChunk = new MonoRectangleChunk(); rectangleChunk.Origin = BoundingBox.UpperLeft; rectangleChunk.Width = BoundingBox.Width(); rectangleChunk.Height = BoundingBox.Height(); MonoRectangleChunkContainer container = new MonoRectangleChunkContainer(); container.Chunk = rectangleChunk; container.Locations = GetLocations(BoundingBox); container.Color = Palette.Colors.First(); result.Add(container); return result; } //output a monochunk? MonoBitPlaneChunk monoColorChunk = new MonoBitPlaneChunk(); monoColorChunk.Width = BoundingBox.Width(); monoColorChunk.Height = BoundingBox.Height(); monoColorChunk.Initialize(); monoColorChunk.Origin = BoundingBox.UpperLeft; foreach (Location location in Locations) { monoColorChunk.SetColor(location.Point.X, location.Point.Y); } MonoBitPlaneChunkContainer monoContainer = new MonoBitPlaneChunkContainer(); monoContainer.Chunk = monoColorChunk; monoContainer.Locations = Locations; monoContainer.Color = Palette.Colors.First(); result.Add(monoContainer); return result; } if (IsRectangle()) { MultiColorRectangleChunkContainer container = new MultiColorRectangleChunkContainer(); ColorRectangleChunk rectangleChunk = new ColorRectangleChunk(); rectangleChunk.Origin = BoundingBox.UpperLeft; rectangleChunk.Width = BoundingBox.Width(); rectangleChunk.Height = BoundingBox.Height(); //rectangleChunk.Direction = Direction.Left; rectangleChunk.Initialize(); container.Chunk = rectangleChunk; container.Locations = Locations; rectangleChunk.Palette = Palette.GetPaletteChunk(); foreach (Location location in Locations) { rectangleChunk.SetColor(location.Color, location.Point.X, location.Point.Y); } result.Add(container); return result; } //Don't break it into further rectangles right now... just output a bitplane MultiColorBitPlaneChunkContainer chunkContainer = new MultiColorBitPlaneChunkContainer(); ColorBitPlaneChunk colorBitPlaneChunk = new ColorBitPlaneChunk(); colorBitPlaneChunk.Origin = BoundingBox.UpperLeft; colorBitPlaneChunk.Height = BoundingBox.Height(); colorBitPlaneChunk.Width = BoundingBox.Width(); colorBitPlaneChunk.Palette = Palette.GetPaletteChunk(); colorBitPlaneChunk.Initialize(); chunkContainer.Chunk = colorBitPlaneChunk; chunkContainer.Locations = Locations; foreach (Location location in Locations) { //bitmask must use local coordinates colorBitPlaneChunk.SetColor(location.Color, location.Point.X, location.Point.Y); } result.Add(chunkContainer); return result; }
/// <summary> /// To return a RectangleChunk we will need the bounding box and a check for missing locations /// </summary> /// <returns></returns> public override HashSet<ChunkContainer> GetChunks(LocationPool locationPool) { HashSet<ChunkContainer> result = new HashSet<ChunkContainer>(); if (IsRectangle()) { MonoRectangleChunk rectangleChunk = new MonoRectangleChunk(); rectangleChunk.Origin = BoundingBox.UpperLeft; rectangleChunk.Width = BoundingBox.Width(); rectangleChunk.Height = BoundingBox.Height(); MonoRectangleChunkContainer container = new MonoRectangleChunkContainer(); container.Chunk = rectangleChunk; container.Locations = GetLocations(BoundingBox); //container.AdditionalSize = NewColorCount(locationPool.Palette); container.Color = Color; result.Add(container); return result; } //break up into many rectangles and return rest here HashSet<Location> locations = new HashSet<Location>(Locations); HashSet<BoundingBox> rectangles = GetAllRectangles(locations, BoundingBox); foreach (BoundingBox rectangle in rectangles) { MonoRectangleChunk rectangleChunk = new MonoRectangleChunk(); rectangleChunk.Origin = rectangle.UpperLeft; rectangleChunk.Width = rectangle.Width(); rectangleChunk.Height = rectangle.Height(); MonoRectangleChunkContainer container = new MonoRectangleChunkContainer(); container.Chunk = rectangleChunk; container.Color = Color; //container.AdditionalSize = NewColorCount(locationPool.Palette); container.Locations = GetLocations(rectangle); result.Add(container); } //now for the remaining locations, create monocolorchunks BoundingBox remaining = new BoundingBox(); foreach (Location location in locations) { remaining.Add(location.Point); } MonoBitPlaneChunk monoColorChunk = new MonoBitPlaneChunk(); monoColorChunk.Width = remaining.Width(); monoColorChunk.Height = remaining.Height(); monoColorChunk.Initialize(); monoColorChunk.Origin = remaining.UpperLeft; foreach (Location location in locations) { monoColorChunk.SetColor(location.Point.X, location.Point.Y); } MonoBitPlaneChunkContainer monoContainer = new MonoBitPlaneChunkContainer(); monoContainer.Chunk = monoColorChunk; monoContainer.Locations = GetLocations(remaining); monoContainer.Color = Color; result.Add(monoContainer); return result; }
public abstract HashSet<ChunkContainer> GetChunks(LocationPool locationPool);