程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 使用Delphi獲取TBitMap圖像緩沖區,提高圖像處理速度

使用Delphi獲取TBitMap圖像緩沖區,提高圖像處理速度

編輯:Delphi

使用Dephi進行圖像處理可以有多種方法,最常用的應該算是TBitmap,它提供方便的圖像存取能力,結合Canvas可進行畫線、畫圓、圖像拷貝等操作。不過在進行大量的圖像處理操作時,為了獲得更高的速度,我們希望能夠直接對圖像緩沖區進行讀寫。查閱Dephi的幫助手冊沒有發現直接取得整個圖像緩沖區的功能,但提供的ScanLine屬性可以取得指定行圖像數據的指針,比較接近我們的要求,先看看ScanLine的描述:

Provides indexed access to each line of pixels.
property ScanLine[Row: Integer]: Pointer;
Description
ScanLine is used only with DIBs (Device Independent Bitmaps) for image editing tools that do low-level pixel work.

讓我們再看看ScanLine[0]、ScanLine[1]的關系:

procedure TForm1.Button1Click(Sender: TObject);
var
    BitMap: TBitmap;
    S: String;
begin
    BitMap := TBitmap.Create;
    try
        BitMap.PixelFormat := pf24bit;  //24位色,每像素點3個字節
        BitMap.Width := 1000;
        BitMap.Height := 2;
        FmtStr(S, 'ScanLine[0]:%8x'#13'ScanLine[1]:%8x'#13'ScanLine[1]-ScanLine[0]:%d'
            , [Integer(BitMap.ScanLine[0]), Integer(BitMap.ScanLine[1])
            , Integer(BitMap.ScanLine[1]) - Integer(BitMap.ScanLine[0])]);
        MessageBox(Handle, PChar(S), 'ScanLine', MB_OK);
    finally
        if Assigned(BitMap) then FreeAndNil(BitMap);
    end;
end;

下面是運行結果:

ScanLine[0]: E90BB8
ScanLine[1]: E90000
ScanLine[1]-ScanLine[0]:-3000

前兩個結果因機器不同而不同,第三個結果很特別,ScanLine[0]與ScanLine[1]之間相差3000=1000像素寬×3字節這很容易理解,但為什麼是負數呢?因為BMP圖像數據是“按行存放,每行按雙字對齊,行按倒序方式存放”的,也就是說屏幕顯示的第一行存放在最後,屏幕顯示的最後一行存放在前面,所以用ACDSee等看圖軟件查看尺寸較大的位圖時先從下部開始顯示就是這個道理。

從上面的結果可以看出TBitmap的圖像數據在內存中是按行倒序連續存放的,通過TBitmap.ScanLine[TBitmap.Height-1]可以取得首地址即圖像緩沖區地址。接著我們來實踐一下,通過直接對圖像緩沖區的讀寫將圖像淡出到黑色:

procedure TForm1.Button1Click(Sender: TObject);
const
    FADEOUT_STEP = 24;  //淡出衰減值
    FIX_WIDTH    = 320;
    FIX_HEIGHT   = 200;
var
    BitMap: TBitmap;
    hWinDC: HDC;
    flagAgein: Boolean;
    lpBuffer: PByte;    //圖像緩沖區指針
begin
    BitMap := TBitmap.Create;
    if not Assigned(BitMap) then Exit;
    try
        //設置位圖格式、寬度、高度
        BitMap.PixelFormat := pf24bit;
        BitMap.Width := FIX_WIDTH;
        BitMap.Height := FIX_HEIGHT;
        //設置Form的寬充、高度,便於顯示結果
        Button1.Visible := false;
        ClientWidth := FIX_WIDTH;
        ClientHeight := FIX_HEIGHT;
        //拷貝圖像到Bitmap中
        hWinDC := GetDC(0);
        if (hWinDC<>NULL) then BitBlt(Bitmap.Canvas.Handle, 0, 0, FIX_WIDTH, FIX_HEIGHT, hWinDC, 0, 0, SRCCOPY)
        else BitBlt(Bitmap.Canvas.Handle, 0, 0, FIX_WIDTH, FIX_HEIGHT, Canvas.Handle, 0, 0, SRCCOPY);

        repeat
            flagAgein := false;
            lpBuffer := BitMap.ScanLine[FIX_HEIGHT-1];  //取得圖像緩沖區首地址
            //Integer(BitMap.ScanLine[0]) + FIX_WIDTH*3 為圖像緩沖區結束地址
            while Integer(lpBuffer) < Integer(BitMap.ScanLine[0]) + FIX_WIDTH*3 do begin
                if lpBuffer^>FADEOUT_STEP then
                begin
                    Dec(lpBuffer^, FADEOUT_STEP);
                    flagAgein := true;
                end
                    else lpBuffer^ :=0;
                Inc(lpBuffer);
                Application.ProcessMessages;
            end;
            Canvas.Draw(0, 0, BitMap);
        until (not flagAgein);

        MessageBox(Handle, 'Done', 'Fadeout', MB_OK);
    finally
        if Assigned(BitMap) then FreeAndNil(BitMap);
        Button1.Visible := true;
    end;
end;

最後補充說明一下:

1、Bitmap圖像緩沖區是雙節對齊的,如果把例1中的圖像寬度改為999,一個像素行還是占3000個字節。

2、目前Bitmap.PixelFormat有pfDevice、pf1bit、pf4bit、pf8bit、pf15bit、pf16bit、pf24bit、pf32bit、pfCustom共9種,不同格式每個像素所占字節數不同,其中pf4bit和pf8bit格式的圖像緩沖區保存的為顏色索引號,真正的顏色值在調色板中,pf15bit、pf16bit格式中RGB所占的位數(Bit)不一定是等長的。有興趣的可查閱相關資料。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved