private double[,] sobelFilter(PixelMap map) { double[,] output = new double[map.Width, map.Height]; double[,] kernelX = { {-1,0,1 }, {-2,0,2 }, {-1,0,1 } }; double[,] kernelY = { {-1,-2,-1}, {0,0,0}, {1,2,1} }; double[,] xFiltered = sobelPass(map, kernelX); double[,] yFiltered = sobelPass(map, kernelY); for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { double xVal = xFiltered[x, y]; double yVal = yFiltered[x, y]; output[x, y] = Math.Sqrt(xVal * xVal + yVal * yVal); } } return output; }
public void Fill(SampleTri t, PixelMap map) { Point center = t.CenterPoint; int radius = (int)t.Samples.Max(s => dist(s.Point, center)); for (int x = center.X - radius; x < center.X + radius; x++) { for (int y = center.Y - radius; y < center.Y + radius; y++) { Point fillPoint = new Point(x, y); double theta = Math.PI+Math.Atan2(fillPoint.Y - center.Y,fillPoint.X - center.X); double distance = dist(fillPoint, center); if (map.Inside(fillPoint) && distance < ShapeFunction(theta)*radius) { map[fillPoint] = t.CenterColor; //map[fillPoint] = new Pixel(theta*180/Math.PI,0.5,0.5); } if (distance > 1000) { Console.WriteLine("wat"); } } } }
static TrigradCompressed fauxResults(PixelMap input) { var results = new TrigradCompressed(); results.Width = input.Width; results.Height = input.Height; List<Point> samplePoints = new List<Point>(); samplePoints.Add(new Point(0, 0)); samplePoints.Add(new Point(input.Width - 1, 0)); samplePoints.Add(new Point(0, input.Height - 1)); samplePoints.Add(new Point(input.Width - 1, input.Height - 1)); int cellsize = 8; for (int x = 0; x < input.Width / cellsize; x++) { for (int y = 0; y < input.Height / cellsize; y++) { samplePoints.Add(new Point(x * cellsize, y * cellsize)); } } foreach (var samplePoint in samplePoints) { results.SampleTable[samplePoint] = input[samplePoint]; } results.Mesh = MeshBuilder.BuildMesh(results.SampleTable); return results; }
private static double errorPolygon(Sample s, PixelMap original, TrigradOptions options) { if(options.ResampleColors) foreach (var sample in s.Samples) { sample.Color = original[sample.Point]; } double error = 0d; foreach (var t in s.Triangles) { t.CenterColor = original[t.CenterPoint]; options.Renderer.Fill(t,tempMap); foreach (var drawPoint in t.Points) { Pixel a = original[drawPoint.Point]; Pixel b = tempMap[drawPoint.Point]; Pixel diff = a - b; error += diff.R; error += diff.G; error += diff.B; } } return error; }
static void Main(string[] args) { //Quickly load a PixelMap through a Bitmap PixelMap map = new PixelMap("Lenna.png"); for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { //Sample a pixel Pixel pixel = map[x, y]; //Create a hue value double value = ((double)x / map.Width) * 360d; //Set the hue value to our sample pixel.Hue = value; //Return our sample to the PixelMap map[x, y] = pixel; } } //Save the PixelMap through a Bitmap map.GetBitmap().Save("output.png"); }
public void Fill(SampleTri t, PixelMap map) { foreach (var drawPoint in t.Points) { Pixel gradedColor = Grader.Grade(t.U, t.V, t.W, drawPoint); map[drawPoint.Point] = gradedColor; } }
public void Fill(SampleTri t, PixelMap map) { foreach (var drawPoint in t.Points) { Pixel gradedColor = t.CenterColor; map[drawPoint.Point] = gradedColor; } }
/// <summary> Constructs a frequency table using sobel edge detection. </summary> public FrequencyTable(PixelMap pixelmap,double power = 1.7) { Table = sobelFilter(pixelmap); for (int x = 0; x < Table.GetLength(0); x++) { for (int y = 0; y < Table.GetLength(1); y++) { Table[x, y] = Math.Pow(Table[x, y], power); } } }
private static void drawMesh(List<SampleTri> mesh, PixelMap output, TrigradOptions options) { int i = 0; int count = mesh.Count; foreach (var triangle in mesh) { options.Renderer.Fill(triangle,output); if (i % 50 == 0 && OnUpdate != null) OnUpdate((double)i / count); i++; } }
public static void OptimiseMesh(TrigradCompressed compressionData, PixelMap original, TrigradOptions options) { var mesh = compressionData.Mesh; GPUT.CalculateMesh(mesh); var samples = mesh.SelectMany(t => t.Samples).Distinct().ToList(); for (int i = 0; i < options.Iterations; i++) { minimiseMesh(samples, options, original); Console.WriteLine("{0}/{1}", i, options.Iterations); } compressionData.Mesh = mesh; }
/// <summary> /// Clones a PixelMap.</summary> public PixelMap(PixelMap original) { Width = original.Width; Height = original.Height; map = new Pixel[Width, Height]; BPP = original.BPP; format = original.format; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { this[x, y] = original[x, y]; } } }
/// <summary> Provides a visualisation of the SampleTable. </summary> public PixelMap DebugVisualisation() { PixelMap map = new PixelMap(Width, Height); for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { map[x, y] = new Pixel(10, 10, 10); } } foreach (var value in SampleTable) { Point p = value.Key; map[p]= value.Value; } return map; }
private static void fillGaps(PixelMap p) { Pixel lastColor = p[0]; Pixel pink = new Pixel(Color.HotPink); for (int x = 0; x < p.Width; x++) { for (int y = 0; y < p.Height; y++) { if (alike(p[x, y],pink)) { p[x, y] = lastColor; } else { lastColor = p[x, y]; } } } }
/// <summary> Compresses a bitmap using TrigradCompression. </summary> /// <param name="pixelmap"> The input bitmap.</param> /// <param name="options"> TrigradOptions specifying how the image will be compressed.</param> public static TrigradCompressed CompressBitmap(PixelMap pixelmap, TrigradOptions options) { TrigradCompressed compressed = new TrigradCompressed { Height = pixelmap.Height, Width = pixelmap.Width }; double baseChance = options.SampleCount / (options.FrequencyTable.Sum); int i = 0; int count = pixelmap.Width * pixelmap.Height; for (int x = 0; x < pixelmap.Width; x++) { for (int y = 0; y < pixelmap.Height; y++) { if ((x == 0 && y == 0) || (x == pixelmap.Width - 1 && y == 0) || (x == 0 && y == pixelmap.Height - 1) || (x == pixelmap.Width - 1 && y == pixelmap.Height - 1)) { compressed.SampleTable[new Point(x, y)] = pixelmap[new Point(x, y)]; continue; } double chance = ((options.FrequencyTable != null) ? options.FrequencyTable.Table[x, y] : 1d) * baseChance; lock(options.Random) if (options.Random.NextDouble() < chance) { lock (compressed.SampleTable) compressed.SampleTable[new Point(x, y)] = pixelmap[new Point(x, y)]; } if (i % 50 == 0 && OnUpdate != null) OnUpdate((double)i / count); i++; } } return compressed; }
static int errorBitmap(PixelMap a, PixelMap b) { int error = 0; PixelMap output = new PixelMap(a.Width, a.Height); for (int x = 0; x < a.Width; x++) { for (int y = 0; y < a.Height; y++) { Pixel cA = a[x, y]; Pixel cB = b[x, y]; Pixel diff = cA - cB; error += (diff.R + diff.G + diff.B); output[x, y] = diff; } } output.GetBitmap().Save("tests\\error.png"); return error; }
/// <summary> Constructor for a TrigradDecompressed object, defining the width and height of output bitmaps. </summary> public TrigradDecompressed(int width, int height) { Output = new PixelMap(width, height); DebugOutput = new PixelMap(width, height); }
/// <summary> /// Load a Bitmap pixel-by-pixel, slowly.</summary> public static PixelMap SlowLoad(Bitmap b) { PixelMap m = new PixelMap(b.Width, b.Height); for (int x = 0; x < b.Width; x++) { for (int y = 0; y < b.Height; y++) { m[x, y] = new Pixel(b.GetPixel(x, y)); } } return m; }
private static void minimiseSample(Sample s, int resamples, PixelMap original, TrigradOptions options) { if (s.Point.X == 0 || s.Point.Y == 0) return; if (s.Point.X == original.Width - 1 || s.Point.Y == original.Height - 1) return; var curPoints = s.Points; double minError = errorPolygon(s, original, options); Point bestPoint = s.Point; if (polygonConvex(s)) return; int count = curPoints.Count; int skip = count / resamples; if (skip == 0) skip = 1; foreach (var drawPoint in curPoints.Where((x, i) => i % skip == 0)) { s.Point = drawPoint.Point; TriangleRasterization.CalculateMesh(s.Triangles); double error = errorPolygon(s, original, options); if (error < minError) { bestPoint = drawPoint.Point; minError = error; } } s.Point = bestPoint; TriangleRasterization.CalculateMesh(s.Triangles); }
static void minimiseMesh(List<Sample> samples, TrigradOptions options, PixelMap original) { tempMap = new PixelMap(original.Width,original.Height); int o = 0; int count = samples.Count; foreach (var sample in samples) { minimiseSample(sample, options.Resamples, original, options); o++; if (o%1000 == 0) Console.WriteLine("{0}/{1}", o, samples.Count); if (o%100 == 0 && OnUpdate != null) OnUpdate((double)o/count); } }
private double[,] sobelPass(PixelMap map, double[,] kernel) { double[,] output = new double[map.Width, map.Height]; for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { double sum = 0; for (int u = 0; u < 3; u++) { for (int v = 0; v < 3; v++) { Point samplePoint = new Point(x - 1 + u, y - 1 + v); if (map.Inside(samplePoint)) { double kVal = kernel[u, v]; double imgVal = map[samplePoint].Lightness; sum += kVal * imgVal; } else { sum += 0.5; } } } output[x, y] = sum; } } return output; }
public PixelMap MeshOutput(PixelMap original) { return Mesh.DrawMesh(Width, Height); }