图形绘图库性能对比:GDI+、OpenCV、ImageSharp 与 SkiaSharp
1.除了无界鼠标mouse without borders之外还有什么其他的软件可以两台电脑共享一套键鼠2.Win10&Win11 LTSC老谭酸菜版本如何升级系统?
3.图形绘图库性能对比:GDI+、OpenCV、ImageSharp 与 SkiaSharp
4.windows常用命令在图形处理和绘制任务中,选择合适的图形库对于应用性能至关重要。本文将对比四大流行图形库——GDI+、OpenCV、ImageSharp 和 SkiaSharp——在绘制任务中的性能表现。我们开展了一组相同条件下的性能测试,以全面了解它们在大规模图形绘制中的效率和表现。
代码会贴在最后
测试环境
测试的笔记本电脑CPU为Ultra 7 155H 32G内存。每个库均被用来在 20,000 x 20,000 像素的空白画布上随机绘制大量简单图形。这些图形包括矩形、圆形和三角形,每个图形的大小固定为 50x50 像素。我们主要关注每个库完成任务所需的时间。
平台介绍
1. GDI+
- 概述: GDI+ 是 Windows 平台上的原生图形库,适合 GUI 应用程序的图形处理。
- 应用场景: 适用于需要与 Windows 系统紧密集成的应用,如传统桌面应用程序。
2. OpenCV
- 概述: OpenCV 是一个开源计算机视觉库,但也支持基本的图形绘制功能。
- 应用场景: 适合需要高级图像处理和计算机视觉功能的应用。
3. ImageSharp
- 概述: ImageSharp 是一个跨平台的 .NET 图形处理库,以其简单的 API 和高效的处理能力而闻名。
- 应用场景: 适合需要跨平台图像处理的应用,特别是在图像操作复杂度较高的情况下。
4. SkiaSharp
- 概述: SkiaSharp 是由 Google 开发的 Skia 引擎的 .NET 封装,提供硬件加速的2D图形处理能力。
- 应用场景: 适合需要高性能渲染的应用,如游戏和复杂 UI 应用。
性能对比
GDI Drawing
GDI+ Drawing Nums:160000
GDI+ Drawing finished in 6754 ms.
OpenCV Drawing
OpenCV Drawing Nums:160000
OpenCv Drawing finished in 4663 ms.
ImageSharp Drawing
ImageSharp Drawing Nums:160000
ImageSharp Drawing finished in 19922 ms.
SkiaSharp Drawing
SkiaSharp Drawing Nums:160000
SkiaSharp Drawing finished in 12115 ms.
总结
选择合适的图形库应基于项目的特定需求和目标平台。如需高性能,OpenCV 会是首选;在需要跨平台兼容性时,ImageSharp,SkiaSharp 是不错的选择,而 GDI+ 则适合与 Windows 应用紧密集成的场景。
通过对于这四个图形库的性能对比,我们可以更清晰地根据特定项目需求选择合适的工具,以实现最佳性能和用户体验。
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Numerics;
using OpenCvSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SkiaSharp;
using Color = System.Drawing.Color;
using CvPoint = OpenCvSharp.Point;
using GdiPointF = System.Drawing.PointF;
using GdiPen = System.Drawing.Pen;
using Pens = SixLabors.ImageSharp.Drawing.Processing.Pens;
namespace CSharpApiLearn.StaticMethods;
public class DrawingMethod
{
public static void GDIDrawing()
{
Console.WriteLine("GDI Drawing");
Stopwatch stopwatch = Stopwatch.StartNew();
Bitmap bitmap = new Bitmap(20000, 20000);
using (Graphics g = Graphics.FromImage(bitmap))
{
// 设置高质量绘制
g.SmoothingMode = SmoothingMode.AntiAlias;
// 图形的基础尺寸(这里设置矩形边长、圆形直径、三角形边长都为相同值,可根据需求调整)
int shapeSize = 50;
// 水平和垂直方向的间距(可以设置为0使图形紧密相连,也可根据需求留一点间隔)
int horizontalSpacing = 0;
int verticalSpacing = 0;
// 计算水平方向可容纳的图形数量(考虑间距)
int horizontalCount = (bitmap.Width + horizontalSpacing) / (shapeSize + horizontalSpacing);
// 计算垂直方向可容纳的图形数量(考虑间距)
int verticalCount = (bitmap.Height + verticalSpacing) / (shapeSize + verticalSpacing);
Console.WriteLine($"GDI+ Drawing Nums:{horizontalCount * verticalCount}");
Random random = new Random();
for (int row = 0; row < verticalCount; row++)
{
for (int col = 0; col < horizontalCount; col++)
{
// 随机确定图形类型(0表示矩形,1表示圆形,2表示三角形)
int shapeType = random.Next(3);
// 根据行列计算图形的位置
int x = col * (shapeSize + horizontalSpacing);
int y = row * (shapeSize + verticalSpacing);
if (shapeType == 0)
{
// 绘制矩形
DrawRectangle(g, x, y, shapeSize, shapeSize);
}
else if (shapeType == 1)
{
// 绘制圆形
DrawCircle(g, x + shapeSize / 2, y + shapeSize / 2, shapeSize / 2);
}
else
{
// 绘制三角形
DrawTriangle(g, x, y, shapeSize);
}
}
}
}
bitmap.Save(@"D:\GdiOutput.png", System.Drawing.Imaging.ImageFormat.Png);
Console.WriteLine($"GDI+ Drawing finished in {stopwatch.ElapsedMilliseconds} ms.");
bitmap.Dispose();
}
public static void OpenCvDrawing()
{
Console.WriteLine("OpenCV Drawing");
Stopwatch stopwatch = Stopwatch.StartNew();
Mat image = new Mat(20000, 20000, MatType.CV_8UC4, new Scalar(0, 0, 0, 0));
// 图形的基础尺寸(这里设置矩形边长、圆形直径、三角形边长都为相同值,可根据需求调整)
int shapeSize = 50;
// 水平和垂直方向的间距(可以设置为0使图形紧密相连,也可根据需求留一点间隔)
int horizontalSpacing = 0;
int verticalSpacing = 0;
// 计算水平方向可容纳的图形数量(考虑间距)
int horizontalCount = (image.Cols + horizontalSpacing) / (shapeSize + horizontalSpacing);
// 计算垂直方向可容纳的图形数量(考虑间距)
int verticalCount = (image.Rows + verticalSpacing) / (shapeSize + verticalSpacing);
Console.WriteLine($"OpenCV Drawing Nums:{horizontalCount * verticalCount}");
Random random = new Random();
for (int row = 0; row < verticalCount; row++)
{
for (int col = 0; col < horizontalCount; col++)
{
// 随机确定图形类型(0表示矩形,1表示圆形,2表示三角形)
int shapeType = random.Next(3);
// 根据行列计算图形的位置
int x = col * (shapeSize + horizontalSpacing);
int y = row * (shapeSize + verticalSpacing);
if (shapeType == 0)
{
// 绘制矩形
CvDrawRectangle(image, x, y, shapeSize, shapeSize);
}
else if (shapeType == 1)
{
// 绘制圆形
CvDrawCircle(image, x + shapeSize / 2, y + shapeSize / 2, shapeSize / 2);
}
else
{
// 绘制三角形
CvDrawTriangle(image, x, y, shapeSize);
}
}
}
// 将绘制好的图像保存到D盘(这里指定文件名为output.png,可根据需求修改)
string filePath = @"D:\OpenCvOutput.png";
Cv2.ImWrite(filePath, image);
Console.WriteLine($"OpenCv Drawing finished in {stopwatch.ElapsedMilliseconds} ms.");
image.Dispose();
}
public static void ImageSharpDrawing()
{
Console.WriteLine("ImageSharp Drawing");
Stopwatch stopwatch = Stopwatch.StartNew();
// Create a new image with specified dimensions
using var image = new SixLabors.ImageSharp.Image<Rgba32>(20000, 20000);
// Set up options for drawing (e.g., anti-aliasing)
var drawingOptions = new DrawingOptions() { GraphicsOptions = { Antialias = true } };
// Define the pen
var pen = Pens.Solid(SixLabors.ImageSharp.Color.Black, 2);
// Base shape dimension and spacing
int shapeSize = 50;
int horizontalSpacing = 0;
int verticalSpacing = 0;
// Calculate how many shapes fit in the image dimensions
int horizontalCount = (image.Width + horizontalSpacing) / (shapeSize + horizontalSpacing);
int verticalCount = (image.Height + verticalSpacing) / (shapeSize + verticalSpacing);
Console.WriteLine($"ImageSharp Drawing Nums:{horizontalCount * verticalCount}");
Random random = new Random();
for (int row = 0; row < verticalCount; row++)
{
for (int col = 0; col < horizontalCount; col++)
{
// Determine shape type randomly
int shapeType = random.Next(3);
// Determine positioning
int x = col * (shapeSize + horizontalSpacing);
int y = row * (shapeSize + verticalSpacing);
if (shapeType == 0)
{
// Rectangle
image.Mutate(ctx => ctx.Draw(drawingOptions, pen, new SixLabors.ImageSharp.Rectangle(x, y, shapeSize, shapeSize)));
}
else if (shapeType == 1)
{
// Circle
image.Mutate(ctx => ctx.Draw(drawingOptions, pen, new EllipsePolygon(new Vector2(x + shapeSize / 2, y + shapeSize / 2), shapeSize / 2)));
}
else
{
// Triangle
var triangle = new Polygon(new LinearLineSegment(
new SixLabors.ImageSharp.PointF(x, y),
new SixLabors.ImageSharp.PointF(x + shapeSize, y),
new SixLabors.ImageSharp.PointF(x + shapeSize / 2, y + (float)(shapeSize * Math.Sqrt(3) / 2))
));
image.Mutate(ctx => ctx.Draw(drawingOptions, pen, triangle));
}
}
}
// Save the image
image.SaveAsPng(@"D:\ImageSharpOutput.png");
Console.WriteLine($"ImageSharp Drawing finished in {stopwatch.ElapsedMilliseconds} ms.");
}
public static void SkiaSharpDrawing()
{
Console.WriteLine("SkiaSharp Drawing");
Stopwatch stopwatch = Stopwatch.StartNew();
const int width = 20000;
const int height = 20000;
using var surface = SKSurface.Create(new SKImageInfo(width, height));
var canvas = surface.Canvas;
// Clear the canvas
canvas.Clear(SKColors.White);
// Set up paint
var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2
};
// Base shape dimension and spacing
int shapeSize = 50;
int horizontalSpacing = 0;
int verticalSpacing = 0;
// Calculate how many shapes fit in the image dimensions
int horizontalCount = (width + horizontalSpacing) / (shapeSize + horizontalSpacing);
int verticalCount = (height + verticalSpacing) / (shapeSize + verticalSpacing);
Console.WriteLine($"SkiaSharp Drawing Nums:{horizontalCount * verticalCount}");
Random random = new Random();
for (int row = 0; row < verticalCount; row++)
{
for (int col = 0; col < horizontalCount; col++)
{
// Determine shape type randomly
int shapeType = random.Next(3);
// Determine positioning
int x = col * (shapeSize + horizontalSpacing);
int y = row * (shapeSize + verticalSpacing);
if (shapeType == 0)
{
// Rectangle
canvas.DrawRect(x, y, shapeSize, shapeSize, paint);
}
else if (shapeType == 1)
{
// Circle
canvas.DrawCircle(x + shapeSize / 2, y + shapeSize / 2, shapeSize / 2, paint);
}
else
{
// Triangle
var path = new SKPath();
path.MoveTo(x, y);
path.LineTo(x + shapeSize, y);
path.LineTo(x + shapeSize / 2, y + (int)(shapeSize * Math.Sqrt(3) / 2));
path.Close();
canvas.DrawPath(path, paint);
}
}
}
// Save the image to a file
using var image = surface.Snapshot();
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
using var stream = System.IO.File.OpenWrite(@"D:\SkiaSharpOutput.png");
data.SaveTo(stream);
Console.WriteLine($"SkiaSharp Drawing finished in {stopwatch.ElapsedMilliseconds} ms.");
}
public static void DrawingBenchmark()
{
GDIDrawing();
OpenCvDrawing();
ImageSharpDrawing();
SkiaSharpDrawing();
}
#region GDI+ Tools
private static void DrawRectangle(Graphics g, int x, int y, int width, int height)
{
GdiPen pen = new GdiPen(Color.Black, 2);
g.DrawRectangle(pen, x, y, width, height);
}
private static void DrawCircle(Graphics g, int x, int y, int radius)
{
GdiPen pen = new GdiPen(Color.Black, 2);
g.DrawEllipse(pen, x - radius, y - radius, radius * 2, radius * 2);
}
private static void DrawTriangle(Graphics g, int x, int y, int sideLength)
{
GdiPointF[] points = new GdiPointF[3];
points[0] = new GdiPointF(x, y);
points[1] = new GdiPointF(x + sideLength, y);
points[2] = new GdiPointF(x + sideLength / 2, y + (float)(sideLength * Math.Sqrt(3) / 2));
GdiPen pen = new GdiPen(Color.Black, 2);
g.DrawPolygon(pen, points);
}
#endregion
#region OpenCV Tools
public static void CvDrawRectangle(Mat image, int x, int y, int width, int height)
{
// 设置矩形颜色为黑色(在OpenCV中颜色顺序是BGR,这里用Scalar表示)
Scalar color = new Scalar(0, 0, 0, 255);
// 线宽设为2
int thickness = 2;
Cv2.Rectangle(image, new CvPoint(x, y), new CvPoint(x + width, y + height), color, thickness);
}
public static void CvDrawCircle(Mat image, int x, int y, int radius)
{
Scalar color = new Scalar(0, 0, 0, 255);
int thickness = 2;
Cv2.Circle(image, new CvPoint(x, y), radius, color, thickness);
}
public static void CvDrawTriangle(Mat image, int x, int y, int sideLength)
{
Scalar color = new Scalar(0, 0, 0, 255);
int thickness = 2;
CvPoint[] points = new CvPoint[4];
points[0] = new CvPoint(x, y);
points[1] = new CvPoint(x + sideLength, y);
points[2] = new CvPoint(x + sideLength / 2, y + (int)(sideLength * Math.Sqrt(3) / 2));
points[3] = new CvPoint(x, y);
// 使用FillPoly来绘制填充的多边形(这里是三角形),如果不需要填充,可使用PolyLines并设置合适参数
Cv2.Polylines(image, new CvPoint[][] { points }, false, color, thickness, LineTypes.Link8);
}
#endregion
}
合集:
Windows系统
, DotNet-API
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)