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

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 nhconch 的 blog

  使用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;

本文关键:获取TBitMap图像缓冲区,提高图像处理速度
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top