没有合适的资源?快使用搜索试试~ 我知道了~
一个找色原理
需积分: 14 3 下载量 75 浏览量
2012-01-29
23:13:05
上传
评论
收藏 24KB TXT 举报
温馨提示
试读
18页
使用步长可以实现矩阵的抽样查找,但上面给出的螺旋遍历算法却不支持步长。因为它要利用访问计数退出循环,使用步长时会使矩阵中访问到的点的数目不确定,使的上述算法出现死循环。对上述算法的一个改进是使用一个逻辑变量记录遍历一轮是否有访问到点。如果没有,说明这一轮访问已经以位于矩阵之外可以退出循环。当步长为1时这种改进的算法要比前面的算法更慢,因为它要“空转”一轮。而且这种算法也不支持矩阵外的点作为基点,它会使循环提前退出。
资源推荐
资源详情
资源评论
一、数据提取
位图其实可以看成是一个由象素组成的矩阵,找图找色可以看成是象素值的比对。很多新手在设计这类的程序时喜欢使用TBitmap.Canvas.Pixels属性,这个属性其实是对API函数GetPixel的封装,这个函数执行速度是很慢的,主要用来对位图象素进行偶尔的访问。而比对过程中需要对象素进行频繁的访问,造成程序运行缓慢。另外一种方法是使用TBitmap.ScanLine属性,利用它可以直接访问位图的数据。但是这些数据和当前位图的格式有关,主要是色深方面的问题,不同的色深会有不同格式的数据。另外比对过程中也需要对该属性进行频繁的调用。由于比对过程完全是数据的比较,不需要进行绘制操作。所以可以一次性将位图的数据提取出来放置到一个缓冲区中再进行比对,这样程序的性能会更高,也便于查找算法的实现。这时可以调用API函数GetDIBits获得设备无关位图的RGB数据,其实ScanLine属性也是调用这个函数实现的。GetDIBits函数格式声明如下:
function GetDIBits(
DC: HDC; //设备上下文句柄;
Bitmap: HBitmap; //位图句柄,注意不是TBitmap对象;
StartScan, //开始检索的第一条扫描线;
NumScans: UINT; //共检索的扫描线数;
Bits: Pointer; //数据缓冲区指针;
var BitInfo: TBitmapInfo; //位图信息结构,此结构确定了设备无关位图的数据格式;
Usage: UINT //指定TBitmapInfo结构的bmiColors成员的格式。
): Integer; stdcall;
其中TBitmapInfo结构的格式如下:
tagBITMAPINFO = packed record
bmiHeader: TBitmapInfoHeader; //位图信息头,该结构用于说明位图的格式;
bmiColors: array[0..0] of TRGBQuad; //颜色表,给出调色板数据。
end;
在上述结构中主要使用bmiHeader成员,TBitmapInfoHeader结构的格式如下:
tagBITMAPINFOHEADER = packed record
biSize: DWORD; //当前结构的大小;
biWidth: Longint; //以像素为单位,给出该结构所描述位图的宽度;
biHeight: Longint; //以像素为单位,给出该结构所描述位图的高度;
biPlanes: Word; //目标设备的平面数,必须为1;
biBitCount: Word; //每个像素所需要的位数,当图像为真彩色时,该成员的取值为24;
biCompression: DWORD; //位图的压缩类型,若该成员的取值为BI_RGB,则图像数据没有经过压缩处理;
biSizeImage: DWORD; //以字节为单位,给出图像数据的大小,若图像为BI_RGB位图,则该成员的值必须设为0;
biXPelsPerMeter: Longint; //以每米像素数为单位,给出位图水平方向的分辨率;
biYPelsPerMeter: Longint; //以每米像素数为单位,给出位图垂直方向的分辨率;
biClrUsed: DWORD; //位图实际使用的颜色表中的颜色变址数;
biClrImportant: DWORD; //位图显示过程中重要颜色的变址数。
end;
位图其实可以看成是一个由象素组成的矩阵,找图找色可以看成是象素值的比对。很多新手在设计这类的程序时喜欢使用TBitmap.Canvas.Pixels属性,这个属性其实是对API函数GetPixel的封装,这个函数执行速度是很慢的,主要用来对位图象素进行偶尔的访问。而比对过程中需要对象素进行频繁的访问,造成程序运行缓慢。另外一种方法是使用TBitmap.ScanLine属性,利用它可以直接访问位图的数据。但是这些数据和当前位图的格式有关,主要是色深方面的问题,不同的色深会有不同格式的数据。另外比对过程中也需要对该属性进行频繁的调用。由于比对过程完全是数据的比较,不需要进行绘制操作。所以可以一次性将位图的数据提取出来放置到一个缓冲区中再进行比对,这样程序的性能会更高,也便于查找算法的实现。这时可以调用API函数GetDIBits获得设备无关位图的RGB数据,其实ScanLine属性也是调用这个函数实现的。GetDIBits函数格式声明如下:
function GetDIBits(
DC: HDC; //设备上下文句柄;
Bitmap: HBitmap; //位图句柄,注意不是TBitmap对象;
StartScan, //开始检索的第一条扫描线;
NumScans: UINT; //共检索的扫描线数;
Bits: Pointer; //数据缓冲区指针;
var BitInfo: TBitmapInfo; //位图信息结构,此结构确定了设备无关位图的数据格式;
Usage: UINT //指定TBitmapInfo结构的bmiColors成员的格式。
): Integer; stdcall;
其中TBitmapInfo结构的格式如下:
tagBITMAPINFO = packed record
bmiHeader: TBitmapInfoHeader; //位图信息头,该结构用于说明位图的格式;
bmiColors: array[0..0] of TRGBQuad; //颜色表,给出调色板数据。
end;
在上述结构中主要使用bmiHeader成员,TBitmapInfoHeader结构的格式如下:
tagBITMAPINFOHEADER = packed record
biSize: DWORD; //当前结构的大小;
biWidth: Longint; //以像素为单位,给出该结构所描述位图的宽度;
biHeight: Longint; //以像素为单位,给出该结构所描述位图的高度;
biPlanes: Word; //目标设备的平面数,必须为1;
biBitCount: Word; //每个像素所需要的位数,当图像为真彩色时,该成员的取值为24;
biCompression: DWORD; //位图的压缩类型,若该成员的取值为BI_RGB,则图像数据没有经过压缩处理;
biSizeImage: DWORD; //以字节为单位,给出图像数据的大小,若图像为BI_RGB位图,则该成员的值必须设为0;
biXPelsPerMeter: Longint; //以每米像素数为单位,给出位图水平方向的分辨率;
biYPelsPerMeter: Longint; //以每米像素数为单位,给出位图垂直方向的分辨率;
biClrUsed: DWORD; //位图实际使用的颜色表中的颜色变址数;
biClrImportant: DWORD; //位图显示过程中重要颜色的变址数。
end;
在上面两个结构中,bmiColours成员指向一个颜色表,它包含多少个表项是由bmiHeader.biBitCount成员定义。当该成员的取值为24时,则颜色表中的表项为空。当biBitCount取值24同时biCompression取值BI_RGB时表示当前位图为24位真彩色无压缩位图。这时可以将位图数据缓冲区看成是一个一维的字节数组。其中每3个字节代表1个像素。这3个字节以蓝(B)、绿(G)、红(R)为顺序,直接定义了像素颜色。这里要注意一个字节顺序,一般我们使用的TColor颜色格式是以红(R)、绿(G)、蓝(B)为顺序的RGB颜色,而缓冲区中使用的是顺序相反的BGR颜色。另外利用GetDIBits提取的位图数据是自下而上从左到右保存到缓冲区中的,即先保存位图最后一行从左到右的象素数据,再保存倒数第二行的数据,以此类推第一行最后保存。除了数据反相保存外,每行数据都以4字节(32位)对齐,一行数据的长度不能被4整除时就在每行的末尾填充值为0的字节使之能被4整除。例如:对于宽5象素的位图每行数据占16个字节,前15个字节每3个字节保存1个象素颜色,最后填充1个字节。对于宽10象素的位图每行数据占32个字节,前30个字节每3个字节保存1个象素颜色,最后填充2个字节。
知道了缓冲区数据的格式,就可以对缓冲区中的数据进行访问。现在给出相关访问的示范代码:首先位图数据缓冲区是一个一维的字节数组,那么这个数组Bits可以按以下代码进行定义:
type
TByteAry = array [0..0] of Byte;
PByteAry = ^TByteAry;
var
Bits : PByteAry;
接着假设有一个位图,高Height象素,宽Width象素。那么对齐后每行数据长度LineWidth字节可以用以下的代码计算出来:
LineWidth:=(((Width*24)+31) and ($7FFFFFFF-31)) shr 3;
于是前面数组Bits的大小Size就为:LineWidth*Height。对于任意一个象素在位图上的位置Left,Top(二维)可以用以下代码换算出该象素数据在数组Bits中的位置Off(一维):
Off:=((Height-Top-1)*LineWidth)+(Left*3);
假设一个BGR格式的颜色值Color,以下代码可以从数组Bits的Off位置读取一个象素颜色值:
Color:=((PInteger(@(Bits[Off])))^ and $FFFFFF);
使用GetDIBits函数后就可以不再使用TBitmap对象。以下的示范代码实现对当前屏幕的全屏截图,并将截图后的位图数据提取到缓冲区中返回:
procedure CopyScreen(var Bits : PByteAry; var Size : Integer);
var
Width,Height,LineWidth : Integer;
Wnd : HWND;
DC,MemDC : HDC;
Bitmap,OldBitmap : HBITMAP;
BitInfo : TBitmapInfo;
begin
//数据初始化
Width:=GetSystemMetrics(SM_CXSCREEN);
Height:=GetSystemMetrics(SM_CYSCREEN);
LineWidth:=(((Width*24)+31) and ($7FFFFFFF-31)) shr 3;
Size:=LineWidth*Height;
GetMem(Bits,Size);
//截图
Wnd:=GetDesktopWindow();
知道了缓冲区数据的格式,就可以对缓冲区中的数据进行访问。现在给出相关访问的示范代码:首先位图数据缓冲区是一个一维的字节数组,那么这个数组Bits可以按以下代码进行定义:
type
TByteAry = array [0..0] of Byte;
PByteAry = ^TByteAry;
var
Bits : PByteAry;
接着假设有一个位图,高Height象素,宽Width象素。那么对齐后每行数据长度LineWidth字节可以用以下的代码计算出来:
LineWidth:=(((Width*24)+31) and ($7FFFFFFF-31)) shr 3;
于是前面数组Bits的大小Size就为:LineWidth*Height。对于任意一个象素在位图上的位置Left,Top(二维)可以用以下代码换算出该象素数据在数组Bits中的位置Off(一维):
Off:=((Height-Top-1)*LineWidth)+(Left*3);
假设一个BGR格式的颜色值Color,以下代码可以从数组Bits的Off位置读取一个象素颜色值:
Color:=((PInteger(@(Bits[Off])))^ and $FFFFFF);
使用GetDIBits函数后就可以不再使用TBitmap对象。以下的示范代码实现对当前屏幕的全屏截图,并将截图后的位图数据提取到缓冲区中返回:
procedure CopyScreen(var Bits : PByteAry; var Size : Integer);
var
Width,Height,LineWidth : Integer;
Wnd : HWND;
DC,MemDC : HDC;
Bitmap,OldBitmap : HBITMAP;
BitInfo : TBitmapInfo;
begin
//数据初始化
Width:=GetSystemMetrics(SM_CXSCREEN);
Height:=GetSystemMetrics(SM_CYSCREEN);
LineWidth:=(((Width*24)+31) and ($7FFFFFFF-31)) shr 3;
Size:=LineWidth*Height;
GetMem(Bits,Size);
//截图
Wnd:=GetDesktopWindow();
剩余17页未读,继续阅读
资源评论
adzc234
- 粉丝: 0
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功