2017-12-11 13 views
-1

イメージから透明ピクセルを切り抜くためにこのメソッドを書きました。CropTransparentPixelsメソッドのスピードアップに最適な方法

これは正常に動作するようですが、GetPixelのために非常に遅いです - アルゴリズムのロジックをより速くする方法はありますか?

私はGetPixelを高速(ただし安全ではない)アクセスコードに変更することができますが、そうするかもしれませんが、フルスキャンを避ける方法はあります。このアルゴリズムの背後にあるロジックをより速くする方法についてのアドバイスが必要です。

public Bitmap CropTransparentPixels(Bitmap originalBitmap) 
{ 
    // Find the min/max transparent pixels 
    Point min = new Point(int.MaxValue, int.MaxValue); 
    Point max = new Point(int.MinValue, int.MinValue); 

    for (int x = 0; x < originalBitmap.Width; ++x) 
    { 
     for (int y = 0; y < originalBitmap.Height; ++y) 
     { 
      Color pixelColor = originalBitmap.GetPixel(x, y); 

      if (pixelColor.A == 255) 
      { 
       if (x < min.X) min.X = x; 
       if (y < min.Y) min.Y = y; 

       if (x > max.X) max.X = x; 
       if (y > max.Y) max.Y = y; 
      } 
     } 
    } 

    // Create a new bitmap from the crop rectangle 
    Rectangle cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X, max.Y - min.Y); 
    Bitmap newBitmap = new Bitmap(cropRectangle.Width, cropRectangle.Height); 
    using (Graphics g = Graphics.FromImage(newBitmap)) 
    { 
     g.DrawImage(originalBitmap, 0, 0, cropRectangle, GraphicsUnit.Pixel); 
    } 

    return newBitmap; 
} 
+1

[Bitmap.Get/SetPixel too slow](https://stackoverflow.com/questions/1490000/)の重複が考えられます。 –

+0

'GetPixel'を一切使用しないだけでなく、1ピクセルごとに' GetPixel'を行うのを避ける方法はありますか?私は4つのネストされたループを持っていると思っていましたが、それぞれの最小値と最大値に1つずつ...私はそれを正しくするのにはかなり近いです...私はそれが働くと、この質問を更新します。 –

+1

私は 'Get/SetPixel'を避けることを勧めます。リンクされた記事を読んでください。 –

答えて

1

これは私が書いた方法であり、はるかに高速です。

public static Bitmap CropTransparentPixels(this Bitmap bmp) 
{ 
    BitmapData bmData = null; 

    try 
    { 
     bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

     int scanline = bmData.Stride; 

     IntPtr Scan0 = bmData.Scan0; 

     Point top = new Point(), left = new Point(), right = new Point(), bottom = new Point(); 
     bool complete = false; 

     unsafe 
     { 
      byte* p = (byte*)(void*)Scan0; 

      for (int y = 0; y < bmp.Height; y++) 
      { 
       for (int x = 0; x < bmp.Width; x++) 
       { 
        if (p[3] != 0) 
        { 
         top = new Point(x, y); 
         complete = true; 
         break; 
        } 

        p += 4; 
       } 
       if (complete) 
        break; 
      } 

      p = (byte*)(void*)Scan0; 
      complete = false; 

      for (int y = bmp.Height - 1; y >= 0; y--) 
      { 
       for (int x = 0; x < bmp.Width; x++) 
       { 
        if (p[x * 4 + y * scanline + 3] != 0) 
        { 
         bottom = new Point(x + 1, y + 1); 
         complete = true; 
         break; 
        } 
       } 
       if (complete) 
        break; 
      } 

      p = (byte*)(void*)Scan0; 
      complete = false; 

      for (int x = 0; x < bmp.Width; x++) 
      { 
       for (int y = 0; y < bmp.Height; y++) 
       { 
        if (p[x * 4 + y * scanline + 3] != 0) 
        { 
         left = new Point(x, y); 
         complete = true; 
         break; 
        } 
       } 
       if (complete) 
        break; 
      } 

      p = (byte*)(void*)Scan0; 
      complete = false; 

      for (int x = bmp.Width - 1; x >= 0; x--) 
      { 
       for (int y = 0; y < bmp.Height; y++) 
       { 
        if (p[x * 4 + y * scanline + 3] != 0) 
        { 
         right = new Point(x + 1, y + 1); 
         complete = true; 
         break; 
        } 
       } 
       if (complete) 
        break; 
      } 
     } 

     bmp.UnlockBits(bmData); 

     System.Drawing.Rectangle rectangle = new Rectangle(left.X, top.Y, right.X - left.X, bottom.Y - top.Y); 

     Bitmap b = new Bitmap(rectangle.Width, rectangle.Height); 

     Graphics g = Graphics.FromImage(b); 

     g.DrawImage(bmp, 0, 0, rectangle, GraphicsUnit.Pixel); 

     g.Dispose(); 

     return b; 
    } 
    catch 
    { 
     try 
     { 
      bmp.UnlockBits(bmData); 
     } 
     catch { } 
     return null; 
    } 
} 
関連する問題