1. 程式人生 > >關於統計變換(CT/MCT/RMCT)演算法的學習和實現

關於統計變換(CT/MCT/RMCT)演算法的學習和實現

剛開會每週的例會,最討厭開會了,不過為了能順利畢業,只能忍了。閒話不多說了,下面把上週學習的一個簡單的演算法總結一下,以備後面寫畢業論文的時候可以參考一下。 一、Census Transform(CT)演算法的學習     Census Transform 演算法是Ramin Zabih 和 John Woodfill 於1994年在他們的論文《Non-parametric LocalTransforms for Computing VisualCorrespondence》中提出的,正如他們在論文中所說,這是一種非引數變換,主要用來表徵影象的區域性結構特徵,能夠比較好的檢測到影象中的邊緣特徵和角點特徵,從這篇論文的470次的引用次數來看,CT演算法用處還是挺廣泛的。下面簡要介紹一下CT演算法的基本思想:用一個3*3或者5*5的滑動視窗遍歷整幅影象,對於每次遍歷的位置,以3*3為例,假設某個位置如下圖所示
123 127 129
126 128 129
127 131 130
然後比較此視窗中每個畫素值(中心除外)與中心畫素值的大小,如果比中心畫素值小,則比較結果為1,否則為0。由此,得到如下結果:

1 1 0
1 0
1 0 0

然後,把此視窗結果組成一個序列:11010100,以此二進位制序列表示的值來代替原影象視窗中心點的畫素。如此下去,等到視窗滑動完整幅影象,我們就得到原影象做統計變換(CT)之後的影象。

注意:只能作用於灰度影象,對於彩色影象,則需要轉換為灰度圖之後再操作;為了簡單起見,我沒有考慮影象的邊緣畫素值。  下面給出一種用 matlab 實現的版本:
  1. % *************************************************************************  
  2. % Title: Function-Census Transform of a given Image  
  3. % Author: Siddhant Ahuja  
  4. % Created: May 2008  
  5. % Copyright Siddhant Ahuja, 2008  
  6. % Inputs: Image (var: inputImage), Window size assuming square window (var:  
  7. % windowSize) of 3x3 or 5x5 only.  
  8. % Outputs: Census Tranformed Image (var: censusTransformedImage),  
  9. % Time taken (var: timeTaken)  
  10. % Example Usage of Function: [a,b]=funcCensusOneImage('Img.png', 3)  
  11. % *************************************************************************  
  12. function [censusTransformedImage, timeTaken] = funcCensusOneImage(inputImage, windowSize)  
  13. % Grab the image information (metadata) using the function imfinfo  
  14. try  
  15. imageInfo = imfinfo(inputImage);  
  16. % Since Census Transform is applied on a grayscale image, determine if the  
  17. % input image is already in grayscale or color  
  18. if(getfield(imageInfo,'ColorType')=='truecolor')  
  19. % Read an image using imread function, convert from RGB color space to  
  20. % grayscale using rgb2gray function and assign it to variable inputImage  
  21. inputImage=rgb2gray(imread(inputImage));  
  22. else if(getfield(imageInfo,'ColorType')=='grayscale')  
  23. % If the image is already in grayscale, then just read it.         
  24. inputImage=imread(inputImage);  
  25. else  
  26. error('The Color Type of Input Image is not acceptable. Acceptable color types are truecolor or grayscale.');  
  27. end  
  28. end  
  29. catch  
  30. inputImage = inputImage;  
  31. end  
  32. % Find the size (columns and rows) of the image and assign the rows to  
  33. % variable nr, and columns to variable nc  
  34. [nr,nc] = size(inputImage);  
  35. % Check the size of window to see if it is an odd number.  
  36. if (mod(windowSize,2)==0)  
  37. error('The window size must be an odd number.');  
  38. end  
  39. if (windowSize==3)  
  40. bits=uint8(0);  
  41. % Create an image of size nr and nc, fill it with zeros and assign  
  42. % it to variable censusTransformedImage of type uint8  
  43. censusTransformedImage=uint8(zeros(nr,nc));  
  44. else if (windowSize==5)  
  45. bits=uint32(0);  
  46. % Create an image of size nr and nc, fill it with zeros and assign  
  47. % it to variable censusTransformedImage of type uint32         
  48. censusTransformedImage=uint32(zeros(nr,nc));  
  49. else  
  50. error('The size of the window is not acceptable. Just 3x3 and 5x5 windows are acceptable.');  
  51. end  
  52. end  
  53. % Initialize the timer to calculate the time consumed.  
  54. tic;  
  55. % Find out how many rows and columns are to the left/right/up/down of the  
  56. % central pixel  
  57. C= (windowSize-1)/2;  
  58. for j=C+1:1:nc-C % Go through all the columns in an image (minus C at the borders)  
  59. for i=C+1:1:nr-C % Go through all the rows in an image (minus C at the borders)   
  60. census = 0; % Initialize default census to 0  
  61. for a=-C:1:C % Within the square window, go through all the rows  
  62. for b=-C:1:C % Within the square window, go through all the columns  
  63. if (~(a==0 && b==0)) % Exclude the centre pixel from the calculation,原來是(C+1),現改為0  
  64. census=bitshift(census,1); %Shift the bits to the left  by 1  
  65. % If the intensity of the neighboring pixel is less than  
  66. % that of the central pixel, then add one to the bit  
  67. % string  
  68. if (inputImage(i+a,j+b) < inputImage(i,j))  
  69. census=census+1;  
  70. end  
  71. end  
  72. end  
  73. end  
  74. % Assign the census bit string value to the pixel in imgTemp  
  75. censusTransformedImage(i,j) = census;  
  76. end  
  77. end  
  78. % Stop the timer to calculate the time consumed.  
  79. timeTaken=toc;  
   這是我在網上找到的一個實現的版本,註釋比較多,除去註釋的話,真正程式碼沒有50行,比較簡單,相信大家都可以看的懂。
  之前講了CT演算法的實現,下面說一下 MCT 以及 RMCT的實現。
二、Modified Census Transform (MCT)演算法     MCT 演算法是 CT 演算法的一個修改版本,它是由Bernhard Froba 在做人臉檢測的時候提出來的,在他2004年發表的論文《Face Detection with theModified Census Transform》中,Bernhard Froba將 CT演算法中“滑動視窗中每個畫素值與中心位置畫素做比較”改為“滑動視窗中每個畫素值與整個視窗中畫素的均值做比較”,這樣,原有的每個3*3的視窗可能產生256種序列(因為沒有算中心畫素),現在變為可能產生512種序列(其實全0和全1的序列表示的是同樣的資訊,可以排除一個),也就是做完MCT之後,影象的每個畫素值的範圍為0——511,這樣就能夠比較充分的利用3*3的核(至於為什麼這麼說,可以看看前面提到的那篇論文)。如此來計算的話,則前面例子產生的結果視窗應該為:
1 1 0
1 0 0
1 0 0

對應的二進位制序列為:110100100。然後以此作為中心畫素點的畫素值,迴圈完畢之後便得到MCT之後的影象。需要注意的一點是,如果要使變換之後的影象得到顯示,應該對畫素值做一下歸一化,使其在0——255之間。 三、Revised Modified Census Transform (RMCT)演算法     RMCT 演算法其實又是對 MCT的又一次修改,它與 MCT的不同之處僅僅在於一個微小的△m,即:在滑動視窗畫素均值上加上一個微小的變數△m=1或者2。其他都是完全一樣的。     下面附上這兩種修改版統計變換的 C++程式碼,程式碼是我自己編的,是基於VS2008和OpenCV2.0的,僅供參考:
  1. #include "stdafx.h" 
  2. #include "MCT.h" 
  3. #include "highgui.h" 
  4. MCT::MCT()   
  5. {   
  6.     window_size = 0;   
  7. }   
  8. MCT::~MCT()   
  9. {   
  10. }   
  11. void MCT::ModifiedCensusTransform(IplImage *input_image, IplImage *mct_image, constint window_size, constint delta )   
  12. {   
  13.     CvSize image_size = cvGetSize(input_image);   
  14.     int image_width = image_size.width;   
  15.     int image_height = image_size.height;   
  16.     IplImage *gray_image = cvCreateImage(cvGetSize(input_image), input_image->depth, 1);   
  17.     cvSetZero(gray_image);   
  18.     if(input_image->nChannels != 1)   
  19.     {   
  20.         cvCvtColor(input_image, gray_image, CV_RGB2GRAY);   
  21.     }   
  22.     else
  23.     {   
  24.         cvCopy(input_image, gray_image);   
  25.     }   
  26.     IplImage *modified_image = NULL;   
  27.     switch (window_size)   
  28.     {   
  29.     case 3:   
  30.         modified_image = cvCreateImage(image_size, IPL_DEPTH_16U, 1);   
  31.         cvSetZero(modified_image);   
  32.         break;   
  33.     case 5:   
  34.         modified_image = cvCreateImage(image_size, IPL_DEPTH_32S, 1);   
  35.         cvSetZero(modified_image);   
  36.         break;   
  37.     default:   
  38.         printf("window size must be 3 or 5!\n");   
  39.         exit(EXIT_FAILURE);   
  40.     }   
  41.     CvMat window;   
  42.     for(int i = 0; i < image_height - window_size; i++)   
  43.     {   
  44.         for(int j = 0; j < image_width - window_size; j++)   
  45.         {   
  46.             unsigned long census = 0;   
  47.             CvRect roi = cvRect(j, i, window_size, window_size);   
  48.             cvGetSubRect(gray_image, &window, roi);   
  49.             CvScalar m = cvAvg(&window, NULL);   
  50.             for(int w = 0; w < window_size; w++)   
  51.             {   
  52.                 for(int h = 0; h < window_size; h++)   
  53.                 {   
  54.                     census = census << 1; //左移1位 
  55.                     double tempvalue = cvGetReal2D(&window, w, h);   
  56.                     if(tempvalue < m.val[0] + delta)   
  57.                         census += 1;   
  58.                 }   
  59.             }   
  60.             cvSetReal2D(modified_image, i, j, census);   
  61.         }   
  62.     }   
  63.     //cvConvertScaleAbs(modified_image, mct_image, 1, 0); 
  64.     Normalize(modified_image, mct_image);   
  65.     cvReleaseImage(&gray_image);   
  66.     cvReleaseImage(&modified_image);   
  67. }   
  68. void MCT::Normalize(IplImage *mct_image, IplImage *nor_image)   
  69. {   
  70.     double minv, maxv;   
  71.     cvMinMaxLoc(mct_image, &minv, &maxv);   
  72.     for (int i = 0; i < mct_image->height; i++)   
  73.     {   
  74.         for (int j = 0; j < mct_image->width; j++)   
  75.         {   
  76.             double tempv = cvGetReal2D(mct_image, i, j);   
  77.             tempv = (tempv - minv) / (maxv - minv) * 255;   
  78.             cvSetReal2D(nor_image, i, j, tempv);   
  79.         }   
  80.     }   
  81. }   
由於演算法比較簡單,所以沒有寫註釋,應該比較容易理解。 四、CT/MCT/RMCT的應用    目前我讀到的幾篇論文裡面,他們主要用於人臉檢測或者面部偽裝檢測,用於做影象的預處理,這可能是因為CT演算法對光照不敏感,可以比較好的排除光照對影象的影響。這裡給出用到該演算法的幾篇paper: 1、《Face Detection with the Modified CensusTransform》(前面提到的那篇) 2、《Adaboost Based Disguised Face Discrimination on EmbeddedDevices》 3、《Disguised-Face Discriminator for Embedded Systems》 OVER!