【轉】使用lockbits方法處理映像

來源:互聯網
上載者:User

標籤:

許多影像處理任務即時是最簡單的檔案類型轉換,例如從32位元深度到8位元深度的格式轉化,直接獲得像素陣列要比使用GetPixel和SetPixel等方法的效率高得多。

你可能會發現DotNet採用託管機制,大多數情況下微軟會推薦你使用Managed 程式碼,理由是便捷和安全。實際應用中,直接操作記憶體中的資料區塊是很少見的,儘管如此,影像處理恰恰是這類為數不多的情況之一,因為使用Managed 程式碼的效率低的難以忍受,特別是對巨幅映像來說,在此,我們討論一下一種新的方法。

如何使用Unmanaged 程式碼是因語言而異的,在C#中我們可以通過unsafe關鍵字來調用指標,從而直接操作記憶體中的位元影像資料;VB則使用Marshal類中的方法,它會導致一部分的效能損失,因此效率不如前者。

鎖定位元流

Bitmap類使用LockBits和UnLockBits方法來將位元影像的資料矩陣儲存在記憶體中、直接對它進行操作,最後用修改後的資料代替位元影像中的未經處理資料。LockBits返回以各BitmapData的類用已描述資料在鎖定的矩陣中的位置和分布。

BitmapData類包括以下幾個重要的屬性:

  • Scan0:資料矩陣在記憶體中的地址。

  • Stride:資料矩陣中的行寬,以byte為單位。可能會擴充幾個Byte,後面會介紹。

  • PixelFormat:像素格式,這對矩陣中位元組的定位很重要。

  • Width:位元影像的寬度。

  • Height:位元影像的高度。

具體關係見:

如所示,stride屬性工作表示位元影像資料矩陣的行寬,以byte為單位。出於效率考慮,矩陣的行寬並非剛好是每行像素數的整數倍,系統往往會將其封裝成4的整數倍。舉例來說,對於一幅24位深17像素寬的映像,其stride屬性為52;每行的資料量為17*3=51,系統將其自動封裝一個位元組,所以它的stride為52byte(或13*4byte)。對於一幅17像素寬的4位索引圖,其stride為12,其中9byte(準確地說是8.5個byte)用來記錄資料資訊,每行再自動添加3(3.5)個byte保證其為4的整數倍。

具體資料的分布因其pixel format而異。24位深的映像每隔3個byte包含一組RGB資訊;32位深的映像每隔4個byte包含一組RGBA資訊。那些每個位元組包含多個像素的pixel format,比如4位索引映像或1位索引映像,必須經過仔細處理,從而保證同一位元組中的相鄰byte不會混淆。

指標的準確定位

  • 32位RGB:假設X、Y為位元影像中像素的座標,則其在記憶體中的地址為scan0+Y*stride+X*4。此時指標指向藍色,其後分別是綠色、紅色,alpha分量。

  • 24位RGB:scan0+Y*stride+X*3。此時指標指向藍色,其後分別是綠色和紅色。

  • 8位索引:scan0+Y*stride+X。當前指標指向映像的調色盤。

  • 4位索引:scan0+Y*stride+(X/2)。當前指標所指的位元組包括兩個像素,通過高位和低位索引16色調色盤,其中高位表示左邊的像素,低位表示右邊的像素。

  • 1位索引:scan0+Y*stride+X/8。當前指標所指的位元組中的每一位都表示一個像素的索引顏色,調色盤為兩色,最左邊的像素為8,最右邊的像素為0。

像素間使用迭代器

下面這個範例將一幅32位深的映像中所有像素的藍色分量設為最大(255):

BitmapData bmd=bm.LockBits(new Rectangle(0, 0, 10, 10),  System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);

int PixelSize=4;

for(int y=0; y<bmd.Height; y++)

{

byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);

for(int x=0; x<bmd.Width; x++)

{

row[x*PixelSize]=255;

}

}

處理4位索引圖,高低位應分開處理,代碼如下:

int offset = (y * bmd.Stride) + (x >> 1);

byte currentByte = ((byte *)bmd.Scan0)[offset];

if((x&1) == 1)

{

currentByte &= 0xF0;

currentByte |= (byte)(colorIndex & 0x0F);

}

else

{

currentByte &= 0x0F;

currentByte |= (byte)(colorIndex << 4);

}

((byte *)bmd.Scan0)[offset]=currentByte;

處理1位索引的代碼:

byte* p=(byte*)bmd.Scan0.ToPointer();

int index=y*bmd.Stride+(x>>3);

byte mask=(byte)(0x80>>(x&0x7));

if(pixel)

p[index]|=mask;

else

p[index]&=(byte)(mask^0xff);

最後在進行完所有處理後馬不要忘記使用Unlockbits命令解鎖。

原文在這裡http://blog.sina.com.cn/s/blog_4e3e2ce4010009on.html

【轉】使用lockbits方法處理映像

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.