【问题标题】:Replacing color with a texture in asp.net core c#在asp.net core c#中用纹理替换颜色
【发布时间】:2018-05-26 17:54:55
【问题描述】:

我一直在尝试使用名为 ImageSharp 的图像处理器,因为 System.Drawing 在 asp.net 核心上不可用,而且 System.Drawing 可能会遇到麻烦。

我想用图像中的特定纹理填充空白。下面的代码正在运行,但速度非常慢。

因为这是我第一次处理图像,我真的不知道最有效的方法是什么。

用纹理填充空白的最佳和有效方法是什么。

结果如下: Doughnut

对此: Sparkly Doughnut

    public void CreateImage()
    {
        var webRoot = _env.WebRootPath;
        var ImgSrc = "\\Images\\SampleImage.png";
        var TextureURL = "\\Images\\Starsinthesky.jpg";
        var file = webRoot + ImgSrc;
        var texture = webRoot + TextureURL;
        var myPath = Path.Combine(webRoot, ImgSrc);

        byte[] img;

        using (Image<Rgba32> image = Image.Load(file))
        {
            HashSet<Texture> textureArr = getRGBaBytes(texture, image);
            for (int h = 0; h <= image.Height; h++)
            {
                for(int w = 0; w <= image.Width; w++)
                {
                    if(image[w,h] == Rgba32.FromHex("#ffffff"))
                    {
                        image[w, h] = textureArr.Where(t => t.x == w && t.y == h).First().color;
                    }
                }
            }
            image.Save("NewImage.png");
        }
    }

    public HashSet<Texture> getRGBaBytes(string textureURL, Image<Rgba32> sample)
    {

        using (Image<Rgba32> tex = Image.Load(textureURL))
        {
            int bitsizelimit = int.MaxValue;    
            if (sample.Width > tex.Width || sample.Height > tex.Height)
            {
                throw new Exception("Texture image dimensions must be greater or equal to sample image");
            }

            HashSet<Texture> myTexture = new HashSet<Texture>();
            for (int h = 0; h <= sample.Height; h++)
            {
                for (int w = 0; w <= sample.Width; w++)
                {
                    System.Diagnostics.Debug.WriteLine($"{tex[w,h].ToHex()} at x:{w} y:{h}");
                    myTexture.Add(new Texture { color = tex[w, h], x = w, y = h });
                }
            }
            return myTexture;
        }
    }

    public class Texture
    {
        public Rgba32 color { get; set; }
        public int x { get; set; }
        public int y { get; set; }
    }

【问题讨论】:

  • 在创建Texture 集合时不要使用HashSet,为什么不直接使用二维数组,基本上你已经在使用它了。这应该有助于你的表现。我打算制作一个测试程序并测试它,但我无法让它在 LinqPad 中运行,抱歉。
  • 另一件可能有帮助的事情是将这条线 Rgba32.FromHex("#ffffff") 提升到你的双重嵌套循环之外。优化器可能会注意到它是一个常量,并且只会执行一次创建,但如果不是,那么您将为图像中的每个像素创建相同的颜色,以便您检查它是否为白色。跨度>

标签: c# image-processing graphics asp.net-core imagesharp


【解决方案1】:

我敲了一个小控制台应用程序来演示实现你想要的东西是多么简单,但首先我会解释为什么你的方法很慢。

  1. getRGBaBytes 不是必需的。您实际上是在遍历两个图像并为纹理图像中的每个像素创建一个类。这是大量的内存分配!
  2. 您在每个像素操作中都有一个 Linq 查询。 WhereFirst。同样,为图像中的每个像素分配大量内存。没必要这样做。
  3. 每次从十六进制值解析时,您都在与新的Rgba32 结构进行比较,这会很慢。这可以改用静态 Rgba32.White 结构来完成。
static void Main(string[] args)
{
    System.IO.Directory.CreateDirectory("output");
    using (var img = Image.Load("LPUVf.png"))
    using (var texture = Image.Load("stars.jpg"))
    {
        if (img.Width >  texture.Width || img.Height > texture.Height)
        {
            throw new InvalidOperationException("Image dimensions must be less than or equal to texture dimensions!");
        }

        for (int y = 0; y < img.Height; y++)
        {
            for (int x = 0; x < img.Width; x++)
            {
                var pixel = img[x, y];
                if (pixel == Rgba32.White)
                {
                    img[x, y] = texture[x, y];
                }
            }
        }

        img.Save("output/LBUVf.png");
    }
}

这是我的示例的输出。 (我想我可能实际上使用了相同的星景图像:))您可以通过测试每个Rgba32 组件是否在255 范围内来改进和减少任何剩余的白色区域,但我会把它留给你。

P.S ImageSharp.Drawing 包包含允许将纹理绘制到多边形的方法。如果您知道每个复合部件的尺寸,理论上您可以从头开始创建新图像。

更新:

我忍不住自己写了一些代码来减少剩余像素。

static void Main(string[] args)
{
    System.IO.Directory.CreateDirectory("output");
    const int min = 128; // Grey midpoint
    using (var img = Image.Load("LPUVf.png"))
    using (var texture = Image.Load("stars.jpg"))
    {
        if (img.Width >  texture.Width || img.Height > texture.Height)
        {
            throw new InvalidOperationException("Image dimensions must be less than or equal to texture dimensions!");
        }

        for (int y = 0; y < img.Height; y++)
        {
            for (int x = 0; x < img.Width; x++)
            {
                var pixel = img[x, y];
                if (pixel.R >= min && pixel.G >= min && pixel.B >= min && pixel.A >= min)
                {
                    img[x, y] = texture[x, y];
                }
            }
        }

        img.Save("output/LBUVf.png");
    }
}

如您所见,这要好得多。

【讨论】:

  • 久经考验。英里更好:D 非常感谢您花时间添加代码以消除锯齿状边缘
  • 别担心,乐于助人:)
猜你喜欢
  • 2011-12-26
  • 1970-01-01
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 2011-10-04
相关资源
最近更新 更多