全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:3944
推到 Plurk!
推到 Facebook!

怎样快速比对两幅图像是否完全一致

答題得分者是:wameng
whoawho
一般會員


發表:13
回覆:18
積分:6
註冊:2004-03-16

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-10-04 03:45:34 IP:220.173.xxx.xxx 未訂閱
既定条件: 一、内存(记忆体)中已有500多个TBitmap的样版组A; 二、TBitmap每个样版的大小为30*50(X*Y); 问:当有测试的TBitmap(30*50)B送到,怎样快速的比对出B与A中哪一个模版完全一致? 目前能想到的办法: 1、看到有资料介绍用scanline之后,逐Byte比对,但这样的方法在模版数量以及测试样品数量较多的时候,极为缓慢,无法适应及时响应的需求; 2、后来想到用GetDIBits将模版和样品都转为内存数据,然后用CompareMem来做比对,不知道这样的想法是否可行?如果可行,请各位大大给出一段示范代码。 3、另外,如果上面的样板组A的图像格式为8位、16位、24位(全样板组同一格式),按照2的处理方法会有不同吗? 4、或者有更好更快的比对图像的办法? 望不吝赐教。 發表人 - whoawho 於 2004/10/04 03:47:57 發表人 - whoawho 於 2004/10/04 03:52:17
wameng
版主


發表:31
回覆:1336
積分:1188
註冊:2004-09-16

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-10-04 10:38:00 IP:61.222.xxx.xxx 未訂閱
您的想法有點意思! 1. 目前來看用 ScanLine 是作法是比較簡單、明瞭。 還是有可以再提升比對速度的方式。要視您的做法而定。 { 或用 Direct Draw 在效率比較好!} 2.建議用Scanline。 GetBitmapBits是位了兼容16位元的程序保留的,32位程序應該用GetDiBits。 其實與ScanLine的速度差不多,而Scanline更容易使用。 另外 CompareMem 可以用 TmemoryStream 代入,會比較快。 如 function StreamsEqual(S1, S2: TMemoryStream): Boolean; begin Result := (S1.Size = S2.Size) and CompareMem(S1.Memory, S2.Memory, S1.Size); end; {用 BMP.SavetoStream } 不過使用這種方式,如果圖形內容格式不同、圖形略不同、檔頭不同 可能都會影響判斷! 3.图像格式为8位、16位、24位,並需先轉換與樣版相同的Format 由於在轉換當中可能會失真 or .... 誤判的機率很大的! 4.由於不曉得,您主要比對的因素是什麼! 影像識別、或者...... 依據此找出判斷的要點,因而找到合適的方法。 如果單單只是比對檔案的內容,不就得了!
andychang1690
資深會員


發表:20
回覆:694
積分:442
註冊:2003-03-14

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-10-04 11:10:45 IP:221.169.xxx.xxx 未訂閱
whoawho:以前有一位Tsay Yih-yuan 寫的一個 Duplicate Image Hunter 1.0 Beta 9 Freeware 禁止作任何商業用途 內容是: 搜尋電腦中重複的圖形檔案以及其他類型的檔案,更可以影像內容作比對搜 尋,同樣的圖形,就算是以不同的壓縮比來儲存,或者是不同的影像檔案格 式,都可以幫你找出來。 圖形檔並提供預覽的功能;其它類型的檔案可用系統預定的應用程式開啟。 他並沒有提供原始程式但介紹中提到他的作法提供給你參考! 尤其下文紅字段是一個方向。 ※重複檔案比對項目分為檔名,檔案大小,檔案內容,影像內容,影像長 寬五種,可任意組合。若是全部都不選,則表示列出所有的檔案。 ※比對檔案內容時,可以自行設定內容比對的百分比。設為100%時,表 示當檔案在比對內容時,會比對全部的檔案內容,但是此時會花費較多 的時間。建議設為5%即可,以圖形檔為例,當兩個不同內容的圖形檔 ,雖然檔案的大小相同,但是其檔案內容的前面5%都完全相同的可能 性是非常低的,因此,設為5%或許結果可能會有些許的誤差,但機率 不大。而且可以節省很多的時間。 若是選擇比對影像內容時,影像比對誤差度選擇5%即可。以兩張同樣 影像內容,但壓縮比不同的JPEG檔案為例,其影像比對誤差度大多介 於1%~4%之間。 因為我是採用抽樣比對的方式,所以有些同樣背景的圖形,或者是色調 接近的圖形,會判斷是相同的圖形。不過若是增加比對的樣本數量,雖 然結果的誤差會比較少,但花費的時間反而更多,權衡之下,還是以節 省時間為主要的考量因素。 ※顯示執行進度。在執行時,會在下方的狀態列顯示目前的執行進度。但 是因為ProgressBar牽涉到螢幕繪圖的關係,會用掉比較多的時間, 所以會稍微的拖慢搜尋的時間。時間就是金錢的人,可以把這個功能關 閉。若是選擇關閉,因為不曉得執行狀態,在執行時,若是硬碟是在讀 取的狀態,則表示程式正常的執行中,請稍後片刻。 重複檔案的搜尋,主要分為三個步驟: (1)搜集檔案的資訊 由指定的檔案資料夾之中,蒐集檔案類型符合的所有檔案資訊。因為只 有讀取檔案的資訊,所以速度算是很快。若是要比對影像內容或是影像 長寬時,因為還要讀取影像的長寬,所以還要花費多一些的時間。 (2)排序 根據指定的比對項目,依據檔案的檔名、大小或是影像長寬來做排序。 這部分我是用宇宙銀河超級無敵霹靂最快最Turbo的QuickSort來作, 就算是五萬筆的資料,在一兩秒之內,輕輕鬆鬆就搞定了。所以排序所 花費的時間,基本上可以忽略。 (3)內容比對 若是有選擇要找出相同檔案內容或是圖形內容時,則進行這個步驟。 檔案內容比對只比對檔案大小相同的檔案。 影像內容比對只比對影像長寬相同的圖形。(目前只支援JPEG,GIF, Bitmap三種圖形格式的檔案) 這部分最花時間,依每個人硬碟讀取的速度而有不同。當然,搜尋愈多 的檔案,要花的時間愈多。尤其是影像內容比對部分,因為必須讀入全 部的檔案,再針對其圖形作比對,更是需要花費較多的時間。 以我的電腦為例(K6-2-350MhzOverClock420Mhz UltraDMA66硬 碟 128MBSDRAM),針對約五萬八千個圖形檔作影像內容的比對搜尋 ,總共大約花了125分鐘。 使用的元件: JemNaadiAhmed的FileSearch元件 jemna@yahoo.com BradStowers的TdfsBrowseDirectoryDlg元件 http://www.delphifreestuff.com AndersMelander的TGIFImage元件 anders@melander.dk AlvaroL.S.Almeida的DrLABEL元件 http://www.di.com.br 請參考! Andy Chang
------
Andy Chang
whoawho
一般會員


發表:13
回覆:18
積分:6
註冊:2004-03-16

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-10-04 13:11:28 IP:220.173.xxx.xxx 未訂閱
感谢andychang的指教,使我能了解更为深远的图像处理方法,谢谢!!! 由于我遇到的问题是要求比对“完全一致”的图像,意即“每一个像素都必须一致”,所以,这次的结案就感谢wameng了。 多谢wameng提及的BMP.SavetoStream方法,我随即去试试看。 至于wameng所担心的图像格式的问题,在我的问题中并不存在,因为所有的样板都保持一致,即:所有的样板都为8位,或者所有的样板都为16位,不会出现两种以上格式同时存在的可能。 發表人 - whoawho 於 2004/10/04 13:13:33
japhenchen
高階會員


發表:51
回覆:444
積分:184
註冊:2003-07-23

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-10-04 14:54:21 IP:211.96.xxx.xxx 未訂閱
我的做法是将TBitmap.Savetostream进TMemoryStream里头,直接对Stream作CRC32编码之后,只记录那个编码后的DWORD值(int64),就算是比对100万张图片,也只需要一百万个INT64元素的数组就能全部記錄起來,只要比對這個CRC32編碼後的值就行,這樣可以提升比對速度哦! CRC32的編碼方式(取錄自TORRY DELPHI TIPS網站)
// The constants here are for the CRC-32 generator 
// polynomial, as defined in the Microsoft 
// Systems Journal, March 1995, pp. 107-108 
const 
  Table: array[0..255] of DWORD = 
    ($00000000, $77073096, $EE0E612C, $990951BA, 
    $076DC419, $706AF48F, $E963A535, $9E6495A3, 
    $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988, 
    $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91, 
    $1DB71064, $6AB020F2, $F3B97148, $84BE41DE, 
    $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7, 
    $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC, 
    $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5, 
    $3B6E20C8, $4C69105E, $D56041E4, $A2677172, 
    $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B, 
    $35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940, 
    $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59, 
    $26D930AC, $51DE003A, $C8D75180, $BFD06116, 
    $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F, 
    $2802B89E, $5F058808, $C60CD9B2, $B10BE924, 
    $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D,         $76DC4190, $01DB7106, $98D220BC, $EFD5102A, 
    $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433, 
    $7807C9A2, $0F00F934, $9609A88E, $E10E9818, 
    $7F6A0DBB, $086D3D2D, $91646C97, $E6635C01, 
    $6B6B51F4, $1C6C6162, $856530D8, $F262004E, 
    $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457, 
    $65B0D9C6, $12B7E950, $8BBEB8EA, $FCB9887C, 
    $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65, 
    $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2, 
    $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB, 
    $4369E96A, $346ED9FC, $AD678846, $DA60B8D0, 
    $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9, 
    $5005713C, $270241AA, $BE0B1010, $C90C2086, 
    $5768B525, $206F85B3, $B966D409, $CE61E49F, 
    $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4, 
    $59B33D17, $2EB40D81, $B7BD5C3B, $C0BA6CAD,         $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A, 
    $EAD54739, $9DD277AF, $04DB2615, $73DC1683, 
    $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8, 
    $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1, 
    $F00F9344, $8708A3D2, $1E01F268, $6906C2FE, 
    $F762575D, $806567CB, $196C3671, $6E6B06E7, 
    $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC, 
    $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5, 
    $D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252, 
    $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B, 
    $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60, 
    $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79, 
    $CB61B38C, $BC66831A, $256FD2A0, $5268E236, 
    $CC0C7795, $BB0B4703, $220216B9, $5505262F, 
    $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04, 
    $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D,         $9B64C2B0, $EC63F226, $756AA39C, $026D930A, 
    $9C0906A9, $EB0E363F, $72076785, $05005713, 
    $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38, 
    $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21, 
    $86D3D2D4, $F1D4E242, $68DDB3F8, $1FDA836E, 
    $81BE16CD, $F6B9265B, $6FB077E1, $18B74777, 
    $88085AE6, $FF0F6A70, $66063BCA, $11010B5C, 
    $8F659EFF, $F862AE69, $616BFFD3, $166CCF45, 
    $A00AE278, $D70DD2EE, $4E048354, $3903B3C2, 
    $A7672661, $D06016F7, $4969474D, $3E6E77DB, 
    $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0, 
    $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9, 
    $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6, 
    $BAD03605, $CDD70693, $54DE5729, $23D967BF, 
    $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94, 
    $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D);     type 
//----------------------------------crc32---------------------------------- 
  {$IFDEF VER130}           // This is a bit awkward 
    // 8-byte integer 
    TInteger8 = Int64;     // Delphi 5 
  {$ELSE} 
  {$IFDEF VER120} 
    TInteger8 = Int64;     // Delphi 4 
  {$ELSE} 
    TInteger8 = COMP;      // Delphi  2 or 3 
  {$ENDIF} 
  {$ENDIF} 
//----------------------------------crc32----------------------------------        
  // Use CalcCRC32 as a procedure so CRCValue can be passed in but 
  // also returned. This allows multiple calls to CalcCRC32 for 
  // the "same" CRC-32 calculation. 
procedure CalcCRC32(p: Pointer; ByteCount: DWORD; var CRCValue: DWORD); 
  // The following is a little cryptic (but executes very quickly). 
  // The algorithm is as follows: 
  // 1. exclusive-or the input byte with the low-order byte of 
  // the CRC register to get an INDEX 
  // 2. shift the CRC register eight bits to the right 
  // 3. exclusive-or the CRC register with the contents of Table[INDEX] 
  // 4. repeat steps 1 through 3 for all bytes 
var 
  i: DWORD; 
  q: ^BYTE; 
begin 
  q := p; 
  for i := 0 to ByteCount - 1 do 
  begin 
    CRCvalue := (CRCvalue shr 8) xor 
      Table[q^ xor (CRCvalue and $000000FF)]; 
    Inc(q) 
  end 
end {CalcCRC32};     function CalcStringCRC32(s: string; out CRC32: DWORD): Boolean; 
var 
  CRC32Table: DWORD; 
begin 
  // Verify the table used to compute the CRCs has not been modified. 
  // Thanks to Gary Williams for this suggestion, Jan. 2003. 
  CRC32Table := $FFFFFFFF; 
  CalcCRC32(Addr(Table[0]), SizeOf(Table), CRC32Table); 
  CRC32Table := not CRC32Table;       if CRC32Table <> $6FCF9E13 then ShowMessage('CRC32 Table CRC32 is '   
      IntToHex(Crc32Table, 8)   
      ', expecting $6FCF9E13') 
  else 
  begin 
    CRC32 := $FFFFFFFF; // To match PKZIP 
    if Length(s) > 0  // Avoid access violation in D4 
      then CalcCRC32(Addr(s[1]), Length(s), CRC32); 
    CRC32 := not CRC32; // To match PKZIP 
  end; 
end;     procedure CalcFileCRC32(FromName: string; var CRCvalue: DWORD; 
  var TotalBytes: TInteger8; 
  var error: Word); 
var 
  Stream: TMemoryStream; 
begin 
  error := 0; 
  CRCValue := $FFFFFFFF; 
  Stream := TMemoryStream.Create; 
  try 
    try 
      Stream.LoadFromFile(FromName); 
      if Stream.Size > 0 then CalcCRC32(Stream.Memory, Stream.Size, CRCvalue) 
      except 
        on E: EReadError do 
          error := 1 
    end; 
    CRCvalue := not CRCvalue 
  finally 
    Stream.Free 
  end; 
end;     procedure TForm1.Button1Click(Sender: TObject); 
var 
  s: string; 
  CRC32: DWORD; 
begin 
  s := 'Test String'; 
  if CalcStringCRC32(s, CRC32) then 
    ShowMessage(IntToStr(crc32)); 
end;     
藏私の禁止
japhenchen
高階會員


發表:51
回覆:444
積分:184
註冊:2003-07-23

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-10-04 15:18:10 IP:67.15.xxx.xxx 未訂閱
就以你的例子为例,如果以内存比对的方式来处理,500张图就要比对125001次,那每一张图都要比对一次内存内容,一张图就有30*50=1500个像素,8位的图就要比对1500个位的值,两张图各读一次也要花上3000次的单位内存读取的时间,125001次比对所有的图片,一共要花上375003000个的单位内存读取时间 用我刚刚的方法,每张图只要读取一次,500张图一共需要花费1500*500=750000次的内存读取时间,INT64占8位长度,两张图共16位,比对500张图需16*125001=2000016次单位内存读取时间,加上开始读图的时间,大概耗时2750016个单位时间 第一种方法需时375003000单位时间 第二种方法需时2750016 单位时间 差别有多大?136倍,如果第二种方法需时1分钟,那第一种方法就要136分钟,两个多小时... 藏私の禁止
japhenchen
高階會員


發表:51
回覆:444
積分:184
註冊:2003-07-23

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-10-04 15:29:03 IP:67.15.xxx.xxx 未訂閱
CRC32 可以视为一种简单的HASH编码方式,当然也有可能产生碰撞(两个完全不同的文件产生相同的结果),但是机率不会太高,如果你担心发生这样的问题,建议使用其它的哈虚编码方式,像是MD5,SHA0/1,碰撞的可能性会降到非常非常低。。。像现在非常有名的P2P工具大部分都用MD5作哈虚编码,在网上寻找种子下载的时候可以省掉非常多的带宽浪费还有比对时间......CRC32并不是不好,只是。。。年代比较久远了。。。 藏私の禁止
japhenchen
高階會員


發表:51
回覆:444
積分:184
註冊:2003-07-23

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-10-04 16:03:28 IP:67.15.xxx.xxx 未訂閱
说到HASH碰撞,这个是最近的一件软件加密的重大事件,中国山东大学的王小云教授破解了MD5的加密方法,关键就是碰撞。。。。 说破了很简单,MD5这种东西,就是将一连串的内存内容依照查表的方式,一个字元转成一个长整数,旋转后取末尾几位的值,在和下一个字元查表值作反或运算,一直这样做下去..得出来的结果就是我们要的Hash值,原则上是没有任何不同的文件(或字符串)产生相同的Hash值,这个原则已经被深信不疑很久一段时间了,一直到了上个月....这个王教授,女性一语道破了这个编码.... 【碰撞=漏洞=别人可以伪造和冒用数字签名】 何谓“碰撞”?就是用一个无止尽长度的文件(内存流),试图去产生一组hash编码,一直到这组新编码和之前文件产生出来的HASH值相同为止。 这种方法是否可行?大家有空可以试验看看。。。。 藏私の禁止
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-10-04 22:44:44 IP:61.64.xxx.xxx 未訂閱
【轉貼】密碼學領域重大發現:山東大學王小雲教授成功破解MD5 http://delphi.ktop.com.tw/topic.php?topic_id=56398 這有較詳細說明 碰撞是=或不= 破解 見解不同 假設 如果一條 線 雖有頭與尾 雖知頭尾長度 但不一定知道 頭尾出口的角度與方向(庵亂掰的) md5仍是好用的方式
japhenchen
高階會員


發表:51
回覆:444
積分:184
註冊:2003-07-23

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-10-04 23:17:58 IP:67.15.xxx.xxx 未訂閱
我想conundrum兄是想多了,我並不是有意要去討論"HASH"的碰撞是否等於"破解",只是藉題發揮,如果害怕擔心CHECKSUM之後的結果會可能出現不同的檔案有相同的結果,那就換個加密的方法,反正用來內容比對,速度會快很多很多的~~ 藏私の禁止
whoawho
一般會員


發表:13
回覆:18
積分:6
註冊:2004-03-16

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-10-06 05:12:28 IP:222.83.xxx.xxx 未訂閱
多谢各位的详细指点。 试过japhenchen的方法,完全可行。 因为原有方法已经达到“及时响应”,在样板数量没有大的变化的情况下,japhenchen的方法肉眼没有看出时间的差别,但是,从方法上来看,应该是比我所用前一种方法有非常大的优势,在将来可能的应用中应能发挥作用。 再次感谢各位。
系統時間:2024-04-28 6:05:08
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!