圖片逐像素處理的速度比較
這篇文章將介紹對圖片進行逐個像素的處理時的方法,由於方法的不同將會造成處理的速度的巨大區別。
以下通過一個例子來說明各種方法的處理速度:
我們將一幅200×266像素的圖片每個像素的RGB顏色中的R分量減少100,減少後小於0的按0計算。如圖所示將圖1轉變成圖2。
[1] [2]
1. 使用Bitmap的GetPixel和SetPixel方法訪問
public static Bitmap ProcessByPixel(Bitmap src)
{
Bitmap rs = new Bitmap(src.Width, src.Height);
for (int i = 0; i < src.Width; i++)
{
for (int j = 0; j < src.Height; j++)
{
//在這裏對圖片進行處理
Color color = src.GetPixel(i, j);
int red = (color.R - 100 < 0) ? 0 : color.R - 100;
color = Color.FromArgb(red, color.G, color.B);
rs.SetPixel(i, j, color);
}
}
return rs;
}
這種方法通過使用Bitmap類的GetPixel方法獲得各點的像素顏色,處理後又通過SetPixel方法設置目標圖片各點的像素顏色。
2. 使用指針訪問
( http://www.codeproject.com/cs/media/csharpgraphicfilters11.asp )
public static Bitmap ProcessByPointer(Bitmap src)
{
Bitmap rs = (Bitmap)src.Clone(); //Bitmap rs = src;
BitmapData data = rs.LockBits(new Rectangle(0, 0, src.Width, src.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)data.Scan0;
int offset = data.Stride - src.Width * 4;
int pixel;
for (int i = 0; i < src.Height; i++)
{
for (int j = 0; j < src.Width; j++)
{
//在這裏對圖片進行處理
pixel = p[2] - 100;
if (pixel < 0) pixel = 0;
if (pixel > 255) pixel = 255;
p[2] = (byte)pixel;
p += 4;
}
p += offset;
}
}
rs.UnlockBits(data);
return rs;
}
這種方法通過指向圖片的指針來訪問圖片,程序中p[2]存儲的是RGB中R的分量,p[1] 存儲的是RGB中G的分量,p[0] 存儲的是RGB中B的分量。
注:在使用第二種方法時,要在編譯器選項中加入“允許不安全代碼”。
3. 通過將圖片轉化成整型數組來訪問
( http://www.xtremevbtalk.com/showthread.php?t=245514 )
public static Bitmap ProcessByArray(Bitmap src)
{
Rectangle rec = new Rectangle(0, 0, src.Width, src.Height);
BitmapData bmpData = src.LockBits(rec, ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
IntPtr scan0 = bmpData.Scan0;
int len =src.Width * src.Height;
int[] pixels = new int[len];
Marshal.Copy(scan0, pixels, 0, len);
src.UnlockBits(bmpData);
for (int i = 0; i < len; i++)
{
//在這裏對圖片進行處理
Color color = Color.FromArgb(pixels[i]);
int red = (color.R - 100 < 0) ? 0 : color.R - 100;
color = Color.FromArgb(red, color.G, color.B);
pixels[i] = color.ToArgb();
}
GCHandle gch = GCHandle.Alloc(pixels, GCHandleType.Pinned);
Bitmap rsBmp = new Bitmap(src.Width, src.Height, bmpData.Stride, PixelFormat.Format32bppPArgb, gch.AddrOfPinnedObject());
gch.Free();
return rsBmp;
}
這種方法通過將圖片的各個像素轉化成一維的整型數組來訪問圖片,數組中的每一個整型代表着每一個像素的RGB值。
分析
通過以上3種方法都可以實現從圖1變到圖2,但是所需的時間卻差別很大,爲了弄清楚它們的運行速度,我們在調用這些函數的前後各聲明一個DateTime對象,然後通過相減來獲得時間間隔:
TimeSpan ts = new TimeSpan();
DateTime start = DateTime.Now;
//在這裏調用函數
DateTime end = DateTime.Now;
ts = end – start;
ts就是調用這個函數所用的時間。
通過分析,第一種方法需時約5300ms,第二種方法需時約800ms,第三種方法需時30ms,但如果把在第二種方法代碼的加亮部分用備註中的代碼替換,也就是說使用的是淺拷貝而不是深拷貝,這樣可以使所需時間降低到50ms左右,基本上接近第三種方法,但這樣是直接對源圖片進行修改,將會改變源圖片。
結論
第一種方法最爲簡單而且明瞭,但是處理的速度太慢,不適合對大量像素進行處理;而第二種方法處理速度快,尤其是對源圖片進行直接修改速度更快,因此第二種方法適合於對源圖片進行直接的處理;第三種方法速度最快,適合各種需要。