GVKun编程网logo

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

20

此处将为大家介绍关于delphi–比较JPEG图像的最快解决方案是什么?(忽略元数据,只是“像素”)的详细内容,此外,我们还将为您介绍关于c–在OpenGL中每帧绘制新的全屏图像的最快方法是什么?、c

此处将为大家介绍关于delphi – 比较JPEG图像的最快解决方案是什么? (忽略元数据,只是“像素”)的详细内容,此外,我们还将为您介绍关于c – 在OpenGL中每帧绘制新的全屏图像的最快方法是什么?、c – 暂停和恢复pthread的最佳解决方案是什么?、delphi – 使用TidHttp从URL下载Jpeg图像(只有那些存在的)?、delphi – 加载和重新调整图像大小的最快方法是什么?的有用信息。

本文目录一览:

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

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;

c – 在OpenGL中每帧绘制新的全屏图像的最快方法是什么?

c – 在OpenGL中每帧绘制新的全屏图像的最快方法是什么?

每个帧,我的程序将从USB摄像机接收新图像.该映像最初将位于cpu内存中. OpenGL中将此图像绘制到屏幕以使其填满整个屏幕的最快方法是什么?

目前,我正在将图像数据上传到纹理,然后渲染全屏四边形.但是,这在我尝试的不同机器上运行得不是很快.

解决方法

Currently,I’m uploading the image data to a texture and then rendering a fullscreen quad. However,this doesn’t run very quickly on a different machine that tried. Any ideas? Thanks.

glTexImage2D执行完整的纹理初始化(这意味着,分配,对象设置等).如果您只想用相同大小的图像替换纹理图像,请使用glTexSubImage2D,这要快得多.如果你想异步这样做,那么看看Pixel Buffer Objects

c – 暂停和恢复pthread的最佳解决方案是什么?

c – 暂停和恢复pthread的最佳解决方案是什么?

我找到了关于pthread的以下主题( here),但有很多好的解决方案.

我想知道下面的代码是否有效,如果是这样,为什么同一个锁被用来调用pthread_cond_wait以及访问它,然后立即解锁:

void suspendMe(){    pthread_mutex_lock(&m_SuspendMutex);    pthread_cond_wait(&m_ResumeCond,&m_SuspendMutex);    pthread_mutex_unlock(&m_SuspendMutex);}

在这里使用2个独立的互斥体是不是更好,或者这是挂起pthread的正确方法?

提前致谢!

编辑:

真棒回复,谢谢大家.
只是一个有关的问题.既然我想在另一个函数中单独恢复一个线程,那么在恢复它时会更合适吗?

void suspendMe(){    pthread_mutex_lock(&m_SuspendMutex);    pthread_cond_wait(&m_ResumeCond,&m_SuspendMutex);}void resumeMe(){    pthread_cond_signal(&m_ResumeCond);    pthread_mutex_unlock(&m_SuspendMutex);}

再次感谢大家! :〜)

解决方法

其实这个代码不是线程安全的.互斥体实际上并不保护任何东西,使隐含的谓词容易受到种族条件的影响.

看这个代码 – 什么是互斥体保护?什么保护暂停/恢复状态?

void suspendMe(){    pthread_mutex_lock(&m_SuspendMutex);    pthread_cond_wait(&m_ResumeCond,&m_SuspendMutex);}void resumeMe(){    pthread_cond_signal(&m_ResumeCond);    pthread_mutex_unlock(&m_SuspendMutex);}

这是对的:

void suspendMe(){ // tell the thread to suspend    pthread_mutex_lock(&m_SuspendMutex);    m_SuspendFlag = 1;    pthread_mutex_unlock(&m_SuspendMutex);}void resumeMe(){ // tell the thread to resume    pthread_mutex_lock(&m_SuspendMutex);    m_SuspendFlag = 0;    phtread_cond_broadcast(&m_ResumeCond);    pthread_mutex_unlock(&m_SuspendMutex);}void checkSuspend(){ // if suspended,suspend until resumed    pthread_mutex_lock(&m_SuspendMutex);    while (m_SuspendFlag != 0) pthread_cond_wait(&m_ResumeCond,&m_SuspendMutex);    pthread_mutex_unlock(&m_SuspendMutex);}

线程应该在可以暂停的安全点调用checkSuspend.其他线程可以调用suspendMe和resumeMe挂起/恢复线程.

请注意,现在mutex保护m_SuspendFlag变量,确保线程被告知要暂停,被告知恢复,并检查是否应该暂停或保持暂停,使代码线程安全.

Would it not be better to use 2 separate mutexes here,or is this the correct way to suspend a pthread??

使用两个互斥体将会消除条件变量的整个点.他们工作的整个机制是,您可以检查是否有某些您应该等待,然后在等待或不得不释放锁然后等待的情况下等待它,而不用持有锁.如果您在等待时握住锁,任何其他线程如何改变状态?如果你释放锁,然后等待,如果你错过了状态的变化会发生什么?

顺便说一下,暂停或恢复线程几乎没有意义.如果你觉得你需要从外面暂停一个线程,那就只是表示你编码的线程来做你实际上不想做的事情.关于暂停或恢复线程的问题通常表明线程编程的心理模型不正确.线程可能需要等待某事,但不应该从外部“暂停”,因为它应该已经知道自己的编码,当它不应该做一些特定的工作.

delphi – 使用TidHttp从URL下载Jpeg图像(只有那些存在的)?

delphi – 使用TidHttp从URL下载Jpeg图像(只有那些存在的)?

我试图使用TidHttp组件从Web检索大量图像.

问题是缺少许多图像(例如:7403,7412等)

我如何仅测试那些存在并将其保存到文件?

procedure TForm.Button1Click(Sender: TObject);
var
  MS : TMemoryStream;
  JPEGImage: TJPEGImage;
  Url,numString: String;
  I,Code: Integer;
begin
 for I := 7400 to 7500 do
 begin
 { 
   Url        :='http://www.mywebpage.com/images/DSC' + numString+  '.jpg';
   try
   idhttp1.Head(URL);
   code := idhttp1.ResponseCode;
   except on E: EIdHTTPProtocolException do
    code := idhttp1.ResponseCode;
   end;//try except
   if code = 200 then
   begin

   MS := TMemoryStream.Create;
   JPEGImage  := TJPEGImage.Create;
   try
     try
     idhttp1.Get(Url,MS); //Send the request and get the image
     code := idhttp1.ResponseCode;
     MS.Seek(0,soFromBeginning);
     JPEGImage.LoadFromStream(MS);//load the image in a Stream
     Image1.Picture.Assign(JPEGImage);//Load the image in a timage component
     Image1.Picture.SavetoFile('C:\Museum_Data\DSC' + numString + '.jpg');
     Application.ProcessMessages;
     except
      on E: EIdHTTPProtocolException do
        code := idhttp1.ResponseCode; // or: code := E.ErrorCode;
     end; //try except
          finally
    MS.free;
    JPEGImage.Free;

  end; //try finally
  end; //if

end;
 end;

解决方法

你不必为此做额外的事情.如果您尝试访问不存在的URL,HTTP服务器将报告TIdHTTP错误而不是包装到EIdHTTPProtocolException异常中.您不必先打扰调用TIdHTTP.Head(),因为您在保存之前将图像下载到TMemoryStream.您可以在单独调用TIdHTTP.Get()时捕获异常,根本不需要检查ResponseCode.

试试这个:

procedure TForm.Button1Click(Sender: TObject); 
var 
  MS: TMemoryStream; 
  JPEG: TJPEGImage; 
  Url: String; 
  I: Integer; 
begin 
  MS := TMemoryStream.Create;
  try
    JPEG := TJPEGImage.Create; 
    try 
      for I := 7400 to 7500 do 
      begin 
        Url := 'http://www.mywebpage.com/images/DSC' + IntToStr(I) +  '.jpg';
        MS.Clear;
        try
          IdHTTP1.Get(Url,MS);
        except
          on E: EIdHTTPProtocolException do 
            Continue;
        end;
        MS.Position := 0; 
        JPEG.LoadFromStream(MS);
        Image1.Picture.Assign(JPEG);
        JPEG.SavetoFile('C:\Museum_Data\DSC' + IntToStr(I) + '.jpg'); 
        Application.ProcessMessages; 
      end;
    finally
      JPEG.Free;
    end;
  finally 
    MS.Free;
  end;
end;

实际上,您不需要timage来将数据保存到文件中.如果您可以省略timage.Picture.Assign()阶段,那么通过完全消除TJPEGImage(除非您尝试验证下载文件是有效的),代码更简单一点,例如:

procedure TForm.Button1Click(Sender: TObject); 
var 
  MS: TMemoryStream; 
  Url: String; 
  I: Integer; 
begin 
  MS := TMemoryStream.Create;
  try
    for I := 7400 to 7500 do 
    begin 
      Url := 'http://www.mywebpage.com/images/DSC' + IntToStr(I) +  '.jpg';
      MS.Clear;
      try
        IdHTTP1.Get(Url,MS);
      except
        on E: EIdHTTPProtocolException do 
          Continue;
      end;
      MS.Position := 0; 
      MS.SavetoFile('C:\Museum_Data\DSC' + IntToStr(I) + '.jpg'); 
      Application.ProcessMessages; 
    end;
  finally 
    MS.Free;
  end;
end;

要么:

procedure TForm.Button1Click(Sender: TObject); 
var 
  FS: TFileStream; 
  Url,FileName: String; 
  I: Integer; 
begin 
  for I := 7400 to 7500 do 
  begin 
    Url := 'http://www.mywebpage.com/images/DSC' + IntToStr(I) +  '.jpg';
    FileName := 'C:\Museum_Data\DSC' + IntToStr(I) + '.jpg'; 
    FS := TFileStream.Create(FileName,fmCreate);
    try
      try
        try
          IdHTTP1.Get(Url,FS);
        except
          on E: EIdHTTPProtocolException do 
            Continue;
        end;
        Application.ProcessMessages; 
      finally
        Fs.Free;
      end;
    except
      DeleteFile(FileName);
    end;
  end;
end;

delphi – 加载和重新调整图像大小的最快方法是什么?

delphi – 加载和重新调整图像大小的最快方法是什么?

我需要在给定目录中显示图像的缩略图.在将图像加载到图像组件之前,我使用TFileStream来读取图像文件.然后将位图的大小调整为缩略图大小,并分配给TScrollBox上的T Image组件.

它似乎工作正常,但是对于较大的图像,速度会慢下来.

是否有更快的方法从磁盘加载(图像)文件并调整它们的大小?

谢谢,彼得

解决方法

并不是的.您可以做的是在后台线程中调整它们的大小,并使用“占位符”图像,直到调整大小完成.然后我会将这些已调整大小的图像保存到某种缓存文件中以供稍后处理( Windows会执行此操作,并在当前目录中调用缓存thumbs.db).

线程架构本身有几个选项.执行所有映像的单个线程,或者线程只知道如何处理单个映像的线程池. AsyncCalls库甚至是另一种方式,可以保持相当简单.

关于delphi – 比较JPEG图像的最快解决方案是什么? (忽略元数据,只是“像素”)的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于c – 在OpenGL中每帧绘制新的全屏图像的最快方法是什么?、c – 暂停和恢复pthread的最佳解决方案是什么?、delphi – 使用TidHttp从URL下载Jpeg图像(只有那些存在的)?、delphi – 加载和重新调整图像大小的最快方法是什么?的相关知识,请在本站寻找。

本文标签: