Пример #1
0
        public SampledImage SampleImage(Bitmap image, int sampleCount)
        {
            Init(image, sampleCount);

            sampleCount = Math.Min(sampleCount, image.Width * image.Height);

            SampledImage sampledImage = new SampledImage()
            {
                Width = width,
                Height = height
            };

            Progress.ReportProgress(0);

            // NOTE: some random position candidates may go outside the image
            // and thus are do not contribute as the real image samples
            Stopwatch stopwatch = Stopwatch.StartNew();

            GenerateSamples(image, sampleCount, sampledImage);

            if (canReadImageDirectly)
            {
                image.UnlockBits(imageData);
            }

            stopwatch.Stop();

            Progress.TimeReport["sampler"] = stopwatch.ElapsedMilliseconds;
            Progress.ReportProgress(100);

            return sampledImage;
        }
Пример #2
0
        public static SampledImage LoadFromFile(string fileName)
        {
            SampledImage sampledImage = new SampledImage();
            using (StreamReader reader = new StreamReader(fileName))
            {
                try
                {
                    sampledImage.Width = Int32.Parse(reader.ReadLine());
                    sampledImage.Height = Int32.Parse(reader.ReadLine());

                    string line = reader.ReadLine();
                    while ((line != null) && (line.Length != 0))
                    {
                        string[] sampleFields = line.Split(new char[] { ' ' }, 3);
                        int x = Int32.Parse(sampleFields[0]);
                        int y = Int32.Parse(sampleFields[1]);
                        int argb = Int32.Parse(sampleFields[2]);
                        Color color = Color.FromArgb(argb);
                        sampledImage.AddSample(new ImageSample(x, y, color));
                        line = reader.ReadLine();
                    }
                }
                catch (FormatException ex)
                {
                    Console.Error.WriteLine(ex.Message);
                    return null;
                }
            }

            return sampledImage;
        }
Пример #3
0
        protected int GenerateCluster(Bitmap image, int sampleCount, SampledImage sampledImage, int samplePercent, int percentDone, int maxIterations)
        {
            for (int i = 0; (sampledImage.Samples.Count < sampleCount) && (i < maxIterations); i++)
            {
                int x;
                int y;
                if (!Next2DWithinImage(out x, out y))
                {
                    continue;
                }
                Color color;
                if (canReadImageDirectly)
                {
                    // faster, only for BGR or BGRA
                    unsafe
                    {
                        byte* imagePtr = imagePtrBase + (y * imageData.Stride) + x * bands;
                        byte b = imagePtr[0];
                        byte g = imagePtr[1];
                        byte r = imagePtr[2];
                        byte a = 255;
                        if (hasAlpha)
                        {
                            a = imagePtr[3];
                        }
                        color = Color.FromArgb(a, r, g, b);
                    }
                }
                else
                {
                    // slower, more general
                    color = image.GetPixel(x, y);
                }
                sampledImage.AddSample(new ImageSample(x, y, color));

                if ((samplePercent > 500) && (sampledImage.Samples.Count % samplePercent == 0))
                {
                    percentDone++;
                    Progress.ReportProgress(percentDone);
                }
            }
            return percentDone;
        }
Пример #4
0
        protected override void GenerateSamples(Bitmap image, int sampleCount, SampledImage sampledImage)
        {
            // NOTE: some random position candidates may go outside the image
            // and thus are do not contribute as the real image samples
            int samplePercent = sampleCount / 100;
            int percentDone = 0;
            int samplesPerCluster = sampleCount / ClusterCount;
            int targetSampleCount = sampleCount % ClusterCount;
            for (int cluster = 0; cluster < ClusterCount; cluster++)
            {
                targetSampleCount += samplesPerCluster;
                int maxIterations = 10 * targetSampleCount;

                // standard deviation of the cluster
                //double stdDev = maxStdDev * random.NextDouble();
                stdDev = meanStdDev * gaussRandom.Next(1, 0.5);
                // center of the cluster
                centerX = random.Next(0, width - 1);
                centerY = random.Next(0, height - 1);

                percentDone = GenerateCluster(image, targetSampleCount, sampledImage, samplePercent, percentDone, maxIterations);
            }
        }
Пример #5
0
        public Bitmap ReconstructImage(SampledImage sampledImage)
        {
            int width = sampledImage.Width;
            int height = sampledImage.Height;

            Stopwatch stopwatch = Stopwatch.StartNew();

            Bitmap image = new Bitmap(width, height);

            // fill with black background
            using (Graphics graphics = Graphics.FromImage(image))
            {
                graphics.FillRectangle(Brushes.Black, 0, 0, width, height);
            }

            // TODO:
            // - directly write into the image via pointers
            //   - at least for RGBA images

            int samplePercent = sampledImage.Samples.Count / 100;
            int currentSample = 0;
            int percentDone = 0;

            if ((image.PixelFormat == PixelFormat.Format32bppArgb) ||
                (image.PixelFormat == PixelFormat.Format24bppRgb))
            {
                // faster, only for BGR or BGRA
                BitmapData imageData = image.LockBits(new Rectangle(0, 0, width, height),
                    ImageLockMode.WriteOnly, image.PixelFormat);
                bool hasAlpha = image.PixelFormat == PixelFormat.Format32bppArgb;
                int bands =  hasAlpha ? 4 : 3;

                unsafe
                {
                    byte* imagePtrBase = (byte*)imageData.Scan0;

                    foreach (ImageSample sample in sampledImage.Samples)
                    {
                        byte* imagePtr = imagePtrBase + (sample.Y * imageData.Stride) + sample.X * bands;
                        imagePtr[0] = sample.color.B;
                        imagePtr[1] = sample.color.G;
                        imagePtr[2] = sample.color.R;
                        if (hasAlpha)
                        {
                            imagePtr[3] = sample.color.A;
                        }
                        ReportProgress(samplePercent, ref currentSample, ref percentDone);
                    }
                }
                image.UnlockBits(imageData);
            }
            else
            {
                // slower, more general
                foreach (ImageSample sample in sampledImage.Samples)
                {
                    image.SetPixel(sample.X, sample.Y, sample.color);
                    ReportProgress(samplePercent, ref currentSample, ref percentDone);
                }
            }

            Progress.TimeReport["visualizer"] = stopwatch.ElapsedMilliseconds;

            Progress.ReportProgress(100);

            return image;
        }
Пример #6
0
 private static void SaveSamplesToFile(SampledImage sampledImage, string sampler)
 {
     sampledImage.SaveToFile(string.Format("{0}{1}_samples_{2}_{3}.txt", RESULTS_DIR, INPUT_IMAGE, sampler, SAMPLE_COUNT));
 }
Пример #7
0
 private static void ReconstructImage(SampledImage sampledImage, ISampledImageVisualizer visualizer, string sampler)
 {
     Bitmap reconstructedImage = visualizer.ReconstructImage(sampledImage);
     reconstructedImage.Save(string.Format("{0}{1}_reconstructed_{2}_{3}.png", RESULTS_DIR, INPUT_IMAGE, sampler, SAMPLE_COUNT));
 }
Пример #8
0
        public Bitmap ReconstructImage(SampledImage sampledImage)
        {
            int width = sampledImage.Width;
            int height = sampledImage.Height;
            Bitmap image = new Bitmap(width, height);

            Progress.ReportProgress(0);

            Stopwatch stopwatch = Stopwatch.StartNew();

            // use cached triangulation if possible
            PointSet triMesh =
                (TriangulationCachingEnabled && sampledImage.Equals(previousSampledImage)) ?
                    previousTriMesh : voronoiHelper.MakeDelaunayTriangulation(sampledImage);

            stopwatch.Stop();
            Progress.TimeReport["delaunay"] = stopwatch.ElapsedMilliseconds;

            previousTriMesh = triMesh;
            previousSampledImage = sampledImage;

            Progress.ReportProgress(25);

            stopwatch.Reset();
            stopwatch.Start();

            using (Graphics graphics = Graphics.FromImage(image))
            {
                // fill with black background
                //graphics.FillRectangle(Brushes.White, 0, 0, width, height);

                graphics.SmoothingMode = AntiAliasingEnabled ?
                    System.Drawing.Drawing2D.SmoothingMode.AntiAlias :
                    System.Drawing.Drawing2D.SmoothingMode.None;

                if (VoronoiCellsEnabled)
                {
                    DrawVoronoiCells(triMesh, graphics, sampledImage);
                }

                Progress.ReportProgress(50);

                if (DelaunayTrianglesEnabled)
                {
                    DrawDelaunayTriangles(triMesh, graphics);
                }

                Progress.ReportProgress(75);

                DrawAdditionalFeatures(width, height, triMesh, graphics, image);

                Progress.ReportProgress(100);
            }
            Progress.TimeReport["visualizer"] = stopwatch.ElapsedMilliseconds;

            return image;
        }
Пример #9
0
        private void DrawVoronoiCells(PointSet triMesh, Graphics graphics, SampledImage sampledImage)
        {
            int samplePercent = 4 * triMesh.Triangles.Count / 100;
            int trianglesDone = 0;
            int percentDone = 0;

            // Voronoi cell which have already been drawn onto the image
            HashSet<Vector2> drawnVoronoiCells = new HashSet<Vector2>();

            foreach (DelaunayTriangle triangle in triMesh.Triangles)
            {
                // draw Voronoi cells, one around each Delaunay triangle vertex
                foreach (TriangulationPoint triVertex in triangle.Points)
                {
                    // each cell corresponds to a triangulation vertex
                    Vector2 point = triVertex.ToVector2();
                    if (drawnVoronoiCells.Contains(point))
                    {
                        // this Voronoi cell was already drawn
                        continue;
                    }
                    drawnVoronoiCells.Add(point);
                    IList<DelaunayTriangle> surroundingTriangles =
                        VoronoiHelper.GetSurroundingTriangles(triangle, triVertex);
                    if (surroundingTriangles.Count < 3)
                    {
                        // there are not enough vertices to make a polygon
                        continue;
                    }
                    // TODO: the computation of the circumference could
                    // be cached since the voronoi vertices are usually
                    // share among multiple triangles
                    IEnumerable<Vector2> voronoiCellVertices = surroundingTriangles.Select(
                        (DelaunayTriangle tri) => VoronoiHelper.GetCircumcenter(tri));
                    PointF[] voronoiCellPolygon = voronoiCellVertices.Select(
                        (Vector2 vertex) => vertex.ToPointF()).ToArray();

                    //Color sampleColor = GetRandomColor();
                    ImageSample imageSample;
                    Color sampleColor = Color.Pink;  // DEBUG
                    if (sampledImage.SampleMap.TryGetValue((int)triVertex.Y * sampledImage.Width + (int)triVertex.X, out imageSample))
                    {
                        sampleColor = imageSample.color;
                    }
                    graphics.FillPolygon(new SolidBrush(sampleColor), voronoiCellPolygon);
                    if (VoronoiCellBordersEnabled)
                    {
                        graphics.DrawPolygon(Pens.Gray, voronoiCellPolygon);
                    }
                }
                trianglesDone++;
                if ((samplePercent > 500) && (trianglesDone % samplePercent == 0))
                {
                    percentDone++;
                    Progress.ReportProgress(25 + percentDone);
                }
            }
        }
Пример #10
0
 protected virtual void GenerateSamples(Bitmap image, int sampleCount, SampledImage sampledImage)
 {
     int maxIterations = 10 * sampleCount;
     int samplePercent = sampleCount / 100;
     int percentDone = 0;
     GenerateCluster(image, sampleCount, sampledImage, samplePercent, percentDone, maxIterations);
 }
Пример #11
0
        public PointSet MakeDelaunayTriangulation(SampledImage sampledImage)
        {
            List<TriangulationPoint> points = new List<TriangulationPoint>();
            foreach (ImageSample sample in sampledImage.Samples)
            {
                points.Add(new TriangulationPoint(sample.position.X, sample.position.Y));
            }

            int width = sampledImage.Width;
            int height = sampledImage.Height;

            // add a bounding box in order to make Voronoi cells bounded
            // inside the image
            points.Add(new TriangulationPoint(-width, -height));
            points.Add(new TriangulationPoint(-width, 2 * height));
            points.Add(new TriangulationPoint(2 * width, 2 * height));
            points.Add(new TriangulationPoint(2 * width, -height));

            return MakeDelaunayTriangulation(points);
        }