圖片逐像素處理的速度比較

圖片逐像素處理的速度比較

 

這篇文章將介紹對圖片進行逐個像素的處理時的方法,由於方法的不同將會造成處理的速度的巨大區別。

 

以下通過一個例子來說明各種方法的處理速度:

我們將一幅200×266像素的圖片每個像素的RGB顏色中的R分量減少100,減少後小於0的按0計算。如圖所示將圖1轉變成圖2

    

                     [1]                                                       [2]

 

 

1. 使用BitmapGetPixelSetPixel方法訪問

 

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]存儲的是RGBR的分量,p[1] 存儲的是RGBG的分量,p[0] 存儲的是RGBB的分量。

 

注:在使用第二種方法時,要在編譯器選項中加入“允許不安全代碼”。

 

 

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左右,基本上接近第三種方法,但這樣是直接對源圖片進行修改,將會改變源圖片。

 

 

結論

    第一種方法最爲簡單而且明瞭,但是處理的速度太慢,不適合對大量像素進行處理;而第二種方法處理速度快,尤其是對源圖片進行直接修改速度更快,因此第二種方法適合於對源圖片進行直接的處理;第三種方法速度最快,適合各種需要。

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章