在 asp.net 核心 c# 中用纹理替换颜色
Replacing color with a texture in asp.net core c#
我一直在一个名为 ImageSharp 的图像处理器上进行试验,因为 System.Drawing 在 asp.net 内核上不可用,并且 System.Drawing 可能会有问题。
我想用图像中的特定纹理填充白色space。下面的代码正在运行,但速度非常慢。
因为这是我第一次处理图像,所以我真的不知道这样做最有效的方法是什么。
用纹理填充白色 space 的最佳和有效方法是什么。
结果如下:
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; }
}
我敲了一个小控制台应用程序来演示实现您想要的是多么简单,但首先我会解释为什么您的方法很慢。
getRGBaBytes
不是必需的。您实际上是在遍历两个图像并为纹理图像中的每个像素创建一个 class。那是很多内存分配!
- 您在每个像素操作中都有一个 Linq 查询。
Where
和 First
。同样,为图像中的每个像素分配大量内存。不需要这个。
- 每次从十六进制值解析时,您都在与新的
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");
}
}
如您所见,这要好得多。
我一直在一个名为 ImageSharp 的图像处理器上进行试验,因为 System.Drawing 在 asp.net 内核上不可用,并且 System.Drawing 可能会有问题。
我想用图像中的特定纹理填充白色space。下面的代码正在运行,但速度非常慢。
因为这是我第一次处理图像,所以我真的不知道这样做最有效的方法是什么。
用纹理填充白色 space 的最佳和有效方法是什么。
结果如下: 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; }
}
我敲了一个小控制台应用程序来演示实现您想要的是多么简单,但首先我会解释为什么您的方法很慢。
getRGBaBytes
不是必需的。您实际上是在遍历两个图像并为纹理图像中的每个像素创建一个 class。那是很多内存分配!- 您在每个像素操作中都有一个 Linq 查询。
Where
和First
。同样,为图像中的每个像素分配大量内存。不需要这个。 - 每次从十六进制值解析时,您都在与新的
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");
}
}
如您所见,这要好得多。