zoukankan      html  css  js  c++  java
  • 获取TBitMap图像缓冲区,提高图像处理速度

      使用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]可以取得首地址即图像缓冲区地址。接着我们来实践一下,通过直接对图像缓冲区的读写将图像淡出到黑色:

    {======================================================================
      DESIGN BY :  彭国辉
      SITE:        
    http://kacarton.yeah.net/
      BLOG:        http://blog.csdn.net/nhconch
      EMAIL:       kacarton@sohu.com

      文章为作者原创,转载前请先与本人联系,转载请注明文章出处、保留作者信息,谢谢支持!
    ======================================================================}


    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)不一定是等长的。有兴趣的可查阅相关资料。

    http://blog.csdn.net/nhconch/article/details/68479

  • 相关阅读:
    学习:Radio Button和Check Box
    学习:访问Edit Control的七种方法
    实现:EDIT控件字符个数与长度的计算
    学习:GDI基础
    学习:MFC的CWinApp和CFrameWnd
    学习:远程代码注入
    实现:获取指定进程PID
    学习:远程线程实现DLL注入和shellcode注入以及OD调试原理
    学习:内存映射文件
    实现 Trie (前缀树)
  • 原文地址:https://www.cnblogs.com/findumars/p/5393717.html
Copyright © 2011-2022 走看看