Esempio n. 1
0
        private void EdgeDetectionRefresh()
        {
            if (image == null)
            {
                return;
            }

            Potrace.Clear();
            ListOfPaths.Clear();


            double scale = OrigImage.ActualHeight / image.Height;

            if (scale <= 0)
            {
                return;
            }
            int x = (int)(RectCutX / scale);
            int w = (int)(RectCutWidth / scale);
            int y = (int)(RectCutY / scale);
            int h = (int)(RectCutHeight / scale);

            Bitmap cutImage = CropBitmap(image, new Rectangle(x, y, w, h));

            Potrace.Potrace_Trace(cutImage, ListOfPaths);

            EdgePathGeometry.AddListOfPaths(ListOfPaths);
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            // Variables
            Bitmap bm;
            GrasshopperBitmapGoo ghbm = new GrasshopperBitmapGoo();
            double t          = 50.0;
            double a          = 1.0;
            double mts        = 2;
            bool   opt        = true;
            double opttol     = 0.2;
            bool   inv        = false;
            int    colorCount = 2;

            // Get Data from Input Params
            if (!DA.GetData(0, ref ghbm))
            {
                return;
            }
            if (DA.GetData(1, ref t))
            {
                if (0.0 > t || t > 100.0)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Threshold must lie between 0.0 to 100.0");
                    return;
                }
            }
            if (DA.GetData(2, ref a))
            {
                if (0.0 > a || a > 1.0)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Corner Threshold must lie between 0.0 to 1.0");
                    return;
                }
            }
            DA.GetData(3, ref mts);
            DA.GetData(4, ref opt);
            if (DA.GetData(5, ref opttol))
            {
                if (0.0 > opttol || opttol > 1.0)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Tolerance for Optimization must lie between 0.0 to 1.0");
                    return;
                }
            }
            DA.GetData(6, ref inv);
            if (DA.GetData(7, ref colorCount))
            {
                if (colorCount < 0)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Color Count cannot be negative");
                    return;
                }
            }
            else
            {
                if (getColors)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Color Count not set. Setting 'Get Colors' to False. Please set a value for Color Count and re-enable Get Colors by right-clicking on the component");
                    getColors = false;
                }
            }

            // set Data in Potrace fields
            Potrace.Treshold        = t / 100;
            Potrace.alphamax        = a * (4 / 3);
            Potrace.turdsize        = ((int)Math.Round(mts, 0, MidpointRounding.AwayFromZero));
            Potrace.curveoptimizing = opt;
            Potrace.opttolerance    = opttol;

            if (ghbm.IsValid && ghbm.Image != null)
            {
                bm = ghbm.Image;
            }
            else
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid Bitmap");
                return;
            }

            // convert png transparent background to white
            if (!getColors || (colorCount == 0))
            {
                using (Bitmap b = new Bitmap(bm.Width, bm.Height))
                {
                    b.SetResolution(bm.HorizontalResolution, bm.VerticalResolution);
                    using (Graphics g = Graphics.FromImage(b))
                    {
                        g.Clear(Color.White);
                        g.DrawImageUnscaled(bm, 0, 0);
                    }

                    b.RotateFlip(RotateFlipType.RotateNoneFlipY);

                    DataTree <Curve> crvs = new DataTree <Curve>();
                    Potrace.Potrace_Trace(b, crvs, inv);

                    DA.SetDataTree(0, crvs);
                }
            }
            else
            {
                using (Bitmap b = new Bitmap(bm.Width, bm.Height))
                {
                    b.SetResolution(bm.HorizontalResolution, bm.VerticalResolution);
                    using (Graphics g = Graphics.FromImage(b))
                    {
                        g.Clear(Color.Transparent);
                        g.DrawImageUnscaled(bm, 0, 0);
                    }
                    b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                    WuQuantizer quantizer = new WuQuantizer();
                    Bitmap      quantized = (Bitmap)quantizer.QuantizeImage(b, colorCount + 1);
                    Color[]     colors    = new Color[colorCount];
                    Array.Copy(quantized.Palette.Entries, 0, colors, 0, colorCount);
                    DataTree <GH_Colour> colorsOut = new DataTree <GH_Colour>();
                    DataTree <Curve>     crvs      = new DataTree <Curve>();
                    for (int i = 0; i < colorCount; i++)
                    {
                        Bitmap temp   = quantized.Clone(new Rectangle(0, 0, b.Width, b.Height), PixelFormat.Format32bppArgb);
                        var    bmData = temp.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

                        unsafe
                        {
                            byte *p           = (byte *)bmData.Scan0;
                            int   stopAddress = (int)p + bmData.Stride * bmData.Height;
                            while ((int)p != stopAddress)
                            {
                                if (p[0] == colors[i].B && p[1] == colors[i].G && p[2] == colors[i].R && p[3] == colors[i].A)
                                {
                                    p[0] = p[1] = p[2] = p[3] = 255;
                                }
                                else
                                {
                                    p[0] = p[1] = p[2] = p[3] = 0;
                                }
                                p += 4;
                            }
                            temp.UnlockBits(bmData);

                            List <Curve> curves = new List <Curve>();
                            Potrace.Potrace_Trace(temp, curves, true);
                            crvs.AddRange(curves, new GH_Path(i));
                            if (inv)
                            {
                                Color invCol = Color.FromArgb(((int)colors[i].A), (255 - ((int)colors[i].R)), (255 - ((int)colors[i].G)), (255 - ((int)colors[i].B)));
                                colorsOut.Add(new GH_Colour(invCol), new GH_Path(i));
                            }
                            else
                            {
                                colorsOut.Add(new GH_Colour(colors[i]), new GH_Path(i));
                            }
                            Potrace.Clear();
                            Potrace.Treshold        = t / 100;
                            Potrace.alphamax        = a * (4 / 3);
                            Potrace.turdsize        = ((int)Math.Round(mts, 0, MidpointRounding.AwayFromZero));
                            Potrace.curveoptimizing = opt;
                            Potrace.opttolerance    = opttol;
                        }
                    }
                    DA.SetDataTree(0, crvs);
                    DA.SetDataTree(2, colorsOut);
                }
            }
            Rectangle3d boundary = new Rectangle3d(Plane.WorldXY, (double)bm.Width, (double)bm.Height);

            DA.SetData(1, boundary);
        }
 protected override void BeforeSolveInstance()
 {
     base.BeforeSolveInstance();
     Potrace.Clear();
 }
Esempio n. 4
0
        /// <summary>
        /// Command.RunCommand override
        /// </summary>
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            Potrace.Clear();

            // Prompt the user for the name of the image file to vectorize.
            string path = GetImageFileName(mode);

            if (string.IsNullOrEmpty(path))
            {
                return(Result.Cancel);
            }

            // Creates a bitmap from the specified file.
            var bitmap = Image.FromFile(path) as Bitmap;

            if (null == bitmap)
            {
                RhinoApp.WriteLine("The specified file cannot be identifed as a supported type.");
                return(Result.Failure);
            }

            // Verify bitmap size
            if (0 == bitmap.Width || 0 == bitmap.Height)
            {
                RhinoApp.WriteLine("Error reading the specified file.");
                return(Result.Failure);
            }

            // Calculate scale factor so curves of a reasonable size are added to Rhino
            var unit_scale = (doc.ModelUnitSystem != UnitSystem.Inches)
        ? RhinoMath.UnitScale(UnitSystem.Inches, doc.ModelUnitSystem)
        : 1.0;
            var scale = (double)(1.0 / bitmap.HorizontalResolution * unit_scale);

            // I'm not convinced this is useful...
            if (true)
            {
                var format = $"F{doc.DistanceDisplayPrecision}";

                // Print image size in pixels
                RhinoApp.WriteLine("Image size in pixels: {0} x {1}",
                                   bitmap.Width,
                                   bitmap.Height
                                   );

                // Print image size in inches
                var width  = (double)(bitmap.Width / bitmap.HorizontalResolution);
                var height = (double)(bitmap.Height / bitmap.VerticalResolution);
                RhinoApp.WriteLine("Image size in inches: {0} x {1}",
                                   width.ToString(format, CultureInfo.InvariantCulture),
                                   height.ToString(format, CultureInfo.InvariantCulture)
                                   );

                // Image size in in model units, if needed
                if (doc.ModelUnitSystem != UnitSystem.Inches)
                {
                    width  = (double)(bitmap.Width / bitmap.HorizontalResolution * unit_scale);
                    height = (double)(bitmap.Height / bitmap.VerticalResolution * unit_scale);
                    RhinoApp.WriteLine("Image size in {0}: {1} x {2}",
                                       doc.ModelUnitSystem.ToString().ToLower(),
                                       width.ToString(format, CultureInfo.InvariantCulture),
                                       height.ToString(format, CultureInfo.InvariantCulture)
                                       );
                }
            }

            // Convert the bitmap to an Eto bitmap
            var eto_bitmap = ConvertBitmapToEto(bitmap);

            if (null == eto_bitmap)
            {
                RhinoApp.WriteLine("Unable to convert image to Eto bitmap.");
                return(Result.Failure);
            }

            // 12-Jan-2021 Dale Fugier
            // This should prevent Eto.Drawing.BitmapData.GetPixels() from throwing an exception
            if (!IsCompatibleBitmap(eto_bitmap))
            {
                RhinoApp.WriteLine("The image has an incompatible pixel format. Please select an image with 24 or 32 bits per pixel, or 8 bit indexed.");
                return(Result.Failure);
            }

            // This bitmap is not needed anymore, so dispose of it
            bitmap.Dispose();

            // Gets the Potrace settings from the plug-in settings file
            GetPotraceSettings();

            // Create the conduit, which does most of the work
            var conduit = new VectorizeConduit(
                eto_bitmap,
                scale,
                doc.ModelAbsoluteTolerance,
                m_select_output
          ? Rhino.ApplicationSettings.AppearanceSettings.SelectedObjectColor
          : doc.Layers.CurrentLayer.Color
                )
            {
                Enabled = true
            };

            if (mode == RunMode.Interactive)
            {
                // Show the interactive dialog box
                var dialog = new VectorizeDialog(doc, conduit);
                dialog.RestorePosition();
                var result = dialog.ShowSemiModal(doc, RhinoEtoApp.MainWindow);
                dialog.SavePosition();
                if (result != Result.Success)
                {
                    conduit.Enabled = false;
                    Potrace.Clear();
                    doc.Views.Redraw();
                    return(Result.Cancel);
                }
            }
            else
            {
                // Show the command line options
                var go = new GetOption();
                go.SetCommandPrompt("Vectorization options. Press Enter when done");
                go.AcceptNothing(true);
                while (true)
                {
                    conduit.TraceBitmap();
                    doc.Views.Redraw();

                    go.ClearCommandOptions();

                    // IgnoreArea
                    var turdsize_opt = new OptionInteger(Potrace.turdsize, 2, 100);
                    var turdsize_idx = go.AddOptionInteger("FilterSize", ref turdsize_opt, "Filter speckles of up to this size in pixels");

                    // TurnPolicy
                    var turnpolicy_idx = go.AddOptionEnumList("TurnPolicy", Potrace.turnpolicy);

                    // Optimizing
                    var curveoptimizing_opt = new OptionToggle(Potrace.curveoptimizing, "No", "Yes");
                    var curveoptimizing_idx = go.AddOptionToggle("Optimizing", ref curveoptimizing_opt);

                    // Tolerance
                    var opttolerance_opt = new OptionDouble(Potrace.opttolerance, 0.0, 1.0);
                    var opttolerance_idx = go.AddOptionDouble("Tolerance", ref opttolerance_opt, "Optimizing tolerance");

                    // CornerThreshold
                    var alphamax_opt = new OptionDouble(Potrace.alphamax, 0.0, 100.0);
                    var alphamax_idx = go.AddOptionDouble("CornerRounding", ref alphamax_opt, "Corner rounding threshold");

                    // Threshold
                    var threshold_opt = new OptionDouble(Potrace.Treshold, 0.0, 100.0);
                    var threshold_idx = go.AddOptionDouble("Threshold", ref threshold_opt, "Threshold");

                    // RestoreDefaults
                    var defaults_idx = go.AddOption("RestoreDefaults");

                    var res = go.Get();

                    if (res == GetResult.Option)
                    {
                        var option = go.Option();
                        if (null != option)
                        {
                            if (turdsize_idx == option.Index)
                            {
                                Potrace.turdsize = turdsize_opt.CurrentValue;
                            }

                            if (turnpolicy_idx == option.Index)
                            {
                                var list = Enum.GetValues(typeof(TurnPolicy)).Cast <TurnPolicy>().ToList();
                                Potrace.turnpolicy = list[option.CurrentListOptionIndex];
                            }

                            if (curveoptimizing_idx == option.Index)
                            {
                                Potrace.curveoptimizing = curveoptimizing_opt.CurrentValue;
                            }

                            if (opttolerance_idx == option.Index)
                            {
                                Potrace.opttolerance = opttolerance_opt.CurrentValue;
                            }

                            if (alphamax_idx == option.Index)
                            {
                                Potrace.alphamax = alphamax_opt.CurrentValue;
                            }

                            if (threshold_idx == option.Index)
                            {
                                Potrace.Treshold = threshold_opt.CurrentValue;
                            }

                            if (defaults_idx == option.Index)
                            {
                                Potrace.RestoreDefaults();
                            }
                        }
                        continue;
                    }

                    if (res != GetResult.Nothing)
                    {
                        conduit.Enabled = false;
                        doc.Views.Redraw();
                        Potrace.Clear();
                        return(Result.Cancel);
                    }

                    break;
                }
            }

            // Group curves
            var attributes = doc.CreateDefaultAttributes();

            attributes.AddToGroup(doc.Groups.Add());
            for (var i = 0; i < conduit.OutlineCurves.Count; i++)
            {
                var rhobj_id = doc.Objects.AddCurve(conduit.OutlineCurves[i], attributes);
                if (m_select_output)
                {
                    var rhobj = doc.Objects.Find(rhobj_id);
                    if (null != rhobj)
                    {
                        rhobj.Select(true);
                    }
                }
            }

            conduit.Enabled = false;
            Potrace.Clear();
            doc.Views.Redraw();

            // Set the Potrace settings to the plug -in settings file.
            SetPotraceSettings();

            return(Result.Success);
        }
Esempio n. 5
0
 /// <summary>
 /// Trace the bitmap using Potrace.
 /// </summary>
 public void TraceBitmap()
 {
     Clear();
     Potrace.Clear();
     Potrace.Potrace_EtoTrace(m_bitmap, m_path_curves);
 }
Esempio n. 6
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            DA.GetData(0, ref ImgPath);
            int t = 0;

            DA.GetData(1, ref t);
            Potrace.Treshold = (double)t / 100;
            DA.GetData(2, ref Potrace.alphamax);
            int policy = 0;

            DA.GetData(3, ref policy);
            Potrace.turnpolicy = (TurnPolicy)policy;
            DA.GetData(4, ref Potrace.turdsize);

            DA.GetData(5, ref Potrace.curveoptimizing);
            DA.GetData(6, ref Potrace.opttolerance);

            //DA.GetData(7, ref boundary);
            bool inv = false;

            DA.GetData(7, ref inv);
            int count = 0;

            DA.GetData(8, ref count);
            //Read and flip image
            bm = new Bitmap(ImgPath);
            bm.RotateFlip(RotateFlipType.RotateNoneFlipY);
            // convert to argb
            bm = bm.Clone(new Rectangle(0, 0, bm.Width, bm.Height), PixelFormat.Format32bppArgb);
            // get boundary
            int         H        = bm.Height;
            int         W        = bm.Width;
            Rectangle3d boundary = new Rectangle3d(Plane.WorldXY, W, H);

            DataTree <GH_Colour> GC     = new DataTree <GH_Colour>();
            DataTree <Curve>     curves = new DataTree <Curve>();

            if ((int)count < 1)
            {
                // convert png transparent background to white
                var b = new Bitmap(bm.Width, bm.Height);
                b.SetResolution(bm.HorizontalResolution, bm.VerticalResolution);
                using (var g = Graphics.FromImage(b)) {
                    g.Clear(Color.White);
                    g.DrawImageUnscaled(bm, 0, 0);
                }
                List <Curve> crvs = new List <Curve>();
                Potrace.Potrace_Trace(b, crvs, inv);
                curves.AddRange(crvs);
            }
            else
            {
                // quantitize image
                Potrace.Treshold = 0.1;
                var     quantizer = new WuQuantizer();
                Bitmap  quantized = (Bitmap)quantizer.QuantizeImage(bm, count + 1);
                Color[] colors    = new Color[count];
                Array.Copy(quantized.Palette.Entries, 0, colors, 0, count);
                // segment image by color
                // TODO, processing each color in parellel
                if (parallel)
                {
                    for (int i = 0; i < colors.Length; i++)
                    {
                        Bitmap temp   = quantized.Clone(new Rectangle(0, 0, bm.Width, bm.Height), PixelFormat.Format32bppArgb);
                        var    bmData = temp.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

                        unsafe
                        {
                            byte *p           = (byte *)bmData.Scan0;
                            int   stopAddress = (int)p + bmData.Stride * bmData.Height;
                            while ((int)p != stopAddress)
                            {
                                if (p[0] == colors[i].B && p[1] == colors[i].G && p[2] == colors[i].R && p[3] == colors[i].A)
                                {
                                    p[0] = p[1] = p[2] = p[3] = 255;
                                }
                                else
                                {
                                    p[0] = p[1] = p[2] = p[3] = 0;
                                }
                                p += 4;
                            }
                            temp.UnlockBits(bmData);

                            List <Curve> crvs = new List <Curve>();
                            Potrace.Potrace_Trace(temp, crvs, inv);
                            curves.AddRange(crvs, new GH_Path(i));
                            GC.Add(new GH_Colour(colors[i]), new GH_Path(i));
                            Potrace.Clear();
                        }
                    }
                }
                for (int i = 0; i < colors.Length; i++)
                {
                    Bitmap temp   = quantized.Clone(new Rectangle(0, 0, bm.Width, bm.Height), PixelFormat.Format32bppArgb);
                    var    bmData = temp.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

                    unsafe
                    {
                        byte *p           = (byte *)bmData.Scan0;
                        int   stopAddress = (int)p + bmData.Stride * bmData.Height;
                        while ((int)p != stopAddress)
                        {
                            if (p[0] == colors[i].B && p[1] == colors[i].G && p[2] == colors[i].R && p[3] == colors[i].A)
                            {
                                p[0] = p[1] = p[2] = p[3] = 255;
                            }
                            else
                            {
                                p[0] = p[1] = p[2] = p[3] = 0;
                            }
                            p += 4;
                        }
                        temp.UnlockBits(bmData);

                        List <Curve> crvs = new List <Curve>();
                        Potrace.Potrace_Trace(temp, crvs, inv);
                        curves.AddRange(crvs, new GH_Path(i));
                        GC.Add(new GH_Colour(colors[i]), new GH_Path(i));
                        Potrace.Clear();
                    }
                }
            }
            DA.SetDataTree(0, curves);
            DA.SetData(1, boundary);
            DA.SetDataTree(2, GC);
        }
Esempio n. 7
0
 protected override void AfterSolveInstance()
 {
     base.AfterSolveInstance();
     Potrace.Clear();
 }
Esempio n. 8
0
 private void Trace()
 {
     Potrace.Clear();
     ListOfPathes.Clear();
     Potrace.Potrace_Trace(sourceImage, ListOfPathes);
 }