123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- using Masuit.Tools.Systems;
- using SixLabors.ImageSharp;
- using SixLabors.ImageSharp.PixelFormats;
- using SixLabors.ImageSharp.Processing;
- using Color = System.Drawing.Color;
- // ReSharper disable AccessToDisposedClosure
- namespace Masuit.Tools.Media;
- /// <summary>
- /// 图像边框移除器
- /// </summary>
- public class ImageBorderRemover
- {
- /// <summary>
- /// 容差模式
- /// </summary>
- private ToleranceMode ToleranceMode { get; }
- private int CroppedBorderCount { get; }
- /// <summary>
- ///
- /// </summary>
- /// <param name="mode">容差模式</param>
- /// <param name="croppedBorderCount">达到边框个数则裁剪</param>
- public ImageBorderRemover(ToleranceMode mode, int croppedBorderCount = 2)
- {
- ToleranceMode = mode;
- CroppedBorderCount = croppedBorderCount;
- }
- /// <summary>
- /// 检测图片边框信息(支持多色边框)
- /// </summary>
- /// <param name="imagePath">图片路径</param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>边框检测结果</returns>
- public BorderDetectionResult DetectBorders(string imagePath, int tolerance, int maxLayers = 3, bool useDownscaling = false, int downscaleFactor = 4)
- {
- using var image = Image.Load<Rgba32>(imagePath);
- return DetectBorders(image, tolerance, maxLayers, useDownscaling, downscaleFactor);
- }
- /// <summary>
- /// 检测图片边框信息(从已加载的图像)
- /// </summary>
- /// <param name="image">已加载的图像</param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>边框检测结果</returns>
- public BorderDetectionResult DetectBorders(Image<Rgba32> image, int tolerance, int maxLayers = 3, bool useDownscaling = false, int downscaleFactor = 4)
- {
- var result = new BorderDetectionResult(CroppedBorderCount)
- {
- ImageWidth = image.Width,
- ImageHeight = image.Height,
- BorderColors = new List<Rgba32>(),
- BorderLayers = 0
- };
- byte toleranceValue = (byte)(tolerance * 2.55);
- // 使用多层边框检测算法
- using var clone = image.Clone(c => c.Grayscale());
- var (top, bottom, left, right, layers, colors) = FindContentBordersWithLayers(clone, toleranceValue, maxLayers, useDownscaling, downscaleFactor);
- // 设置内容边界
- result.ContentTop = top;
- result.ContentBottom = bottom;
- result.ContentLeft = left;
- result.ContentRight = right;
- result.BorderLayers = layers;
- result.BorderColors = colors;
- return result;
- }
- /// <summary>
- /// 自动移除图片的多层边框
- /// </summary>
- /// <param name="inputPath">输入图片路径</param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>是否执行了裁剪操作</returns>
- public void RemoveBorders(string inputPath, int tolerance, int maxLayers = 3, bool useDownscaling = false, int downscaleFactor = 4)
- {
- RemoveBorders(inputPath, inputPath, tolerance, maxLayers, useDownscaling, downscaleFactor);
- }
- /// <summary>
- /// 自动移除图片的多层边框
- /// </summary>
- /// <param name="inputPath">输入图片路径</param>
- /// <param name="outputPath">输出图片路径</param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>是否执行了裁剪操作</returns>
- public void RemoveBorders(string inputPath, string outputPath, int tolerance, int maxLayers = 3, bool useDownscaling = false, int downscaleFactor = 4)
- {
- using Image<Rgba32> image = Image.Load<Rgba32>(inputPath);
- var hasCropped = RemoveBorders(image, tolerance, maxLayers, useDownscaling, downscaleFactor);
- // 决定是否保存
- if (hasCropped)
- {
- image.Save(outputPath);
- }
- }
- /// <summary>
- /// 自动移除图片的多层边框
- /// </summary>
- /// <param name="input">输入图片路径</param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>是否执行了裁剪操作</returns>
- public PooledMemoryStream RemoveBorders(Stream input, int tolerance, int maxLayers = 3, bool useDownscaling = false, int downscaleFactor = 4)
- {
- var format = Image.DetectFormat(input);
- input.Seek(0, SeekOrigin.Begin);
- Image<Rgba32> image = Image.Load<Rgba32>(input);
- RemoveBorders(image, tolerance, maxLayers, useDownscaling, downscaleFactor);
- var stream = new PooledMemoryStream();
- image.Save(stream, format);
- return stream;
- }
- /// <summary>
- /// 自动移除图片的多层边框
- /// </summary>
- /// <param name="image"></param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>是否执行了裁剪操作</returns>
- public bool RemoveBorders(Image<Rgba32> image, int tolerance, int maxLayers, bool useDownscaling, int downscaleFactor)
- {
- // 保存原始尺寸用于比较
- int originalWidth = image.Width;
- int originalHeight = image.Height;
- // 使用多层检测方法获取边框信息
- var borderInfo = DetectBorders(image, tolerance, maxLayers, useDownscaling, downscaleFactor);
- bool hasCropped = false;
- if (borderInfo.CanBeCropped)
- {
- int newWidth = borderInfo.ContentRight - borderInfo.ContentLeft + 1;
- int newHeight = borderInfo.ContentBottom - borderInfo.ContentTop + 1;
- if (newWidth > 0 && newHeight > 0 && (newWidth != originalWidth || newHeight != originalHeight))
- {
- image.Mutate(x => x.Crop(new Rectangle(borderInfo.ContentLeft, borderInfo.ContentTop, newWidth, newHeight)));
- hasCropped = true;
- }
- }
- return hasCropped;
- }
- /// <summary>
- /// 查找内容边界(支持多层边框检测)
- /// </summary>
- private (int top, int bottom, int left, int right, int layers, List<Rgba32> colors) FindContentBordersWithLayers(Image<Rgba32> image, byte tolerance, int maxLayers, bool useDownscaling, int downscaleFactor)
- {
- // 如果启用缩小采样且图像足够大
- Image<Rgba32> workingImage;
- float scale = 1f;
- bool isDownscaled = false;
- if (useDownscaling && image.Width > 500 && image.Height > 500)
- {
- // 计算缩小尺寸
- int newWidth = image.Width / downscaleFactor;
- int newHeight = image.Height / downscaleFactor;
- scale = (float)image.Width / newWidth;
- // 创建缩小版本用于检测
- workingImage = image.Clone(ctx => ctx.Resize(newWidth, newHeight));
- isDownscaled = true;
- }
- else
- {
- workingImage = image;
- }
- int width = workingImage.Width;
- int height = workingImage.Height;
- int top = 0;
- int bottom = height - 1;
- int left = 0;
- int right = width - 1;
- int layers = 0;
- var borderColors = new List<Rgba32>();
- // 检测多层边框
- for (int layer = 0; layer < maxLayers; layer++)
- {
- bool borderFound = false;
- // 并行检测四个方向的边框层
- var results = new (int borderSize, Rgba32? color)[4];
- Parallel.Invoke(() =>
- {
- if (top < height / 2)
- {
- Rgba32? layerColor = null;
- int newTop = DetectLayerBorderTop(workingImage, top, bottom, left, right, tolerance, ref layerColor);
- results[0] = (newTop - top, layerColor);
- if (newTop > top) borderFound = true;
- top = newTop;
- }
- }, () =>
- {
- if (bottom > height / 2)
- {
- Rgba32? layerColor = null;
- int newBottom = DetectLayerBorderBottom(workingImage, top, bottom, left, right, tolerance, ref layerColor);
- results[1] = (newBottom - bottom, layerColor);
- if (newBottom < bottom) borderFound = true;
- bottom = newBottom;
- }
- }, () =>
- {
- if (left < width / 2)
- {
- Rgba32? layerColor = null;
- int newLeft = DetectLayerBorderLeft(workingImage, top, bottom, left, right, tolerance, ref layerColor);
- results[2] = (newLeft - left, layerColor);
- if (newLeft > left) borderFound = true;
- left = newLeft;
- }
- }, () =>
- {
- if (right > width / 2)
- {
- Rgba32? layerColor = null;
- int newRight = DetectLayerBorderRight(workingImage, top, bottom, left, right, tolerance, ref layerColor);
- results[3] = (newRight - right, layerColor);
- if (newRight < right) borderFound = true;
- right = newRight;
- }
- });
- // 收集检测到的边框颜色
- foreach (var (borderSize, color) in results)
- {
- if (color.HasValue && borderSize > 0)
- {
- borderColors.Add(color.Value);
- }
- }
- if (borderFound)
- {
- layers++;
- }
- else
- {
- break; // 没有检测到更多边框层
- }
- }
- // 如果是缩小采样版本,映射回原图坐标
- if (isDownscaled)
- {
- top = (int)(top * scale);
- bottom = (int)(bottom * scale);
- left = (int)(left * scale);
- right = (int)(right * scale);
- // 确保边界在图像范围内
- top = Clamp(top, 0, image.Height - 1);
- bottom = Clamp(bottom, top, image.Height - 1);
- left = Clamp(left, 0, image.Width - 1);
- right = Clamp(right, left, image.Width - 1);
- // 释放缩小图像
- workingImage.Dispose();
- }
- return (top, bottom, left, right, layers, borderColors);
- }
- private static int Clamp(int value, int min, int max)
- {
- return value < min ? min : value > max ? max : value;
- }
- /// <summary>
- /// 检测顶部边框层(优化版)
- /// </summary>
- private int DetectLayerBorderTop(Image<Rgba32> image, int currentTop, int currentBottom, int currentLeft, int currentRight, byte tolerance, ref Rgba32? borderColor)
- {
- int newTop = currentTop;
- Rgba32? detectedColor = null;
- // 使用采样检测代替全行扫描
- int sampleCount = Math.Min(50, currentRight - currentLeft + 1);
- int stepX = Math.Max(1, (currentRight - currentLeft) / sampleCount);
- // 从当前顶部开始向下扫描
- for (int y = currentTop; y <= currentBottom; y++)
- {
- Rgba32? rowColor = null;
- bool isUniform = true;
- // 采样检查行是否统一颜色
- for (int x = currentLeft; x <= currentRight; x += stepX)
- {
- if (!rowColor.HasValue)
- {
- rowColor = image[x, y];
- continue;
- }
- if (!IsSimilarColor(image[x, y], rowColor.Value, tolerance))
- {
- isUniform = false;
- break;
- }
- }
- // 如果是统一颜色行
- if (isUniform && rowColor.HasValue)
- {
- // 第一行总是被认为是边框
- if (y == currentTop)
- {
- detectedColor = rowColor;
- newTop = y + 1;
- continue;
- }
- // 后续行必须与第一行颜色相似
- if (detectedColor.HasValue && IsSimilarColor(rowColor.Value, detectedColor.Value, tolerance))
- {
- newTop = y + 1;
- }
- else
- {
- break;
- }
- }
- else
- {
- break;
- }
- }
- if (newTop > currentTop)
- {
- borderColor = detectedColor;
- return newTop;
- }
- return currentTop;
- }
- /// <summary>
- /// 检测底部边框层(优化版)
- /// </summary>
- private int DetectLayerBorderBottom(Image<Rgba32> image, int currentTop, int currentBottom, int currentLeft, int currentRight, byte tolerance, ref Rgba32? borderColor)
- {
- int newBottom = currentBottom;
- Rgba32? detectedColor = null;
- // 使用采样检测代替全行扫描
- int sampleCount = Math.Min(50, currentRight - currentLeft + 1);
- int stepX = Math.Max(1, (currentRight - currentLeft) / sampleCount);
- // 从当前底部开始向上扫描
- for (int y = currentBottom; y >= currentTop; y--)
- {
- Rgba32? rowColor = null;
- bool isUniform = true;
- // 采样检查行是否统一颜色
- for (int x = currentLeft; x <= currentRight; x += stepX)
- {
- if (!rowColor.HasValue)
- {
- rowColor = image[x, y];
- continue;
- }
- if (!IsSimilarColor(image[x, y], rowColor.Value, tolerance))
- {
- isUniform = false;
- break;
- }
- }
- if (isUniform && rowColor.HasValue)
- {
- if (y == currentBottom)
- {
- detectedColor = rowColor;
- newBottom = y - 1;
- continue;
- }
- if (detectedColor.HasValue && IsSimilarColor(rowColor.Value, detectedColor.Value, tolerance))
- {
- newBottom = y - 1;
- }
- else
- {
- break;
- }
- }
- else
- {
- break;
- }
- }
- if (newBottom < currentBottom)
- {
- borderColor = detectedColor;
- return newBottom;
- }
- return currentBottom;
- }
- /// <summary>
- /// 检测左侧边框层(优化版)
- /// </summary>
- private int DetectLayerBorderLeft(Image<Rgba32> image, int currentTop, int currentBottom, int currentLeft, int currentRight, byte tolerance, ref Rgba32? borderColor)
- {
- int newLeft = currentLeft;
- Rgba32? detectedColor = null;
- // 使用采样检测代替全列扫描
- int sampleCount = Math.Min(50, currentBottom - currentTop + 1);
- int stepY = Math.Max(1, (currentBottom - currentTop) / sampleCount);
- // 从当前左侧开始向右扫描
- for (int x = currentLeft; x <= currentRight; x++)
- {
- Rgba32? colColor = null;
- bool isUniform = true;
- // 采样检查列是否统一颜色
- for (int y = currentTop; y <= currentBottom; y += stepY)
- {
- if (!colColor.HasValue)
- {
- colColor = image[x, y];
- continue;
- }
- if (!IsSimilarColor(image[x, y], colColor.Value, tolerance))
- {
- isUniform = false;
- break;
- }
- }
- if (isUniform && colColor.HasValue)
- {
- if (x == currentLeft)
- {
- detectedColor = colColor;
- newLeft = x + 1;
- continue;
- }
- if (detectedColor.HasValue && IsSimilarColor(colColor.Value, detectedColor.Value, tolerance))
- {
- newLeft = x + 1;
- }
- else
- {
- break;
- }
- }
- else
- {
- break;
- }
- }
- if (newLeft > currentLeft)
- {
- borderColor = detectedColor;
- return newLeft;
- }
- return currentLeft;
- }
- /// <summary>
- /// 检测右侧边框层(优化版)
- /// </summary>
- private int DetectLayerBorderRight(Image<Rgba32> image, int currentTop, int currentBottom, int currentLeft, int currentRight, byte tolerance, ref Rgba32? borderColor)
- {
- int newRight = currentRight;
- Rgba32? detectedColor = null;
- // 使用采样检测代替全列扫描
- int sampleCount = Math.Min(50, currentBottom - currentTop + 1);
- int stepY = Math.Max(1, (currentBottom - currentTop) / sampleCount);
- // 从当前右侧开始向左扫描
- for (int x = currentRight; x >= currentLeft; x--)
- {
- Rgba32? colColor = null;
- bool isUniform = true;
- // 采样检查列是否统一颜色
- for (int y = currentTop; y <= currentBottom; y += stepY)
- {
- if (!colColor.HasValue)
- {
- colColor = image[x, y];
- continue;
- }
- if (!IsSimilarColor(image[x, y], colColor.Value, tolerance))
- {
- isUniform = false;
- break;
- }
- }
- if (isUniform && colColor.HasValue)
- {
- if (x == currentRight)
- {
- detectedColor = colColor;
- newRight = x - 1;
- continue;
- }
- if (detectedColor.HasValue && IsSimilarColor(colColor.Value, detectedColor.Value, tolerance))
- {
- newRight = x - 1;
- }
- else
- {
- break;
- }
- }
- else
- {
- break;
- }
- }
- if (newRight < currentRight)
- {
- borderColor = detectedColor;
- return newRight;
- }
- return currentRight;
- }
- /// <summary>
- /// 颜色相似度比较(SIMD优化)
- /// </summary>
- private bool IsSimilarColor(Rgba32 color1, Rgba32 color2, byte tolerance)
- {
- switch (ToleranceMode)
- {
- case ToleranceMode.Channel:
- return CompareColors(color1, color2, tolerance, true);
- case ToleranceMode.DeltaE2000:
- return Color.FromArgb(color1.A, color1.R, color1.G, color1.B).CIE2000(Color.FromArgb(color2.A, color2.R, color2.G, color2.B)) <= tolerance;
- case ToleranceMode.DeltaE1976:
- return Color.FromArgb(color1.A, color1.R, color1.G, color1.B).CIE1976(Color.FromArgb(color2.A, color2.R, color2.G, color2.B)) <= tolerance;
- case ToleranceMode.DeltaE1994:
- return Color.FromArgb(color1.A, color1.R, color1.G, color1.B).CIE1994(Color.FromArgb(color2.A, color2.R, color2.G, color2.B)) <= tolerance;
- case ToleranceMode.DeltaECMC:
- return Color.FromArgb(color1.A, color1.R, color1.G, color1.B).CMC(Color.FromArgb(color2.A, color2.R, color2.G, color2.B)) <= tolerance;
- case ToleranceMode.EuclideanDistance:
- return CompareWithEuclideanDistance(color1, color2, tolerance, true);
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- /// <summary>
- /// 比较两个颜色是否在容差范围内相等
- /// </summary>
- /// <param name="color1">第一个颜色</param>
- /// <param name="color2">第二个颜色</param>
- /// <param name="tolerance">容差值 (0-255)</param>
- /// <param name="compareAlpha">是否比较Alpha通道</param>
- /// <returns>是否匹配</returns>
- private static bool CompareColors(Rgba32 color1, Rgba32 color2, int tolerance = 10, bool compareAlpha = false)
- {
- // 检查R通道
- if (Math.Abs(color1.R - color2.R) > tolerance)
- return false;
- // 检查G通道
- if (Math.Abs(color1.G - color2.G) > tolerance)
- return false;
- // 检查B通道
- if (Math.Abs(color1.B - color2.B) > tolerance)
- return false;
- // 可选检查Alpha通道
- if (compareAlpha && Math.Abs(color1.A - color2.A) > tolerance)
- return false;
- return true;
- }
- /// <summary>
- /// 使用欧几里得距离比较颜色
- /// </summary>
- /// <param name="color1">第一个颜色</param>
- /// <param name="color2">第二个颜色</param>
- /// <param name="maxDistance">最大允许距离 (0-442之间)</param>
- /// <param name="compareAlpha">是否包含Alpha通道</param>
- /// <returns>是否匹配</returns>
- private static bool CompareWithEuclideanDistance(Rgba32 color1, Rgba32 color2, double maxDistance = 20.0, bool compareAlpha = false)
- {
- // 计算各分量平方差之和
- double sum = Math.Pow(color1.R - color2.R, 2) + Math.Pow(color1.G - color2.G, 2) + Math.Pow(color1.B - color2.B, 2);
- // 可选添加Alpha通道
- if (compareAlpha)
- {
- sum += Math.Pow(color1.A - color2.A, 2);
- }
- // 计算欧几里得距离
- double distance = Math.Sqrt(sum);
- return distance <= maxDistance;
- }
- }
- public static class ImageBorderRemoverExt
- {
- /// <summary>
- /// 检测图片边框信息(从已加载的图像)
- /// </summary>
- /// <param name="image">已加载的图像</param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="toleranceMode">容差模式</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>边框检测结果</returns>
- public static BorderDetectionResult DetectBorders(this Image<Rgba32> image, int tolerance, ToleranceMode toleranceMode, int maxLayers = 3, bool useDownscaling = false, int downscaleFactor = 4)
- {
- var remover = new ImageBorderRemover(toleranceMode);
- return remover.DetectBorders(image, tolerance, maxLayers, useDownscaling, downscaleFactor);
- }
- /// <summary>
- /// 自动移除图片的多层边框(仅当至少有两边存在边框时才裁剪)
- /// </summary>
- /// <param name="image"></param>
- /// <param name="tolerance">颜色容差(0-100),通道模式建议10,ΔE模式建议1-10,欧几里德模式建议(0-442之间)</param>
- /// <param name="toleranceMode">容差模式</param>
- /// <param name="maxLayers">最大检测边框层数,默认3</param>
- /// <param name="cropBorderCount">最少边框数</param>
- /// <param name="useDownscaling">是否使用缩小采样优化性能,默认false,开启可能会导致图片过多裁剪</param>
- /// <param name="downscaleFactor">缩小采样比例(1-10),默认4</param>
- /// <returns>是否执行了裁剪操作</returns>
- public static bool RemoveBorders(this Image<Rgba32> image, int tolerance, ToleranceMode toleranceMode, int maxLayers = 3, int cropBorderCount = 2, bool useDownscaling = false, int downscaleFactor = 4)
- {
- var remover = new ImageBorderRemover(toleranceMode, cropBorderCount);
- return remover.RemoveBorders(image, tolerance, maxLayers, useDownscaling, downscaleFactor);
- }
- }
|