幾種常見的圖像處理的方法

轉自:http://blog.csdn.net/smells2/article/details/7378840

=============================================

本章所涉及的方法有:灰度化彩色圖像,將圖像轉換爲ASNII碼文件,直方圖均衡化,伽馬校正,哈爾小波變換。

0.知識儲備

這裏我們處理的是bmp格式的圖像,bmp格式的文件有3個文件頭,第一個文件頭大小爲14個字節,主要是對整個文件的信息的存儲。

  1. typedef struct tagBITMAPFILEHEADER {  
  2.         WORD    bfType;  
  3.         DWORD   bfSize;  
  4.         WORD    bfReserved1;  
  5.         WORD    bfReserved2;  
  6.         DWORD   bfOffBits;  
  7. } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;  

第二個文件頭大小爲50個字節,主要存儲了圖像的信息,比如,圖像有多少行,多少列,大小等等。

  1. typedef struct tagBITMAPINFOHEADER{  
  2.         DWORD      biSize;  
  3.         LONG       biWidth;  
  4.         LONG       biHeight;  
  5.         WORD       biPlanes;  
  6.         WORD       biBitCount;  
  7.         DWORD      biCompression;  
  8.         DWORD      biSizeImage;  
  9.         LONG       biXPelsPerMeter;  
  10.         LONG       biYPelsPerMeter;  
  11.         DWORD      biClrUsed;  
  12.         DWORD      biClrImportant;  
  13. } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;  

第三個文件頭,是圖像的調色板,這裏我們使用的文件是24位真彩,所以沒有調色板,這個文件頭不存在,所以我就不列在下面了。

注意:bmp格式圖像數據是倒着存貯的,具體可以參考百度百科http://baike.baidu.com/view/7671.htm#2


1.將彩色圖像轉換爲灰度圖像

我們都知道,圖像是一像素爲單位的,一個像素有三個色彩分量組成,即RGB(紅綠藍),每一個分量由8位(一個字節)組成,範圍是0-255 。灰度圖像可由彩色圖像轉化,可以使用公式gray = 0.3*red+0.59*green+0.11*blue,並且三個分量的值相等,即red = gray,green=gray,blue=gray。那麼,我們的圖像就變成了灰度圖像。

  1. /******************************************** 
  2.  *     將文件轉換成灰度圖像           * 
  3.  ********************************************/  
  4. int CBitMapFile::turn2Gray()  
  5. {  
  6.     if (m_imageArray == NULL)  
  7.     {  
  8.         return -2;  
  9.     }  
  10.       
  11.     for (int i =0,j= 0,k=0;i<m_sizeImage;)  
  12.     {  
  13.         //轉換爲灰度圖像,注意填充的字節  
  14.         BYTE blue,green,red,gray;  
  15.   
  16.         blue = m_imageArray[i];  
  17.         green = m_imageArray[i+1];  
  18.         red = m_imageArray[i+2];  
  19.           
  20.         m_realColorImageArray[k] = blue;  
  21.         m_realColorImageArray[k+1] = green;  
  22.         m_realColorImageArray[k+2] = red;  
  23.   
  24.         gray = (BYTE)(0.3*red+0.59*green+0.11*blue);  
  25.   
  26.         m_imageArray[i] = gray;  
  27.         m_imageArray[i+1] = gray;  
  28.         m_imageArray[i+2] = gray;  
  29.   
  30.         m_realImageArray[j] = m_imageArray[i];  
  31.   
  32.         i += 3;  
  33.         k += 3;  
  34.         j++;  
  35.   
  36.         ////跳過填充字節  
  37.         if (j % m_width == 0)  
  38.         {  
  39.             i += m_addByte;  
  40.         }  
  41.           
  42.     }  
  43.       
  44.     return 1;  
  45. }  


2.圖像轉換爲ASNII碼文件

三個步驟:(1)提取圖像數據(2)建立映射表(3)處理灰度並映射

映射表我建立的是8個字符'@','$','#','%','!','~','^','`'

把灰度值除上32將其範圍映射到0-7這個範圍內。

將灰度值按照映射表映射。

  1. /****************************************** 
  2.  *對圖像的每個像素做文本映射,最終寫入文件* 
  3.  ******************************************/  
  4. int CBitMapFile::turn2Txt(CFile& txtFile)  
  5. {  
  6.     char* _txtBuf = new char[m_width*m_height+2*m_height];  
  7.     memset(_txtBuf,0,m_width*m_height+2*m_height);  
  8.   
  9.     //文本映射  
  10.     char txtMap[8] = {'@','$','#','%','!','~','^','`'};  
  11.   
  12.     char* _buf = new char[m_width+2];  
  13.     memset(_buf,0,m_width+2);  
  14.     //TRACE(_T("\'\\r\'=%x,\'\\n\'=%x"),'\r','\n');  
  15.     for (int i = m_height-1;i>=0;i--)  
  16.     {  
  17.         for (int j = 0;j<m_width;j++)  
  18.         {  
  19.             _buf[j] = txtMap[m_realImageArray[i*m_width+j]>>5];  
  20.               
  21.         }  
  22.           
  23.         _buf[m_width] = '\r';  
  24.         _buf[m_width+1] = '\n';  
  25.           
  26.         for (int k=0;k<m_width+2;k++)  
  27.         {  
  28.             _txtBuf[(m_height-1-i)*m_width+k+(m_height-1-i)*2] = _buf[k];  
  29.           
  30.         }  
  31.     }  
  32.       
  33.     txtFile.Write(_txtBuf,sizeof(char)*(m_width*m_height+2*m_height));  
  34.   
  35.     delete _txtBuf;  
  36.     delete _buf;  
  37.     return 1;  
  38. }  

3.直方圖均衡化

每一幅圖像都有自己的直方圖


圖像取自岡薩雷斯的《數字圖像處理》第三版

這幅圖像的灰度大部分集中在較高的灰度,均衡化就使圖像在概率率較大的地方稀疏一點,概率較小的地方稠密一點。

方法是:(1)統計各個灰度的概率(2)歸一化(3)畫直方圖(4)累計概率(5)取整得到映射(6)將原灰度值映射到新灰度值

  1. /******************************************** 
  2.  *  對bmp文件的每個像素的灰度值進行統計     * 
  3.  ********************************************/  
  4. int CBitMapFile::addupLevel()  
  5. {  
  6.     for (int i = 0;i<m_width*m_height;i++)  
  7.     {  
  8.         m_grayStatistic[m_realImageArray[i]] += 1;  
  9.           
  10.     }  
  11.     for (int i = 0;i<256;i++)  
  12.     {  
  13.         if (m_grayStatistic[i]>m_max)  
  14.         {  
  15.             m_max = m_grayStatistic[i];  
  16.         }  
  17.       
  18.     }  
  19.     //TRACE(_T("m_max = %d\n"),m_max);  
  20.     return 1;  
  21. }  
  22. /******************************************** 
  23.  *  對bmp文件的每個像素的灰度值進行歸一化    * 
  24.  *      並計算每個像素灰度值的概率           * 
  25.  ********************************************/  
  26. int CBitMapFile::turn2One()  
  27. {  
  28.     for (int i =0;i<256;i++)  
  29.     {  
  30.         m_grayTurn2OneData[i] = (double)m_grayStatistic[i]/m_max;  
  31.         m_grayFrequencyPerLevel[i] = (double)m_grayStatistic[i]/(m_width*m_height);  
  32.       
  33.     }  
  34.     m_maxFrequency = m_max/(m_width*m_height);  
  35.     return 1;  
  36. }  
  37.   
  38. /******************************************** 
  39.  *  清除統計數組、歸一化數組、頻率數組       * 
  40.  ********************************************/  
  41. void CBitMapFile::clearup()  
  42. {  
  43.     memset(m_grayStatistic,0,sizeof(LONG)*256);  
  44.     memset(m_grayTurn2OneData,0,sizeof(double)*256);  
  45.     memset(m_grayFrequencyPerLevel,0,sizeof(double)*256);  
  46.     m_max = 0;  
  47.     m_maxFrequency = 0.0f;  
  48. }  
  49. /******************************************** 
  50.  *              灰度均衡化                   * 
  51.  ********************************************/  
  52. void CBitMapFile::equation(CFile& file)  
  53. {  
  54.     double _temp =0.0f;  
  55.     double* _array = new double[256];  
  56.     memset(_array,0,sizeof(double)*256);  
  57.     int* _intArray = new int[256];  
  58.     memset(_intArray,0,sizeof(int)*256);  
  59.     BYTE* _writeArray = new BYTE[m_sizeImage];  
  60.     memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);  
  61.     for(int i = 0;i<256;i++)  
  62.     {  
  63.         _array[i] = ((m_grayFrequencyPerLevel[i])*255)+_temp;  
  64.         _temp = _array[i];  
  65.           
  66.     }  
  67.     for (int i = 0;i<256;i++)  
  68.     {  
  69.         _intArray[i] = (int)(_array[i]);  
  70.     }  
  71.     for (int i = 0,j = 0;i<m_sizeImage;)  
  72.     {  
  73.           
  74.         _writeArray[i] = _intArray[m_realImageArray[j]];  
  75.         _writeArray[i+1] = _intArray[m_realImageArray[j]];  
  76.         _writeArray[i+2] = _intArray[m_realImageArray[j]];  
  77.         j++;  
  78.         i += 3;  
  79.         if (j%m_width == 0)  
  80.         {  
  81.             for (int k = 0;k<m_addByte;k++)  
  82.             {  
  83.                 _writeArray[i+k] = 0;  
  84.                   
  85.             }  
  86.             i += m_addByte;  
  87.         }  
  88.     }  
  89.     file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));  
  90.     file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));  
  91.     file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);  
  92.     delete _array;  
  93.     delete _intArray;  
  94.     delete _writeArray;  
  95. }  


4.伽馬校正

伽馬校正其實很簡單,就是將舊的灰度值通過一個由灰度值爲底,伽馬次冪的映射得到新的灰度值,它的做用是,對於不同的伽馬係數的選取,會使得某些較亮的圖片,變得對比度適當。

  1. /******************************************** 
  2.  *              伽馬校正                    * 
  3.  ********************************************/  
  4. void CBitMapFile::gammaCorrection(double gamma,CFile& file)  
  5. {  
  6.     //數據準備  
  7.     double* _correctData = new double[m_width*m_height];  
  8.     BYTE* _writeArray = new BYTE[m_sizeImage];  
  9.     memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);  
  10.     memset(_correctData,0,sizeof(double)*m_width*m_height);  
  11.     //算法  
  12.     for (int i = 0;i<m_width*m_height;i++)  
  13.     {  
  14.         _correctData[i] = (double)m_realImageArray[i]/255;  
  15.       
  16.         _correctData[i] = pow(_correctData[i],gamma)*255;  
  17.   
  18.     }  
  19.     //寫入文件準備  
  20.     for (int i = 0,j = 0;i<m_sizeImage;)  
  21.     {  
  22.         _writeArray[i] = (BYTE)_correctData[j];  
  23.         _writeArray[i+1] = (BYTE)_correctData[j];  
  24.         _writeArray[i+2] = (BYTE)_correctData[j];  
  25.         j++;  
  26.         i += 3;  
  27.         if (j%m_width == 0)  
  28.         {  
  29.             for (int k = 0;k<m_addByte;k++)  
  30.             {  
  31.                 _writeArray[i+k] = 0;  
  32.                   
  33.             }  
  34.             i += m_addByte;  
  35.         }  
  36.     }  
  37.     //寫入文件  
  38.     file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));  
  39.     file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));  
  40.     file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);  
  41.       
  42.     delete _writeArray;  
  43.     delete _correctData;  
  44. }  


這個是伽馬選擇7.5的效果

4.哈爾小波變換(HWT,haar wavelet tansform)

這個是小波變換裏最簡單的一個,由於涉及較多的數學,這裏就不做贅述了,只是附上程序。(程序使用的矩陣乘法是我自己寫的,效率較低,經過測試在128*128的大小的圖像效果可以,再大就會出現未響應的現象。)

注意,哈爾小波變換的矩陣是偶數*偶數的,所以圖片的行列也必須是偶數。

Matrix.h

  1. #pragma once  
  2. #define ZERO 0  //零陣  
  3. #define IDENTITY 1//單位陣  
  4. #define HAAR 2//HAAR小波矩陣  
  5. #define UNSQUARE -1//非方陣  
  6. #define UNSAME -2//非同型矩陣  
  7. #define UNSAME -2//非同型矩陣  
  8. #define UNEVEN -3//行列非偶數  
  9.   
  10. class CMatrix  
  11. {  
  12. public:  
  13.     CMatrix(int r,int c);  
  14.     CMatrix(CMatrix& m);  
  15.     CMatrix(double* d,int r,int c);  
  16.     CMatrix(BYTE* d,int r,int c);  
  17.     ~CMatrix();  
  18.     int inital(int type);//初始化爲單位陣,或特殊矩陣(以後擴展)  
  19. #ifdef _DEBUG  
  20.     void display();  
  21. #endif  
  22.     //////////////////////////////////////////////////////////////////////////  
  23. public:  
  24.     CMatrix& transpose();//矩陣的轉置  
  25.     void nonZero();  
  26.     //////////////////////////////////////////////////////////////////////////  
  27. public:  
  28.      CMatrix& operator=(CMatrix& m1);  
  29.      friend CMatrix operator+(CMatrix& m1,CMatrix& m2);  
  30.      friend CMatrix operator-(CMatrix& m1,CMatrix& m2);  
  31.      friend CMatrix operator*(CMatrix& m1,double& a);  
  32.      friend CMatrix operator*(CMatrix& m1,CMatrix& m2);  
  33.     //////////////////////////////////////////////////////////////////////////  
  34. public:  
  35.     inline int getRow(){return m_row;}  
  36.     inline int getCol(){return m_col;}  
  37.     //inline CString getName(){return m_name;}  
  38.     inline double getElem(int r,int c){return m_data[r*m_row+c];}  
  39.     inline double* getData(){return m_data;}  
  40.     //////////////////////////////////////////////////////////////////////////  
  41. protected:  
  42.     int m_row;  
  43.     int m_col;  
  44.     double* m_data;  
  45. //  CString m_name;  
  46. };  


Matrix.cpp

  1. #include "StdAfx.h"  
  2.   
  3. #include "MatrixBase.h"  
  4. #ifdef _DEBUG  
  5. #include <iostream>  
  6. #endif  
  7.   
  8. CMatrix::CMatrix(int r,int c)  
  9. {  
  10.     m_row = r;  
  11.     m_col = c;  
  12.     m_data = new double[r*c];  
  13.     memset(m_data,0,sizeof(double)*r*c);  
  14. }  
  15. CMatrix::CMatrix(double* d,int r,int c)  
  16. {  
  17.     m_row = r;  
  18.     m_col = c;  
  19.     m_data = new double[r*c];  
  20.     for (int i = 0;i<r*c;i++)  
  21.     {  
  22.         m_data[i] = d[i];  
  23.     }  
  24. }  
  25. CMatrix::CMatrix(BYTE* d,int r,int c)  
  26. {  
  27.     m_row = r;  
  28.     m_col = c;  
  29.     m_data = new double[r*c];  
  30.     for (int i = 0;i<r*c;i++)  
  31.     {  
  32.         m_data[i] = (double)d[i];  
  33.     }  
  34. }  
  35. CMatrix::CMatrix(CMatrix& m)  
  36. {  
  37.     this->m_row = m.m_row;  
  38.     this->m_col = m.m_col;  
  39.     m_data = new double[m_row*m_col];  
  40.     for (int i = 0;i<m_row*m_col;i++)  
  41.     {  
  42.         this->m_data[i] = m.m_data[i];  
  43.         TRACE(_T("data[%d]=%f\n"),i,this->m_data[i]);  
  44.     }  
  45. }  
  46. CMatrix::~CMatrix()  
  47. {  
  48.     delete[] m_data;  
  49. }  
  50. int CMatrix::inital(int type)  
  51. {  
  52.       
  53.     switch(type)  
  54.     {  
  55.     case IDENTITY:  
  56.         if (m_row != m_col)  
  57.         {  
  58.             return UNSQUARE;  
  59.         }  
  60.         for (int i=0;i<m_col;i++)  
  61.         {  
  62.             m_data[i*m_row+i] = 1;  
  63.         }  
  64.         break;  
  65.     case HAAR:  
  66.         if (m_row != m_col)  
  67.         {  
  68.             return UNSQUARE;  
  69.         }  
  70.         if (m_row%2 != 0)  
  71.         {  
  72.             return UNEVEN;  
  73.         }  
  74.         for(int i = 0;i<m_row/2;i++)  
  75.         {  
  76.             m_data[i*m_row+i*2] = 1;  
  77.             m_data[i*m_row+i*2+1] = 1;  
  78.         }  
  79.         for (int i = m_row/2,j = 0;i<m_row;i++,j++)  
  80.         {  
  81.             m_data[i*m_row+j*2] = -1;  
  82.             m_data[i*m_row+j*2+1] = 1;  
  83.         }  
  84.         break;  
  85.     default:  
  86.         break;  
  87.     }  
  88.     return type;  
  89. }  
  90. CMatrix& CMatrix::operator=(CMatrix& m1)  
  91. {  
  92.     ASSERT(m_row == m1.getRow() && m_col == m1.getCol());  
  93.     for (int i = 0;i<m_row*m_col;i++)  
  94.     {  
  95.         m_data[i] = m1.getElem(i/m_row,i%m_row);  
  96.         TRACE(_T("\'=\'data[%d]=%f\n"),i,m_data[i]);  
  97.     }  
  98.     return *this;  
  99. }  
  100. CMatrix operator+(CMatrix& m1,CMatrix& m2)  
  101. {  
  102.     ASSERT(m1.m_row == m2.m_row && m1.m_col==m2.m_col);  
  103.     CMatrix ret(m1.m_row,m1.m_col);  
  104.     for (int i = 0;i<m1.m_row*m1.m_col;i++)  
  105.     {  
  106.         ret.m_data[i] = m1.m_data[i]+m2.m_data[i];  
  107.         TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);  
  108.     }  
  109.     return ret;  
  110.   
  111. }  
  112. CMatrix operator-(CMatrix& m1,CMatrix& m2)  
  113. {  
  114.     ASSERT(m1.m_row == m2.m_row && m1.m_col==m2.m_col);  
  115.     CMatrix ret(m1.m_row,m1.m_col);  
  116.     for (int i = 0;i<m1.m_row*m1.m_col;i++)  
  117.     {  
  118.         ret.m_data[i] = m1.m_data[i]-m2.m_data[i];  
  119.         TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);  
  120.     }  
  121.     return ret;  
  122. }  
  123. CMatrix operator*(CMatrix& m1,double& a)  
  124. {  
  125.     CMatrix ret(m1);  
  126.     for (int i = 0;i<m1.m_row*m1.m_col;i++)  
  127.     {  
  128.         ret.m_data[i] *=a;  
  129.         TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);  
  130.     }  
  131.     return ret;  
  132. }  
  133. CMatrix operator*(CMatrix& m1,CMatrix& m2)  
  134. {  
  135.     ASSERT(m1.m_col == m2.m_row);  
  136.     CMatrix ret(m1.m_row,m2.m_col);  
  137.     for (int i= 0;i<m1.m_row;i++)  
  138.     {  
  139.         for (int j = 0;j<m2.m_col;j++)  
  140.         {  
  141.             double _temp = 0;  
  142.             for (int k = 0;k<m1.m_col;k++)  
  143.             {  
  144.                 _temp += m1.m_data[i*m1.m_row+k]*m2.m_data[k*m2.m_row+j];  
  145.             }  
  146.             ret.m_data[i*m1.m_row+j] = _temp;  
  147.         }  
  148.     }  
  149.     return ret;  
  150. }  
  151. CMatrix& CMatrix::transpose()  
  152. {  
  153.     double* _newData = new double[m_row*m_col];  
  154.       
  155.     for (int i = 0;i<m_row;i++)  
  156.     {  
  157.         for (int j=0;j<m_col;j++)  
  158.         {  
  159.             _newData[j*m_col+i] = m_data[i*m_row+j];  
  160.         }  
  161.     }  
  162.     delete m_data;  
  163.     m_data = _newData;  
  164.           
  165.     return *this;  
  166.       
  167. }  
  168. void CMatrix::nonZero()  
  169. {  
  170.     for (int i = 0;i<m_row;i++)  
  171.     {  
  172.         for (int j = 0;j<m_col;j++)  
  173.         {  
  174.             if(m_data[i*m_row+j]<0)  
  175.             {  
  176.                 m_data[i*m_row+j]=0;  
  177.             }  
  178.         }  
  179.     }  
  180. }  
  181. #ifdef _DEBUG  
  182. void CMatrix::display()  
  183. {  
  184.     std::cout<<"[\n";  
  185.     for (int i = 0;i<m_row*m_col;i++)  
  186.     {  
  187.         std::cout<<m_data[i]<<" ,";  
  188.         if ((i+1)%m_row == 0)  
  189.         {  
  190.             std::cout<<std::endl;  
  191.         }  
  192.     }  
  193.     std::cout<<"]"<<std::endl;  
  194. }  
  195. #endif  


哈爾小波變換函數

  1. /******************************************** 
  2.  *              HAAR小波變換                * 
  3.  ********************************************/  
  4. void CBitMapFile::haarTransform(CFile& file)  
  5. {  
  6.     CMatrix imageMatrix(m_realImageArray,m_height,m_width);  
  7.     CMatrix haarMatrix_r(m_height,m_height);  
  8.     CMatrix haarMatrix_c(m_width,m_width);  
  9. #ifdef _DEBUG  
  10.     imageMatrix.display();  
  11. #endif  
  12.     haarMatrix_c.inital(HAAR);  
  13.     haarMatrix_c = haarMatrix_c.transpose();  
  14.     haarMatrix_r.inital(HAAR);  
  15.     imageMatrix = haarMatrix_r*imageMatrix;  
  16.     double _d = 0.25*sqrt(2.0);  
  17.     imageMatrix = imageMatrix*_d;  
  18.     imageMatrix = imageMatrix*haarMatrix_c;  
  19.     imageMatrix = imageMatrix*_d;  
  20.       
  21.   
  22.     imageMatrix.nonZero();  
  23. #ifdef _DEBUG  
  24.     imageMatrix.display();  
  25. #endif    
  26.       
  27.     double* _correctData = imageMatrix.getData();  
  28.     BYTE* _writeArray = new BYTE[m_sizeImage];  
  29.     memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);  
  30.   
  31.     for (int i = 0,j = 0;i<m_sizeImage;)  
  32.     {  
  33.         _writeArray[i] = (BYTE)_correctData[j];  
  34.         _writeArray[i+1] = (BYTE)_correctData[j];  
  35.         _writeArray[i+2] = (BYTE)_correctData[j];  
  36.         j++;  
  37.         i += 3;  
  38.         if (j%m_width == 0)  
  39.         {  
  40.             for (int k = 0;k<m_addByte;k++)  
  41.             {  
  42.                 _writeArray[i+k] = 0;  
  43.   
  44.             }  
  45.             i += m_addByte;  
  46.         }  
  47.     }  
  48.     file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));  
  49.     file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));  
  50.     file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);  
  51.   
  52.     delete _writeArray;  
  53.     //delete _correctData;  
  54. }  


處理後圖像

由於bmp格式是倒着存儲圖像數據的,因爲個人時間原因沒有將其倒回,所以出現這種現象。

實驗軟件可以在這裏下載:http://download.csdn.net/detail/smells2/4162515


發佈了28 篇原創文章 · 獲贊 6 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章