2017-12-12 7 views
1

私はImageSharpというイメージプロセッサを試していました。なぜなら、System.Drawingはasp.netコアでは使用できず、System.Drawingには不具合があります。asp.netコアのテクスチャと色を入れ替えるC#

空白を画像の特定のテクスチャで塗りつぶしたい。以下のコードは動作していますが、痛いほど遅いです。

これは初めて画像を処理するため、これを行う最も効率的な方法が実際にはわかりません。

空白にテクスチャを塗りつぶすには、どのような方法が最適です。これに 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; } 
    } 
+0

は、あなたは基本的にはすでになどの使用しています。それはあなたのパフォーマンスを助けるはずです。私はテストプログラムを作ってこれをテストしようとしていましたが、LinqPadで実行することはできません。 – pstrjds

+0

もう一つは、この行 'Rgba32.FromHex("#ffffff ")'を二重にネストされたループの外側に進めることです。オプティマイザはそれが定数であることに気づき、作成を1回しか実行しませんが、そうでない場合、イメージのすべてのピクセルに同じ色を作成しているので、白であるかどうかを確認できます。 – pstrjds

答えて

2

を私はそれはあなたが望むものを達成するのがいかに簡単で実証する小さなコンソールアプリケーションをノックしたが、最初に私は理由を説明しますあなたのアプローチは遅いです。

  1. getRGBaBytesは必須ではありません。基本的には、両方のイメージをループして、テクスチャイメージ内の各ピクセルのクラスを作成しています。それはたくさんのメモリ割り当てです!
  2. 各ピクセル操作内にLinqクエリがあります。 WhereおよびFirst。ここでも、イメージ内の各ピクセルの大量のメモリ割り当て。これは必要ありません。
  3. 新しいRgba32構造体との比較は、遅くなる16進値から解析するたびに行われます。これは、代わりにstatic 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の範囲内にあるかどうかをテストすることで、残りの白い部分を改善し、減らすことができます。

Sample output

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"); 
    } 
} 

これははるかに良いです。代わりに、あなただけの2次元配列を使用しない理由は、 `Texture`コレクションを、作成しているとき` HashSet`を使用しての

Updated sample with better result

+1

試してテストしました。マイルの方が良い:D そしてギザギザのエッジを取り除くコードを追加していただきありがとうございます – CyanideHavik

+0

心配しないでください。 –

関連する問題