1. 程式人生 > >漢明距離的計算

漢明距離的計算

漢明距離,作為一種衡量特徵距離的計算方法,在很多場合都有應用,其主要思想是找到兩個特徵之間的差異大小,也可以說是相似性。

我是在影象處理中用到的,專案中需要計算影象梯度方向,我選擇了四個方向,這樣就可以用二位二進位制表示,分別為 0,1,2,3,也就是 00,01,10,11,這四種情況。這樣,我就可以可以把,例如四個臨近點,對應梯度特徵合併為一個特徵向量,如圖


只需要一個位元組的大小空間就可以表示一個特徵。那麼,我來用這個特徵描述兩張圖, 假設A,B,就得到了兩個特徵,featureA,featureB,在假設影象大小為100*100的8bit灰度影象,選擇水平方向的四個畫素,那麼我就可以得到 100*25個單位元組的描述特徵。接下來,我要怎麼衡量這兩張圖是不是相似,就要用到漢明距離(其他距離也可以,這裡直說漢明距離)。如果兩個影象在這種特徵下是相似的,那意味著他們特徵的對應位元位應該是儘可能多的一致,也就是說,featureA ^ featureB ,特徵的異或結果中1 的個數儘可能的少。這就涉及到,我們如何計算1的個數。這在leetcode和劍指offer等書中都有類似筆試面試題。

常規解法就是移位判斷是不是1,是則計數,需要注意,應該要判斷給定數(這裡用tmp表示)的符號,否則可能死迴圈。

  1. int CountOne(int tmp)
  2. {
  3. int count= 0;
  4. if( 0==tmp)
  5. return
    count;
  6. else if(tmp> 0)
  7. {
  8. while(tmp)
  9. {
  10. if(tmp& 1)
  11. ++count;
  12. tmp=tmp>> 1;
  13. }
  14. }
  15. else
  16. {
  17. tmp=-tmp;
  18. count= 1;
  19. while(tmp)
  20. {
  21. if(tmp& 1)
  22. ++count;
  23. tmp=tmp>> 1;
  24. }
  25. }
  26. return count;
  27. }

這樣還是不方便,我們可以不對tmp移位:

  1. int CountOneVersion2(int tmp)
  2. {
  3. int flag= 1;
  4. int count= 0;
  5. while(flag)
  6. {
  7. if(flag&tmp)
  8. ++count;
  9. flag=flag<< 1;
  10. }
  11. return count;
  12. }


這樣就少去了判斷符號的麻煩。

還有一種解法,那就是考慮到tmp每次減一後,最後一位1都會發生變化,這樣我們把剩下的保留,下次再減一,知道tmp為零位置,這樣就可以知道其中1的個數。

  1. int CountOneVersion3(int n)
  2. {
  3. int count= 0;
  4. while(n)
  5. {
  6. ++count;
  7. n=n&(n -1);
  8. }
  9. return count;
  10. }


以上是採用移位的方法,我們還可以不用移位,那就是下面的快速漢明距離計算的問題。我們先取三個數,這裡考慮unsigned char 型,也就一個位元組的情況。分別是 AA=85,即01010101,BB=51,即00110011,CC=15,即00001111;主要思想就是計算1的和,(1)一行是計算相鄰兩個位置的和,得到的結果最多需要兩位,然後(2)一行在計算相鄰四個位置的和,計算結果最多需要四位.(3)一行再把高四位和低四位相加,得到的就是1的個數。


  1. unsigned char A,B,Ch,D;
  2. const unsigned char AA = 85;
  3. const unsigned char BB = 51;
  4. const unsigned char CC = 15;
  5. A = tmp; B = A&AA; Ch = (A>> 1)&AA; //(1)
  6. D = B+Ch; B = D &BB; Ch = (D>> 2)&BB; //(2)
  7. D = B+Ch; B = D & CC; Ch = (D>> 4)&CC; //(3)
  8. ss += B+Ch;


應為是在硬體上實現,所以每個時鐘週期都要計較,要做效能優化,通過這樣的位運算,能夠顯著提升速度,這種計算單元重複度相當高,所以效能會提升很多。