图像矢量化 – 工作流程 – .NET

本文介绍如何使用 Aspose.SVG API 将位图转换为矢量图形。您将找到图像矢量化过程的描述;使用矢量化算法和选项,了解如何将 PNG、JPG、BMP、TIFF、GIF、ICO 等光栅图像矢量化为 SVG 文档。

Aspose.SVG 提供免费的在线 图像矢量化器,它基于浏览器并可在任何平台上运行。使用此应用程序,您可以应用一组选项来获得完美的结果。节省您的时间并检查这个免费的图像矢量化器以获得矢量图形的所有好处!

文本“横幅图像矢量化器”

什么是图像矢量化?

矢量化的任务是将 2D 图像转换为图像的 2D 矢量表示。二维矢量图形是表示为数学曲线的计算机图形图像。此类矢量图像被定义为由直线和曲线连接以形成所需形状的笛卡尔点。光栅图像是一组像素。如果是RGB图像,则可以表示为颜色像素表。每个像素都是 8 位整数值的三元组,其中每个值代表红色、绿色和蓝色的数量。

图像矢量化是将光栅图像转换为矢量图形(贝塞尔曲线、样条曲线和直线)的过程。

光栅到矢量转换的源图像可以接受位图格式,例如 JPG、TIFF、BMP、GIF 和 PNG。输出图像是矢量文件格式,例如SVG文件格式。地图、图标、徽标、技术图纸和剪贴画等图像适合矢量化。这些图像基于几何形状并用简单的曲线绘制。

图像矢量化有什么用?

缩放比例和尺寸。光栅图像是基于像素的,因此它们与分辨率相关。图像质量取决于构成图像的像素数量以及决定每英寸显示多少像素的分辨率值。因此,图像中的像素越多、分辨率越高,图像质量就越高。例如,在不更改分辨率的情况下缩放位图以放大它会降低质量并显得模糊或像素化。这是因为像素被拉伸到更大的区域,使得它们不那么清晰。 与位图图形不同,矢量图像可以调整大小和缩放,而不会损失任何质量,并且它们仍然可以清晰地显示。换句话说,矢量图形比光栅图形具有独特的优势,因为点、线和曲线可以按比例放大或缩小,而不会降低质量。

安全和隐私。有时有必要保护图像免受人脸识别等图像识别技术的影响。矢量化图像更能抵抗此类攻击,因为图像识别器通常是面向像素的。

图像恢复。矢量化可用于更新或恢复图像。

图像矢量化过程

图像矢量化过程包括以下步骤:

颜色量化和调整大小。颜色量化或彩色图像量化是应用于颜色空间的量化。这是一个减少图像中使用的不同颜色数量的过程,目的是使新图像在视觉上尽可能与原始图像相似。在我们的图像矢量化过程中,颜色量化起着重要作用,因为它减少了使用的颜色数量,而颜色数量显着影响矢量化 SVG 的大小和质量。 当图像很大或者包含很多小的相同颜色的点或像素时,我们调整它的大小以防止SVG文档太大。

轮廓追踪。轮廓追踪或边界追踪是一种应用于数字图像以提取非单色图像的边界的技术。有几种这样的技术,如 Suzuki-Abe、Moore-neighbor、Square Tracing Algorithm、Theo Pavlidis’ Algorithm 等。不幸的是,这些算法适用于单色图像,而适用于多色图像则效果不佳。因此,我们开发了一种新的轮廓跟踪算法,可以快速准确地处理多色图像,并显着减少轮廓数量。

轨迹平滑(此步骤是可选的)。有时轮廓片段看起来像锯齿波,因为矢量化图像的分辨率不够高,或者图像中存在噪声。为了平滑,这些曲线可以使用多种方法,如局部线性回归、局部多项式回归、高斯核等……我们发现,借助最近邻方法可以实现完美的结果,该方法在 [ImageTraceSmoother 中实现】(三)课。

跟踪简化(可选)。这一步需要将由线段组成的轨迹曲线抽取为点数更少的相似曲线。有不同的算法,如 Ramer–Douglas–Peucker、Visvalingam–Whyatt、Reumann–Witkam 等,可用于解决此任务。我们在 ImageTraceSimplifier 类中实现了 Ramer–Douglas–Peucker 方法,因为它在我们的实验中显示出比其他方法更好的结果,但我们声明了 IImageTraceSimplifier 接口来实现任何其他方法。

从痕迹构建 SVG 路径元素。最后一步是将跟踪点转换为 SVG 路径线和贝塞尔曲线,并将它们添加到 SVG 文档中。为了拟合穿过每个跟踪点的曲线,我们使用 Catmull-Roma 样条线,该样条线会转换为贝塞尔曲线。

矢量化选项

您可以使用默认或自定义配置选项将光栅图像转换为矢量图形。您将能够应用自定义设置以获得图像到矢量转换的最佳结果,并将输出 SVG 文件保存到您的计算机。处理假定控制以下属性:

PropertyDescription
ColorsLimitThis property gets or sets the maximum number of colors used to quantize an image. The default value is 25.
ImageSizeLimitGets or sets maximal dimension of an image determined by multiplication image width and height. The size of the image will be scaled based on this property. The default value is 1800000.
PathBuilderThis property sets the SVG path segments builder and affects how sharply the curve bends at the control points.
TraceSimplifierThe property sets the trace simplified. As a result, the trace curve will be built composed of line segments with fewer (or bigger) points.
TraceSmootherThis property sets the trace smoother. It is used to smooth out fragments of contours.

C# 示例

Aspose.HTML API 提供了 ImageVectorization 命名空间,它实现了各种类,这些类允许实现一组用于图像矢量化过程的算法。提供的类和方法使您能够在将图像保存为矢量格式之前使用多个矢量化选项来预处理图像。

注意: Aspose.SVG API 旨在实现图像矢量化任务,因此源图像到光栅到矢量的转换可能接受位图格式,例如 JPGPNGBMPTIFFGIF 等。输出图像是矢量 SVG 文件格式。

要使用 Aspose.SVG 对图像进行矢量化,您应该遵循以下几个步骤:

  1. 初始化 ImageVectorizer 类的实例。使用 ImageVectorizer() 构造函数之一并指定配置属性。
  2. 对指定文件中的光栅图像进行矢量化。使用返回 SVGDocumentVectorize() 方法。
  3. 将 SVGDocument(矢量化图像)另存为 SVG 文件。

以下是如何使用 Aspose.SVG API 对 PNG 图像进行矢量化的 C# 示例。

 1using System.IO;
 2using Aspose.Svg.ImageVectorization;
 3using Aspose.Svg.Saving;
 4...
 5
 6    // Initialize an instance of the ImageVectorizer class
 7    var vectorizer = new ImageVectorizer
 8    {
 9        // Optionally set configuration
10        Configuration =
11        {
12            // Optionally set path builder
13            PathBuilder = new BezierPathBuilder {
14            // Optionally set trace smoother
15            TraceSmoother = new ImageTraceSmoother(2),
16            },
17            ColorsLimit = 10,
18            LineWidth = 1
19        }
20    };
21    // Vectorize image from the specified file
22    using var document = vectorizer.Vectorize(Path.Combine(DataDir, "png-to-svg.png"));
23
24    // Save vectorized Image as SVG file 
25    document.Save(Path.Combine(OutputDir, "png-to-svg.svg"));

您可以通过链接查看源文件和最终结果 – png-to-svg.pngpng-to-svg.svg

您可以在 图像矢量化示例 文章中找到应用矢量化选项的描述和 C# 示例。

IImageTraceSimplifier 实现示例

ImageVectorization 命名空间包括 IImageTraceSimplifierIImageTraceSmootherIPathBuilder 接口,用于实现您的任何方法和算法。让我们考虑基于 Viswalingam 算法的 IImageTraceSimplifier 实现:

  1	struct Point3
  2    {
  3        public float X { get; set; }
  4        public float Y { get; set; }
  5        public float? Z { get; set; }
  6        public Point3(float x, float y, float? z)
  7        {
  8            X = x;
  9            Y = y;
 10            Z = z;
 11        }
 12    }
 13
 14    internal class Visvalingam: IImageTraceSimplifier
 15    {
 16        Point3[] line;
 17        List<int> indizes;
 18        bool enriched;
 19        float tolerance;
 20
 21        public Visvalingam(float tolerance)
 22        {
 23            this.tolerance = tolerance;
 24        }
 25
 26        // Calculate the area of one triangle       	
 27        private float GetTriangleArea(Point3 a, Point3 b, Point3 c)
 28		{
 29            return Math.Abs((a.X * (b.Y - c.Y) + b.X * (c.Y - a.Y) + c.X * (a.Y - b.Y)) / 2f);
 30        }
 31
 32        // Add the area of the triangle to each point
 33        private float EnrichPoints()
 34		{
 35            var minArea = float.PositiveInfinity;
 36
 37            for (var i = 1; i < indizes.Count() - 1; i++)
 38            {
 39                var @this = indizes[i];
 40                var prev = indizes[i - 1];
 41                var next = indizes[i + 1];
 42				
 43                var area = GetTriangleArea(line[prev], line[@this], line[next]);
 44
 45                // Reset minim value for area, if current is smaller than all previous
 46                if (area < minArea)
 47
 48                    minArea = area;
 49
 50                // Save the area of the triangle as 3rd coordinate
 51                // Replace if it does exist already
 52                line[@this].Z = area;
 53            }
 54            return minArea;
 55        }
 56
 57        // Check for the smallest triangles and remove corresponding points from the index
 58        private void RemoveSmallestAreaIndex(float minArea)
 59        {
 60            var newIndizes = new List<int>();
 61            newIndizes.Add(indizes[0]);
 62			
 63            for (var i = 1; i < indizes.Count - 1; i++)
 64            {
 65                var index = indizes[i];
 66
 67                if (line[index].Z > minArea)
 68
 69                    newIndizes.Add(index);
 70            }
 71
 72            newIndizes.Add(indizes[indizes.Count - 1]);
 73            indizes = newIndizes;
 74
 75            // Return newIndizes
 76        }
 77
 78        // Do Visvalingam-Calculations until only start-& endpoint are left
 79        private void EnrichLineString()
 80        {
 81            while (indizes.Count > 2)
 82
 83                RemoveSmallestAreaIndex(EnrichPoints());
 84
 85            enriched = true;
 86        }
 87
 88        // Simplify a linestring corresponding to a given tolerance (depends on projection of data)
 89
 90        public IEnumerable<PointF> Simplify(IEnumerable<PointF> trace)
 91        {
 92            line = trace.Select(pt => new Point3(pt.X, pt.Y, null)).ToArray();
 93            indizes = line.Select((v, i) => i).ToList();
 94            enriched = false;
 95
 96            // It is enough to enrich the line once
 97            if (enriched == false)
 98			
 99                EnrichLineString();
100
101            // Build the new line
102            return line.Where(p => p.Z != null && (p.Z > tolerance) || p.Z == null)
103
104                .Select(p => new PointF(p.X, p.Y));
105        }
106    }

您可以从 GitHub 下载完整的 C# 示例和数据文件。关于从 GitHub 下载并运行示例,您可以从 如何运行示例 部分找到。

Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.