2014-09-19 69 views
3

我想在C#中獲取指定顏色的所有像素(來自ARGB或來自Color類的任何類型)。我的第一個想法是將picturebox內容繪製成Bitmap,然後使用for循環,使用b.GetPixel(x, y);遍歷像素。但是,我使用的PictureBox非常龐大,因此需要花費數百萬/數千萬次的迭代來檢查這個問題,這在性能上不友好。有沒有人有比這更好的解決方案?謝謝從PictureBox獲取指定顏色的所有像素

+2

您正在尋找[Bitmap.Lockbits](http://msdn.microsoft.com/en-us/library/5ey6h79d(v = vs.110).aspx)。 – 2014-09-19 19:46:00

+0

我幾乎沒有看到你如何驗證每個像素,並選擇你想要的,而不檢查每個像素。看起來你被困在O(n)中,除非你使用了一種會降低準確性的啓發式方法(如預測周圍像素)。這就像試圖在不經過每個元素的情況下對一個數組進行計數一樣,你被限制爲O(n),這是不可能的。你可能會發現的選擇可能都是在內部逐個查看每個像素。 – 2014-09-19 19:50:31

+0

您想要處理的圖像有多大?也許使用早先評論中提到的'Lockbits()',並將它與不安全的圖像處理代碼結合起來,可以讓你獲得可以接受的性能,儘管檢查每個像素。 – 2014-09-19 20:45:23

回答

0

我寫了System.Drawing.Image的擴展方法,它遍歷圖像中的每個像素,並返回一個包含每個x/y座標的List作爲System.Drawing.Point。
您可以搜索rgb值或rgba值。
我的方法使用指針,所以你需要爲你的項目啓用不安全的代碼。
與GetPixel(...)相比,使用指針迭代位圖的速度要快很多倍。
在此博客中,GetPixel(...)聲稱比基於指針的解決方案慢1000多倍。
http://davidthomasbernal.com/blog/2008/03/14/c-image-processing-performance-unsafe-vs-safe-code-part-ii/
在使用它之前,您應該正確地測試此代碼,但即使出現錯誤,所顯示的技巧也會讓您開始使用!

using System; 
using System.Collections.Generic; 
using System.Drawing; 
using System.Drawing.Imaging; 

public static class Pixelcounter 
{ 
    private struct PixeldataARGB 
    { 
     public byte b; 
     public byte g; 
     public byte r; 
     public byte a; 
    } 

    private struct PixeldataRGB 
    { 
     public byte b; 
     public byte g; 
     public byte r; 
    } 

    public static IEnumerable<Point> CountOccurences(this Image @this, int r, int g, int b) 
    { 
     if (r < 0 || g < 0 || b < 0) 
      throw new ArgumentException("color values must not be negative"); 
     if (r > 255 || g > 255 || b > 255) 
      throw new ArgumentException("color values must be below 256"); 

     return CountOccurences(@this, (byte)r, (byte)g, (byte)b); 
    } 

    public static unsafe IEnumerable<Point> CountOccurences(this Image @this, byte r, byte g, byte b) 
    { 
     Bitmap bitmap = new Bitmap(@this); 
     BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 
     PixeldataRGB* pointer = (PixeldataRGB*)bitmapData.Scan0; 

     List<Point> pointList = new List<Point>(); 

     for (int y = 0; y < bitmap.Height; y++) 
     { 
      for (int x = 0; x < bitmap.Width; x++) 
      { 
       PixeldataRGB current = *pointer; 
       if (current.r == r && current.g == g && current.b == b) 
        pointList.Add(new Point(x, y)); 
       pointer++; 
      } 
     } 

     bitmap.Dispose(); 

     return pointList; 
    } 

    public static IEnumerable<Point> CountOccurences(this Image @this, int r, int g, int b, int a) 
    { 
     if (r < 0 || g < 0 || b < 0 || a < 0) 
      throw new ArgumentException("color and alpha values must not be negative"); 
     if (r > 255 || g > 255 || b > 255 || a > 255) 
      throw new ArgumentException("color and alpha values must be below 256"); 

     return CountOccurences(@this, (byte)r, (byte)g, (byte)b, (byte)a); 
    } 

    public static unsafe IEnumerable<Point> CountOccurences(this Image @this, byte r, byte g, byte b, byte a) 
    { 
     Bitmap bitmap = new Bitmap(@this); 
     BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
     PixeldataARGB* pointer = (PixeldataARGB*)bitmapData.Scan0; 

     List<Point> pointList = new List<Point>(); 

     for (int y = 0; y < bitmap.Height; y++) 
     { 
      for (int x = 0; x < bitmap.Width; x++) 
      { 
       PixeldataARGB current = *pointer; 
       if (current.r == r && current.g == g && current.b == b && current.a == a) 
        pointList.Add(new Point(x, y)); 
       pointer++; 
      } 
     } 

     bitmap.Dispose(); 

     return pointList; 
    } 
}