加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 比较JPEG图像的最快解决方案是什么? (忽略元数据,只

发布时间:2020-12-15 09:20:11 所属栏目:大数据 来源:网络整理
导读:当我搜索单词“JPEG”和“元数据”时,我有很多答案来操纵元数据……这是我想要的相反……; o) 我写了一个函数,它完全像我想要的那样…(如果图像相似,只有元数据改变与否,函数返回True;如果至少有一个像素改变,则返回False)但是,我想要改善表现…… 瓶颈是bmp
当我搜索单词“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;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读