delphi图像处理代码(delphi图像识别)
admin 发布:2022-12-19 10:09 130
今天给各位分享delphi图像处理代码的知识,其中也会对delphi图像识别进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
delphi 如何实现两个表面间图形的缩放
在delphi中对图像的简单处理,于是不停的从网上找资料,翻看csdn以前的帖子,从我搜索的结果发现很多人会在各种项目中遇到类似的 图片处理问题,但是多数得到的答案似乎并不完整(因为很多都没有结帖,也可能是个人习惯的问题,呵呵,希望大家读了我这个文章之后,能够家开结帖速度)。 于是我把我遇到的问题和解决方案写在下面,供大家参考,同时欢迎大家继续拍砖。
在正式内容之前要把我要解决的问题写在前面,同时也让读者有一个好的定位,从而不会因为我在处理过程中的拙劣手段而感到恼火。这里主要解决的问题是在 Delphi中将用扫描仪扫描得到的图片进行90度旋转,从而得到适合使用的图片,并且由于不能正确把握图片的大小,因此要对图片进行简单的缩放。而我的 解决方法也完全是根据此要求进行,因为对于效率、图片处理之后的清晰度考虑的不是很多,同时带来的好处就是程序看起来很简单。
首先,我没有扫描仪,因此我不知道使用扫描程序(已经提供)得到的图片是什么格式,而在Delphi的帮助中说“A bitmap is a powerful graphics object used to create, manipulate (scale, scroll, rotate, and paint), and store images in memory and as files on a disk”,所以我的第一步就是要把我的片转化为TBitmap来处理。在转化格式的同时,我将图片的实际大小改变,以适合后面选取部分图像的需要。函数 如下:
procedure TMainForm.ChangeImageFormate;
var Bitmap : TBitmap;
Zoom : Integer;
begin
Bitmap := TBitmap.Create; //1
try
with ImageCert do begin
Bitmap.Assign(Picture.Graphic); //2
Picture := nil; //3
Zoom := Max(Bitmap.Width div Width,Bitmap.Height div Height)+1; //4
Width := Bitmap.Width div Zoom; //5
Height := Bitmap.Height div Zoom; //6
Canvas.StretchDraw(Rect(0,0,Width,Height),Bitmap); //7
end;
finally
Bitmap.Free;
end;
end;
我想这段代码并不是很复杂,ImageCert是一个TImage控件放在Form上,唯一可能陌生的就是第八句,但是大家可以从Delphi的帮助中得 到很到说明,我在这就不再翻译了(我的建议就是多看帮助)。同时应该指出的是第三句作用是很关键的,如果去掉这一句同时你的图片格式不是bmp的话,就会 出现“只有bitmap才能才能修改”的错误。
第二步就是实现图片的旋转,因为程序要求只是每次旋转90度即可,因此这里也比较容易处理。处理的手段就是按照像素进行替换。实现过程如下:
procedure TMainForm.RotateImage;
var x,y : Integer;
TmpBitMap : TBitmap;
begin
TmpBitMap := TBitmap.Create;
try
TmpBitMap.Assign(ImageCert.Picture.Graphic);
with ImageCert do begin
Picture.Bitmap.Height := TmpBitMap.Width;
Picture.Bitmap.Width := TmpBitMap.Height;
for x:=0 to Height do
for y:=0 to Width do
Canvas.Pixels[TmpBitMap.Height-x,y] := TmpBitMap.Canvas.Pixels[y,x];
Height := TmpBitMap.Width;
Width := TmpBitMap.Height;
end;
finally
TmpBitMap.Free;
end;
end;
这段程序也没有什么好讲的,但是几个高度和宽度的设置令我是分的烦闷,总是觉得多做的点什么,但是却偏偏去不掉任何一行,如果哪位有兴趣可以尝试一下,最 好把结果也告诉我一声。而且在这个里面由于TImage和TBitmap都有各自的canvas,所以使用哪一个可能也是值得研究的,但是由于时间有限就 没有在尝试了。
至于在部分取图的过程中,我是用了一个TShape,然后用将brush的style设置成bsclear,在ImageCert的 onMouseMove中安排这个TShap的位置,这样做不是很灵敏,因为当鼠标在TShape上面时则不会起到作用,所幸影响不大。同时我在 TShape的OnMouseDown事件中取出TShape下面的部分图片。这个时候如果你的图片没有做过缩放处理,就会发现取出的图片和我们看到的位 置不相符(当然是在TImage没有正确显示图片大小的情况下)。
可以肯定这个方法不是很好的方法,但是至少它解决了问题。
怎样把图像灰度化
由Delphi中的图像灰度化代码看基本图像处理
基础篇]
首先看一段实现24位色图像灰度化转换的代码
procedure Grayscale(const Bitmap:TBitmap);
var
X: Integer;
Y: Integer;
R,G,B,Gray: Byte;
Color: TColor;
begin
for Y := 0 to (Bitmap.Height - 1) do
begin
for X := 0 to (Bitmap.Width - 1) do
begin
Color := Bitmap.Canvas.Pixels[X,Y];
R := Color and $FF;
G := (Color and $FF00) shr 8;
B := (Color and $FF0000) shr 16;
Gray := Trunc(0.3 * R + 0.59 * G + 0.11 * B);
Bitmap.Canvas.Pixels[X,Y] := Gray shl 16 or Gray shl 8 or Gray;
end
end
end;
{这段代码效率是非常低的,但可以方便我们理解同时一些问题}
Delphi的帮助中对TColor已经有了详细的描述,这可以方便我们理解上面的代码!
首先看:
R := Color and $FF;
G := (Color and $FF00) shr 8;
B := (Color and $FF0000) shr 16;
这是段常见的从TColor中提取三原色的代码,但它是什么意思呢?
首先应该知道and是与(.)运算,0.1=0,0.0=0,1.1=1,以取绿色为例:$FF00实际上就是$00FF00,它与一个TColor类型数按位进行与运算后,表示红色和绿色的位都变为了$00,而表示绿色的部分不变(0,1和1进行与运算值都不变),再右移8位,自然就获得了绿色值的8位表示!
再获得三原色的值后,就是计算灰度值,0.3 * Red + 0.59 * Green + 0.11 * Blue 这是求加权平均值的公式。(因为人眼对颜色的敏感度不同,所以权值不同,就像在pf16bit中用了6位表示绿色,其它两种颜色只用了5位,这问题以后另写文章说明)
然后就是像素颜色信息的写回,刚才是右移,现在自然就是左移,而或(+)运算就是(0+1=1,0+0=0,1+1=1),举个简单例子就是:($FF shl 16 = $FF0000) or ($FF shl 8 = $FF00) or $FF = $FFFFFF ,其实这里的或运算当然也可以用 + 代替。
虽然上面的代码实现了24位色图像的灰度化,但当图像比较大时,速度非常慢,为什么?查看相关VCL代码可知调用Bitmap.Canvas.Pixels获取,写入像素的颜色信息实际上是利用了API GetPixel、SetPixel,这种方法是非常低效的!(唯一的好处是在进行一些和颜色无关的操作,如图像的旋转,翻转时不需要因为PixelFormat的不同而修改代码)所以应该换一种更高效的访问像素点数据的方法,如用API GetDIBits、SetDIBits,但这种方法比较复杂,好在Delphi3以后版本的TBitmap中提供了Scanline。利用Scanline可以快速对像素进行访问!
还是以24位色(PixelFormats=pf24bit)为例,可改写为:
procedure Grayscale(const Bitmap:TBitmap);
const
PixelCountMax = 32768;
type
pRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = ARRAY[0..PixelCountMax-1] OF TRGBTriple;
var
Row: pRGBTripleArray;
X: Integer;
Y: Integer;
Gray: Byte;
begin
for Y := 0 to (Bitmap.Height - 1) do
begin
Row := Bitmap.ScanLine[Y];
for X := 0 to (Bitmap.Width - 1) do
begin
Gray := Trunc(0.3 * Row^[X].rgbtRed + 0.59 * Row^[X].rgbtGreen + 0.11 * Row^[X].rgbtBlue);
Row^[X].rgbtRed:=Gray;
Row^[X].rgbtGreen:=Gray;
Row^[X].rgbtBlue:=Gray;
end;
end;
end;
上面的例子用了一个TRGBTriple数组
PRGBTriple = ^TRGBTriple;
tagRGBTRIPLE = packed record
rgbtBlue: Byte;
rgbtGreen: Byte;
rgbtRed: Byte;
end;
TRGBTriple = tagRGBTRIPLE;
这种方法会限制位图的大小,但一般不用理会,直接用TBitmap可处理不了那么大的位图
当然也可用指针的移动实现,实测结果这样更快~~~
procedure Grayscale(const Bitmap:TBitmap);
var
X: Integer;
Y: Integer;
PRGB: pRGBTriple;
Gray: Byte;
begin
for Y := 0 to (Bitmap.Height - 1) do
begin
PRGB := Bitmap.ScanLine[Y];
for X := 0 to (Bitmap.Width - 1) do
begin
Gray := Trunc(0.3 * PRGB^.rgbtRed + 0.59 * PRGB^.rgbtGreen + 0.11 * PRGB^.rgbtBlue);
PRGB^.rgbtRed:=Gray;
PRGB^.rgbtGreen:=Gray;
PRGB^.rgbtBlue:=Gray;
Inc(PRGB);
end;
end;
end;
[颜色篇]
在上面提到了,那灰度化代码只能适用于24位色(PixelFormats=pf24bit),为什么?看看记录类型tagRGBTRIPLE,正好24位,所以这样只能处理24位色图!
那怎么处理其他的位图呢?
先对这各种类型的位图做些简单的介绍~~~
pf1bit:
每个像素只需要用一位表示,如调色板定义的是黑白两种颜色(0为黑,1为白),这时只能用位操作访问像素信息!如定义
var P:PByte
for Y := 0 to (Bitmap.Height - 1) do
begin
p := Bitmap.ScanLine[Y];
for X := 0 to (Bitmap.width - 1) DIV 8 + 1 do
begin
p^:=1 or 2 or 4 or 8 or 16 or 32 or 64 or 128;
Inc(PRGB,3);
end;
end;
p^:=1 or 2 or 4 or 8 or 16 or 32 or 64 or 128;
这行代码什么意思呢?1=1(二进制),2=10(二进制),4=100(二进制),8=1000(二进制)...
结合上篇中解释了的或运算,很容易理解就以八个字位为单位,给其赋上颜色信息!
pf4bit:
和pf1bit位图一样,操作pf4bit位图也需要用位操作。
pf8bit:
可直接利用Byte、TByteArray,但用Scanline取的值表示的只是调色板上颜色的索引。
pf15bit和pf16bit:
这两种位图都是16位的,pf15bit是第一位为0,后15位的每5位分别表示红、绿、蓝。而pf16bit中绿色占6位,其它两种颜色占用5位(人眼对绿色比较敏感)!
pf24bit位图转pf15bit位图代码
var
Row24:pRGBTriple;
Row15:PWord;
for j := 0 TO Bitmap.Height-1 DO
begin
Row15 := Bitmap15.Scanline[j];
Row24 := Bitmap24.Scanline[j];
for i := 0 TO Bitmap.Width-1 DO
begin
with Row24^ do
Row15^ := (rgbtRed Shr 3) Shl 10 or (rgbtGreen Shr 3) Shl 5 or (rgbtBlue Shr 3);
Inc(Row24);
Inc(Row15);
end
end;
pf24bit和pf32bit:
pf24bit上面的已多次用到,就不多说了。而pf32bit和pf24bit一样,用24位(前24位)来记录三原色的颜色信息!
PRGBQuad = ^TRGBQuad;
tagRGBQUAD = packed record
rgbBlue: Byte;
rgbGreen: Byte;
rgbRed: Byte;
rgbReserved: Byte;
end;
TRGBQuad = tagRGBQUAD;
如果要修改上面的程序,就是简单的PRGBQuad替换PRGBTriple,TRGBQuad替换TRGBTriple的过程~
测试表明在pf32bit中利用Scanline处理图像要比pf24bit快。
所以除了单色图(PixelFormats=pf1bit)外(没必要),其它都可转外32位色实现灰度化。这也是一种比较可行的方法!
[优化篇]
还以上篇中给出的灰度化代码为例
procedure Grayscale(const Bitmap:TBitmap);
var
X: Integer;
Y: Integer;
PRGB: pRGBTriple;
Gray: Byte;
begin
for Y := 0 to (Bitmap.Height - 1) do
begin
PRGB := Bitmap.ScanLine[Y];
for X := 0 to (Bitmap.Width - 1) do
begin
Gray := Trunc(0.3 * PRGB^.rgbtRed + 0.59 * PRGB^.rgbtGreen + 0.11 * PRGB^.rgbtBlue);
PRGB^.rgbtRed:=Gray;
PRGB^.rgbtGreen:=Gray;
PRGB^.rgbtBlue:=Gray;
Inc(PRGB);
end;
end;
end;
实际应用中,这种方法已经很快了,但实际上还存在可以优化的余地,什么呢?
Gray := Trunc(0.3 * Red + 0.59 * Green + 0.11 * Blue);//这句用的是浮点运算
在图像处理中,速度就是生命,能不用浮点运算,就最好不要用!
Gray := (30 * Red + 59 * Green + 11 * Blue) div 100;
虽然这样一改,运算次数多了一次,但在我的雷鸟1.1G上,处理速度大概能提高5%左右!而同主频下(或略低,如Athlon 1600+相当于P4 1.6G)AMD的CPU浮点运算能力比Intel的较强,整数运算能力较弱,所以用Intel的CPU在这里更能体现出优势!
注:x div 100 和 Trunc(x/100)的效果是相同的,但查看其汇编代码可知一个用的指令是div,而另一个是fdiv(即进行浮点运算),还要调用函数Trunc,其处理速度差距非常大,所以能用 x div 100 的时候就不要用 Trunc(x/100)。
但这还不是最快的,再看一个:
Gray := HiByte(77 * Red + 151 * Green + 28 * Blue);
即
Gray := (77 * Red + 151 * Green + 28 * Blue) shr 8;
(建议用后一种,不要调用函数)
这种方法比最原始的方法快了近3/4!
什么意思呢?用77,151,28分别除以256试试~~~
移位是什么意思呢,和10进制的进位,退位联系一下,是不是可以近似的理解为乘除2的n次方呢?当然这和真正意义的乘除法是不一样的!比如shr(右移),和真正的除法相比,比如shr 1,只有最后一个字位为0时(既为2的倍数),它才等于除2!如二进制数110(6)右移1位变为11(3),和6/2=3结果相同。
当然这和一开始的灰度化效果有了些误差!
如果允许存在更大的误差,还可以考虑另一种方法:
Gray := (Red shr 2) + (Red shr 4) + (Green shr 1) + (Green shr 4) + (Blue shr 3);
连乘法都没用,完全用移位实现,结合上面的解释,用除法来理解该表达式,其值只是约等于(0.3125 * Red + 0.5625 * Green + 0.125 * Blue),和一开始的加权平均值有了比较大的误差!但如果对速度有苛刻的要求的话,可以怎么用!这比上一种方法还能再快5%!
关于delphi新手求解
去掉背景色,牵涉到图像处理,算法比较复杂。建议可以参考 CnPack 提供的开源代码库中的相关代码:
白色背景图:
背景色透明:
delphi图像处理代码的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于delphi图像识别、delphi图像处理代码的信息别忘了在本站进行查找喔。
版权说明:如非注明,本站文章均为 AH站长 原创,转载请注明出处和附带本文链接;
- 上一篇:员工管理系统代码(企业员工管理系统代码)
- 下一篇:轮播代码安卓(轮播怎么实现)
相关推荐
- 05-09网页代码,网页代码快捷键
- 05-06单页网站的代码(完整的网页代码)[20240506更新]
- 05-06个人主页图片代码(个人主页图片代码怎么弄)[20240506更新]
- 05-06提取微信名片代码(微信名片信息提取)[20240506更新]
- 05-06php后台权限管理代码(php管理员权限)[20240506更新]
- 05-06付费观看代码php(付费观看代码)[20240506更新]
- 05-06在线html执行代码(html怎么运行)[20240506更新]
- 05-06源代码管理资源管理器(资源管理器运行代码)[20240506更新]
- 05-06代码源软件库(程序代码库)[20240506更新]
- 05-06点击弹出密码代码(点击弹出密码代码错误)[20240506更新]
取消回复欢迎 你 发表评论:
- 标签列表
- 最近发表
- 友情链接