获取TBitMap图像缓冲区,提高图像处理速度

原创 2004年08月08日 14:28:00

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

 

使用CImage进行图像处理

MFC和ATL共享的新类CImage为图像处理提供了许多相应的处理方法 CImage类 我们知道,Visual C++的CBitmap类和静态图片控件的功能是比较弱的,它只能显...
  • phenixyf
  • phenixyf
  • 2014年12月11日 10:33
  • 1389

OpenGL ES 学习教程(十五) 从 颜色缓冲区(FBO的颜色附着)中 读取颜色数据 保存到图片(FreeImage)

GL中提供读取像素数据的API glReadPixels,方便实现游戏中截屏功能。
  • cp790621656
  • cp790621656
  • 2016年12月07日 02:39
  • 1348

Qt:通过预解释和预读取,大幅度提升图片加载速度

在我以往的开发中,尤其是嵌入式,图片的加载一直是一个头疼的问题。图片大了,加载就很慢,在嵌入式上,一个1280*1080的图片,加载可能要好几百毫秒。也就是说加载一个背景,就可能要花去几百毫秒,还不包...
  • wsj18808050
  • wsj18808050
  • 2017年03月28日 11:15
  • 1457

各种图像处理库的处理速度

来自  http://topic.csdn.net/u/20090527/16/d689a74f-f2be-444b-81c5-9b65228cf71c.html    1.对OpenCV的印...
  • m_kiss
  • m_kiss
  • 2011年10月31日 15:19
  • 378

提高窗体图层叠加处理速度

在前几节,我们使用窗体图层叠加技术,解决了窗体,例如鼠标移动时,破坏其他窗体界面的问题,但以此同时,也引入了新的问题。当鼠标移动时,内核会将所有窗口重新绘制,如果当前系统打开的窗口很多,假设有几十上百...
  • tyler_download
  • tyler_download
  • 2016年11月18日 11:42
  • 265

图形图像处理-之-彩色转化到灰度的速度优化

文章来源:http://blog.csdn.net/housisong/archive/2009/02/12/3884368.aspx图形图像处理-之-彩色转化到灰度的速度优化            ...
  • woodyarm
  • woodyarm
  • 2011年02月25日 18:43
  • 351

为了提高数据库的处理速度,怎样设计数据库?

本文首先讨论了基于第三范式的数据库表的基本设计,着重论述了建立主键和索引的策略和方案,然后从数据库表的扩展设计和库表对象的放置等角度概述了数据库管理系统的优化方案。  关键词: 优化(Optimiz...
  • qq_14844093
  • qq_14844093
  • 2015年04月09日 08:12
  • 367

并行编程提高软件处理速度

使用 TParallel 来提速你的循环,但总有些时候,你需要运行多个可以并行执行,而又并非循环的任务。 要执行此类任务,我们可以使用 System.Threading.TTask 和 System...
  • caonumber
  • caonumber
  • 2015年10月07日 11:37
  • 417

storm的利用并行度提高处理速度的几点感想

在storm的流计算框架中,在数据量非常大或者计算逻辑比较复杂的情况下,可能会造成chulisudubianmandeqingk...
  • shuaiOKshuai
  • shuaiOKshuai
  • 2014年08月04日 10:36
  • 4874

storm用于提高处理速度的并行度设计的感想2

最近看到一篇文章,是关于设定topology中并行度的设定,用于提高
  • shuaiOKshuai
  • shuaiOKshuai
  • 2014年08月18日 14:32
  • 1616
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:获取TBitMap图像缓冲区,提高图像处理速度
举报原因:
原因补充:

(最多只允许输入30个字)