delphi – 比较JPEG图像的最快解决方案是什么? (忽略元数据,只
当我搜索单词“JPEG”和“元数据”时,我有很多答案来操纵元数据……这是我想要的相反……; o)
我写了一个函数,它完全像我想要的那样…(如果图像相似,只有元数据改变与否,函数返回True;如果至少有一个像素改变,则返回False)但是,我想要改善表现…… 瓶颈是bmp.Assign(jpg); function CompareImages(fnFrom,fnTo: TFileName): Boolean; var j1,j2: TJpegImage; b1,b2: TBitmap; s1,s2: TMemoryStream; begin Result := False; sw1.Start; j1 := TJpegImage.Create; j2 := TJpegImage.Create; sw1.Stop; sw2.Start; s1 := TMemoryStream.Create; s2 := TMemoryStream.Create; sw2.Stop; //sw3.Start; b1 := TBitmap.Create; b2 := TBitmap.Create; //sw3.Stop; try sw1.Start; j1.LoadFromFile(fnFrom); j2.LoadFromFile(fnTo); sw1.Stop; // the very long part... sw3.Start; b1.Assign(j1); b2.Assign(j2); sw3.Stop; sw4.Start; b1.SaveToStream(s1); b2.SaveToStream(s2); sw4.Stop; sw2.Start; s1.Position := 0; s2.Position := 0; sw2.Stop; sw5.Start; Result := IsIdenticalStreams(s1,s2); sw5.Stop; finally // sw3.Start; b1.Free; b2.Free; // sw3.Stop; sw2.Start; s1.Free; s2.Free; sw2.Stop; sw1.Start; j1.Free; j2.Free; sw1.Stop; end; end; sw1,…,sw5是TStopWatch,我用来识别花费的时间. IsIdenticalStreams来自here. 如果我直接比较TJpegImage,流是不同的…… 有没有更好的代码编写方式? 问候, W. 更新: 测试从注释中提取的一些解决方案,我对此代码具有相同的性能: type TMyJpeg = class(TJPEGImage) public function Equals(Graphic: TGraphic): Boolean; override; end; ... function CompareImages(fnFrom,j2: TMyJpeg; begin sw1.Start; Result := False; j1 := TMyJpeg.Create; j2 := TMyJpeg.Create; try j1.LoadFromFile(fnFrom); j2.LoadFromFile(fnTo); Result := j1.Bitmap.Equals(j2.Bitmap); finally j1.Free; j2.Free; end; sw1.Stop; end; 有没有直接访问文件中的像素数据字节(跳过元数据字节)而无需位图转换的方法? 解决方法
JPEG文件由块组成,这些块由标记标识.块的结构(独立的SOI,EOI,RSTn除外):
chunk type marker (big-endian FFxx) chunk length (big-endian word) data (length-2 bytes) 编辑:SOS块受另一个标记的限制,而不是长度. 元数据块以APPn标记(FFEn)开始,但具有JFIF标题的APP0(FFE0)标记除外. 所以我们只能读取和比较重要的块并忽略APPn块和COM块(如TLama注意到的). 示例:某些jpeg文件的十六进制视图: 它以SOI(图像开始)标记FFD8(独立,无长度)开始, 然后APP0块(FFE0)长度= 16字节, 然后APP1块(FFE1),其中包含元数据(EXIF数据,NIKON COOLPIX名称等),因此我们可以忽略9053字节(23 5D)并检查地址2373处的下一个块标记,依此类推…… 编辑:简单解析示例: var jp: TMemoryStream; Marker,Len: Word; Position: Integer; PBA: PByteArray; procedure ReadLenAndMovePosition; begin Inc(Position,2); Len := Swap(PWord(@PBA[Position])^); Inc(Position,Len); end; begin jp := TMemoryStream.Create; jp.LoadFromFile('D:3.jpg'); Position := 0; PBA := jp.Memory; while (Position < jp.Size - 1) do begin Marker := Swap(PWord(@PBA[Position])^); case Marker of $FFD8: begin Memo1.Lines.Add('Start Of Image'); Inc(Position,2); end; $FFD9: begin Memo1.Lines.Add('End Of Image'); Inc(Position,2); end; $FFE0: begin ReadLenAndMovePosition; Memo1.Lines.Add(Format('JFIF Header Len: %d',[Len])); end; $FFE1..$FFEF,$FFFE: begin ReadLenAndMovePosition; Memo1.Lines.Add(Format('APPn or COM Len: %d Ignored',[Len])); end; $FFDA: begin //SOS marker,data stream,ended by another marker except for RSTn Memo1.Lines.Add(Format('SOS data stream started at %d',[Position])); Inc(Position,2); while Position < jp.Size - 1 do begin if PBA[Position] = $FF then if not (PBA[Position + 1] in [0,$D0..$D7]) then begin Inc(Position,2); Memo1.Lines.Add(Format('SOS data stream ended at %d',[Position])); Break; end; Inc(Position); end; end; else begin ReadLenAndMovePosition; Memo1.Lines.Add(Format('Marker %x Len: %d Significant',[Marker,Len])); end; end; end; jp.Free; end; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |