问下面红色代码什么意思,为什么不用bmp1.Width来循环?我看到很多例子是用高和宽循环的,这里为什么这样做? function IsBmpSame(bmp1,bmp2: TBitmap): Boolean; var i,j: Integer; ScanLine1,ScanLine2: PByteArray; Count: Integer; begin Result := (bmp1.Height = bmp2.Height) and (bmp1.Width = bmp2.Width) and (bmp1.PixelFormat = bmp2.PixelFormat); if Result then begin i := Integer(bmp1.PixelFormat); if i < 4 then i := 4 else if i = 4 then inc(i); Count := (i - 3) * bmp1.Width - 1; for i:=0 to bmp1.Height-1 do begin ScanLine1 := bmp1.ScanLine[i]; ScanLine2 := bmp2.ScanLine[i]; for j := 0 to Count do if ScanLine1[j] <> ScanLine2[j] then begin Result := False; Exit; end; end; end; end;
撸过 用height循环也一样嘛,反正都是x*y btw,这程序的默认图标不是c#的吗
TPixelFormat = (pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom); i := Integer(bmp1.PixelFormat);//这里的i返回的是像素值;一般我们用的bmp是pf24bit,也就是等于6; if i < 4 then i := 4 else if i = 4 then inc(i); Count := (i - 3) * bmp1.Width - 1; pf24bit表示一个像素点占24位,即3Byte,所以Count=3* bmp1.Width - 1;
下面的代码已经统一了一个标准。确保了每一行像素数组的长度范围。可是,我想问的是,正常来说,Count(应该叫Length才对),应该比 bmp1.Width大。也就是说,增加了循环的范围。 i := Integer(bmp1.PixelFormat); if i < 4 then i := 4 else if i = 4 then inc(i); Count := (i - 3) * bmp1.Width - 1;这里如果用Count循环,应该是对这个数组(PBYTEARRAY)的每一个元素进行比对。 for j := 0 to Count do if ScanLine1[j] <> ScanLine2[j] then而,比对有些例子用的是bmp1.Width,我是想问,既然用WIDTH也可以,用length也可以,那么为啥要用COUNT,因为更精确?还是其他原因? for j := 0 to bmp1.Width -1 do if ScanLine1[j] <> ScanLine2[j] then感谢你的回答,好吧,我承认我表达有问题。
感谢大虾的帮忙。我明白了。现在我想求大虾指点一下,怎么找到不一样的像素的位置。 我做的代码如下,目前貌似没啥错误。请指点!var BMPA,BMPB:TBitMap; I,X,Y,Z : Integer; W,H,Count : Integer; p1,p2: PByteArray; begin BMPA:=TBitMap.Create; BMPB:=TBitMap.Create; BMPA.LoadFromFile(PathA); BMPB.LoadFromFile(PathB); i := Integer(BMPA.PixelFormat); if i < 4 then i := 4 else if i = 4 then inc(i); Count := (i - 3) * BMPA.Width - 1;
H:=BMPA.Height - 1; for Y := 0 to H do begin p1:=BMPA.ScanLine[Y]; p2:=BMPB.ScanLine[Y]; for X := 0 to Count do begin if p1[X]<>p2[X] then begin z:=x DIV (i-3);//转换回像素坐标 ShowMessage('找到像素不同的位置['+IntToStr(z)+','+IntTostr(y)+']'); BMPA.Canvas.Pixels[z,y]:=clRed;//把2张图片不同的位置用特殊颜色标记出来 end; end; end; //显示图片,红色代表不同的地方 self.imgComPare.Picture.Bitmap.Assign(BMPA); BMPA.Free; BMPB.Free; end;
应该是6次,1个像素点占3Byte,2*3=6;你改为这样: for X := 0 to BMPA.Width - 1 do begin if (p1[X]<>p2[X]) or (p1[X+1]<>p2[X+1]) or (p1[X+2]<>p2[X+2]) then begin z:=x; ShowMessage('找到像素不同的位置['+IntToStr(z)+','+IntTostr(y)+']'); BMPA.Canvas.Pixels[z,y]:=clRed;//把2张图片不同的位置用特殊颜色标记出来 end; end;
Sorry,应该是: if (p1[3*X]<>p2[3*X]) or (p1[3*X+1]<>p2[3*X+1]) or (p1[3*X+2]<>p2[3*X+2]) then
呵呵 正好解决我的困惑,因为我之前的比较是这样的。for X := 0 to BMPA.Width - 1 do begin if p1[X]<>p2[X] then ---------->因为这里只扫描了1/3的像素点,所以,就没有达到预期目的。 begin P[X*3] :=0; p[X*3+1]:=0; p[X*3+2]:=0; end .........感谢大虾的耐心帮助。感觉真好!!
问下面红色代码什么意思,为什么不用bmp1.Width来循环?我看到很多例子是用高和宽循环的,这里为什么这样做?
function IsBmpSame(bmp1,bmp2: TBitmap): Boolean;
var
i,j: Integer;
ScanLine1,ScanLine2: PByteArray;
Count: Integer;
begin
Result := (bmp1.Height = bmp2.Height) and
(bmp1.Width = bmp2.Width) and
(bmp1.PixelFormat = bmp2.PixelFormat);
if Result then
begin
i := Integer(bmp1.PixelFormat);
if i < 4 then
i := 4
else if i = 4 then
inc(i);
Count := (i - 3) * bmp1.Width - 1; for i:=0 to bmp1.Height-1 do
begin
ScanLine1 := bmp1.ScanLine[i];
ScanLine2 := bmp2.ScanLine[i];
for j := 0 to Count do
if ScanLine1[j] <> ScanLine2[j] then
begin
Result := False;
Exit;
end;
end;
end;
end;
用height循环也一样嘛,反正都是x*y
btw,这程序的默认图标不是c#的吗
TPixelFormat = (pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom); i := Integer(bmp1.PixelFormat);//这里的i返回的是像素值;一般我们用的bmp是pf24bit,也就是等于6;
if i < 4 then
i := 4
else if i = 4 then
inc(i);
Count := (i - 3) * bmp1.Width - 1; pf24bit表示一个像素点占24位,即3Byte,所以Count=3* bmp1.Width - 1;
其实我想问的重点是,用bmp1.Width循环和用这个COUNT循环的差别,因为他们的值不同啊!
如果你的图像是pf24bit的,执行ScanLine1 := bmp1.ScanLine[i];后,Length(ScanLine1) = 3* bmp1.Width;
如果你的图像是其他格式的,执行ScanLine1 := bmp1.ScanLine[i];后,Length(ScanLine1)就不一定是3* bmp1.Width;
下面的代码已经统一了一个标准。确保了每一行像素数组的长度范围。可是,我想问的是,正常来说,Count(应该叫Length才对),应该比 bmp1.Width大。也就是说,增加了循环的范围。
i := Integer(bmp1.PixelFormat);
if i < 4 then
i := 4
else if i = 4 then
inc(i);
Count := (i - 3) * bmp1.Width - 1;这里如果用Count循环,应该是对这个数组(PBYTEARRAY)的每一个元素进行比对。
for j := 0 to Count do
if ScanLine1[j] <> ScanLine2[j] then而,比对有些例子用的是bmp1.Width,我是想问,既然用WIDTH也可以,用length也可以,那么为啥要用COUNT,因为更精确?还是其他原因?
for j := 0 to bmp1.Width -1 do
if ScanLine1[j] <> ScanLine2[j] then感谢你的回答,好吧,我承认我表达有问题。
用length应该可以适用所有的图像格式;
Count是计算的长度,length(ScanLine1)应该等于Count,你可以测试下。
如果图像格式是pf24bit的,用bmp1.Width是不对的,只比了图像的前1/3像素点;
感谢大虾的帮忙。我明白了。现在我想求大虾指点一下,怎么找到不一样的像素的位置。
我做的代码如下,目前貌似没啥错误。请指点!var
BMPA,BMPB:TBitMap;
I,X,Y,Z : Integer;
W,H,Count : Integer;
p1,p2: PByteArray;
begin
BMPA:=TBitMap.Create;
BMPB:=TBitMap.Create; BMPA.LoadFromFile(PathA);
BMPB.LoadFromFile(PathB);
i := Integer(BMPA.PixelFormat);
if i < 4 then
i := 4
else if i = 4 then
inc(i);
Count := (i - 3) * BMPA.Width - 1;
H:=BMPA.Height - 1; for Y := 0 to H do
begin
p1:=BMPA.ScanLine[Y];
p2:=BMPB.ScanLine[Y];
for X := 0 to Count do
begin
if p1[X]<>p2[X] then
begin
z:=x DIV (i-3);//转换回像素坐标
ShowMessage('找到像素不同的位置['+IntToStr(z)+','+IntTostr(y)+']');
BMPA.Canvas.Pixels[z,y]:=clRed;//把2张图片不同的位置用特殊颜色标记出来
end;
end;
end;
//显示图片,红色代表不同的地方
self.imgComPare.Picture.Bitmap.Assign(BMPA); BMPA.Free;
BMPB.Free;
end;
还有点问题,因为这里的COUNT问题,我刚刚测试了一下。事实上,这2个图品只有2个像素点不同。但是,if p1[X]<>p2[X] then位置的判断却是出现5次,这个很尴尬,虽然问题不大,但我觉得怎样才能完美点呢!
应该是6次,1个像素点占3Byte,2*3=6;你改为这样:
for X := 0 to BMPA.Width - 1 do
begin
if (p1[X]<>p2[X]) or (p1[X+1]<>p2[X+1]) or (p1[X+2]<>p2[X+2]) then
begin
z:=x;
ShowMessage('找到像素不同的位置['+IntToStr(z)+','+IntTostr(y)+']');
BMPA.Canvas.Pixels[z,y]:=clRed;//把2张图片不同的位置用特殊颜色标记出来
end;
end;
if (p1[3*X]<>p2[3*X]) or (p1[3*X+1]<>p2[3*X+1]) or (p1[3*X+2]<>p2[3*X+2]) then
呵呵 正好解决我的困惑,因为我之前的比较是这样的。for X := 0 to BMPA.Width - 1 do
begin
if p1[X]<>p2[X] then ---------->因为这里只扫描了1/3的像素点,所以,就没有达到预期目的。
begin
P[X*3] :=0;
p[X*3+1]:=0;
p[X*3+2]:=0;
end
.........感谢大虾的耐心帮助。感觉真好!!