轉自:http://blog.csdn.net/smells2/article/details/7378840
=============================================
本章所涉及的方法有:灰度化彩色圖像,將圖像轉換爲ASNII碼文件,直方圖均衡化,伽馬校正,哈爾小波變換。
0.知識儲備
這裏我們處理的是bmp格式的圖像,bmp格式的文件有3個文件頭,第一個文件頭大小爲14個字節,主要是對整個文件的信息的存儲。
- typedef struct tagBITMAPFILEHEADER {
- WORD bfType;
- DWORD bfSize;
- WORD bfReserved1;
- WORD bfReserved2;
- DWORD bfOffBits;
- } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
第二個文件頭大小爲50個字節,主要存儲了圖像的信息,比如,圖像有多少行,多少列,大小等等。
- typedef struct tagBITMAPINFOHEADER{
- DWORD biSize;
- LONG biWidth;
- LONG biHeight;
- WORD biPlanes;
- WORD biBitCount;
- DWORD biCompression;
- DWORD biSizeImage;
- LONG biXPelsPerMeter;
- LONG biYPelsPerMeter;
- DWORD biClrUsed;
- DWORD biClrImportant;
- } 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。那麼,我們的圖像就變成了灰度圖像。
- /********************************************
- * 將文件轉換成灰度圖像 *
- ********************************************/
- int CBitMapFile::turn2Gray()
- {
- if (m_imageArray == NULL)
- {
- return -2;
- }
- for (int i =0,j= 0,k=0;i<m_sizeImage;)
- {
- //轉換爲灰度圖像,注意填充的字節
- BYTE blue,green,red,gray;
- blue = m_imageArray[i];
- green = m_imageArray[i+1];
- red = m_imageArray[i+2];
- m_realColorImageArray[k] = blue;
- m_realColorImageArray[k+1] = green;
- m_realColorImageArray[k+2] = red;
- gray = (BYTE)(0.3*red+0.59*green+0.11*blue);
- m_imageArray[i] = gray;
- m_imageArray[i+1] = gray;
- m_imageArray[i+2] = gray;
- m_realImageArray[j] = m_imageArray[i];
- i += 3;
- k += 3;
- j++;
- ////跳過填充字節
- if (j % m_width == 0)
- {
- i += m_addByte;
- }
- }
- return 1;
- }
2.圖像轉換爲ASNII碼文件
三個步驟:(1)提取圖像數據(2)建立映射表(3)處理灰度並映射
映射表我建立的是8個字符'@','$','#','%','!','~','^','`'。
把灰度值除上32將其範圍映射到0-7這個範圍內。
將灰度值按照映射表映射。
- /******************************************
- *對圖像的每個像素做文本映射,最終寫入文件*
- ******************************************/
- int CBitMapFile::turn2Txt(CFile& txtFile)
- {
- char* _txtBuf = new char[m_width*m_height+2*m_height];
- memset(_txtBuf,0,m_width*m_height+2*m_height);
- //文本映射
- char txtMap[8] = {'@','$','#','%','!','~','^','`'};
- char* _buf = new char[m_width+2];
- memset(_buf,0,m_width+2);
- //TRACE(_T("\'\\r\'=%x,\'\\n\'=%x"),'\r','\n');
- for (int i = m_height-1;i>=0;i--)
- {
- for (int j = 0;j<m_width;j++)
- {
- _buf[j] = txtMap[m_realImageArray[i*m_width+j]>>5];
- }
- _buf[m_width] = '\r';
- _buf[m_width+1] = '\n';
- for (int k=0;k<m_width+2;k++)
- {
- _txtBuf[(m_height-1-i)*m_width+k+(m_height-1-i)*2] = _buf[k];
- }
- }
- txtFile.Write(_txtBuf,sizeof(char)*(m_width*m_height+2*m_height));
- delete _txtBuf;
- delete _buf;
- return 1;
- }
3.直方圖均衡化
每一幅圖像都有自己的直方圖
圖像取自岡薩雷斯的《數字圖像處理》第三版
這幅圖像的灰度大部分集中在較高的灰度,均衡化就使圖像在概率率較大的地方稀疏一點,概率較小的地方稠密一點。
方法是:(1)統計各個灰度的概率(2)歸一化(3)畫直方圖(4)累計概率(5)取整得到映射(6)將原灰度值映射到新灰度值
- /********************************************
- * 對bmp文件的每個像素的灰度值進行統計 *
- ********************************************/
- int CBitMapFile::addupLevel()
- {
- for (int i = 0;i<m_width*m_height;i++)
- {
- m_grayStatistic[m_realImageArray[i]] += 1;
- }
- for (int i = 0;i<256;i++)
- {
- if (m_grayStatistic[i]>m_max)
- {
- m_max = m_grayStatistic[i];
- }
- }
- //TRACE(_T("m_max = %d\n"),m_max);
- return 1;
- }
- /********************************************
- * 對bmp文件的每個像素的灰度值進行歸一化 *
- * 並計算每個像素灰度值的概率 *
- ********************************************/
- int CBitMapFile::turn2One()
- {
- for (int i =0;i<256;i++)
- {
- m_grayTurn2OneData[i] = (double)m_grayStatistic[i]/m_max;
- m_grayFrequencyPerLevel[i] = (double)m_grayStatistic[i]/(m_width*m_height);
- }
- m_maxFrequency = m_max/(m_width*m_height);
- return 1;
- }
- /********************************************
- * 清除統計數組、歸一化數組、頻率數組 *
- ********************************************/
- void CBitMapFile::clearup()
- {
- memset(m_grayStatistic,0,sizeof(LONG)*256);
- memset(m_grayTurn2OneData,0,sizeof(double)*256);
- memset(m_grayFrequencyPerLevel,0,sizeof(double)*256);
- m_max = 0;
- m_maxFrequency = 0.0f;
- }
- /********************************************
- * 灰度均衡化 *
- ********************************************/
- void CBitMapFile::equation(CFile& file)
- {
- double _temp =0.0f;
- double* _array = new double[256];
- memset(_array,0,sizeof(double)*256);
- int* _intArray = new int[256];
- memset(_intArray,0,sizeof(int)*256);
- BYTE* _writeArray = new BYTE[m_sizeImage];
- memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);
- for(int i = 0;i<256;i++)
- {
- _array[i] = ((m_grayFrequencyPerLevel[i])*255)+_temp;
- _temp = _array[i];
- }
- for (int i = 0;i<256;i++)
- {
- _intArray[i] = (int)(_array[i]);
- }
- for (int i = 0,j = 0;i<m_sizeImage;)
- {
- _writeArray[i] = _intArray[m_realImageArray[j]];
- _writeArray[i+1] = _intArray[m_realImageArray[j]];
- _writeArray[i+2] = _intArray[m_realImageArray[j]];
- j++;
- i += 3;
- if (j%m_width == 0)
- {
- for (int k = 0;k<m_addByte;k++)
- {
- _writeArray[i+k] = 0;
- }
- i += m_addByte;
- }
- }
- file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));
- file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));
- file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);
- delete _array;
- delete _intArray;
- delete _writeArray;
- }
4.伽馬校正
伽馬校正其實很簡單,就是將舊的灰度值通過一個由灰度值爲底,伽馬次冪的映射得到新的灰度值,它的做用是,對於不同的伽馬係數的選取,會使得某些較亮的圖片,變得對比度適當。
- /********************************************
- * 伽馬校正 *
- ********************************************/
- void CBitMapFile::gammaCorrection(double gamma,CFile& file)
- {
- //數據準備
- double* _correctData = new double[m_width*m_height];
- BYTE* _writeArray = new BYTE[m_sizeImage];
- memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);
- memset(_correctData,0,sizeof(double)*m_width*m_height);
- //算法
- for (int i = 0;i<m_width*m_height;i++)
- {
- _correctData[i] = (double)m_realImageArray[i]/255;
- _correctData[i] = pow(_correctData[i],gamma)*255;
- }
- //寫入文件準備
- for (int i = 0,j = 0;i<m_sizeImage;)
- {
- _writeArray[i] = (BYTE)_correctData[j];
- _writeArray[i+1] = (BYTE)_correctData[j];
- _writeArray[i+2] = (BYTE)_correctData[j];
- j++;
- i += 3;
- if (j%m_width == 0)
- {
- for (int k = 0;k<m_addByte;k++)
- {
- _writeArray[i+k] = 0;
- }
- i += m_addByte;
- }
- }
- //寫入文件
- file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));
- file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));
- file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);
- delete _writeArray;
- delete _correctData;
- }
這個是伽馬選擇7.5的效果
4.哈爾小波變換(HWT,haar wavelet tansform)
這個是小波變換裏最簡單的一個,由於涉及較多的數學,這裏就不做贅述了,只是附上程序。(程序使用的矩陣乘法是我自己寫的,效率較低,經過測試在128*128的大小的圖像效果可以,再大就會出現未響應的現象。)
注意,哈爾小波變換的矩陣是偶數*偶數的,所以圖片的行列也必須是偶數。
Matrix.h
- #pragma once
- #define ZERO 0 //零陣
- #define IDENTITY 1//單位陣
- #define HAAR 2//HAAR小波矩陣
- #define UNSQUARE -1//非方陣
- #define UNSAME -2//非同型矩陣
- #define UNSAME -2//非同型矩陣
- #define UNEVEN -3//行列非偶數
- class CMatrix
- {
- public:
- CMatrix(int r,int c);
- CMatrix(CMatrix& m);
- CMatrix(double* d,int r,int c);
- CMatrix(BYTE* d,int r,int c);
- ~CMatrix();
- int inital(int type);//初始化爲單位陣,或特殊矩陣(以後擴展)
- #ifdef _DEBUG
- void display();
- #endif
- //////////////////////////////////////////////////////////////////////////
- public:
- CMatrix& transpose();//矩陣的轉置
- void nonZero();
- //////////////////////////////////////////////////////////////////////////
- public:
- CMatrix& operator=(CMatrix& m1);
- friend CMatrix operator+(CMatrix& m1,CMatrix& m2);
- friend CMatrix operator-(CMatrix& m1,CMatrix& m2);
- friend CMatrix operator*(CMatrix& m1,double& a);
- friend CMatrix operator*(CMatrix& m1,CMatrix& m2);
- //////////////////////////////////////////////////////////////////////////
- public:
- inline int getRow(){return m_row;}
- inline int getCol(){return m_col;}
- //inline CString getName(){return m_name;}
- inline double getElem(int r,int c){return m_data[r*m_row+c];}
- inline double* getData(){return m_data;}
- //////////////////////////////////////////////////////////////////////////
- protected:
- int m_row;
- int m_col;
- double* m_data;
- // CString m_name;
- };
Matrix.cpp
- #include "StdAfx.h"
- #include "MatrixBase.h"
- #ifdef _DEBUG
- #include <iostream>
- #endif
- CMatrix::CMatrix(int r,int c)
- {
- m_row = r;
- m_col = c;
- m_data = new double[r*c];
- memset(m_data,0,sizeof(double)*r*c);
- }
- CMatrix::CMatrix(double* d,int r,int c)
- {
- m_row = r;
- m_col = c;
- m_data = new double[r*c];
- for (int i = 0;i<r*c;i++)
- {
- m_data[i] = d[i];
- }
- }
- CMatrix::CMatrix(BYTE* d,int r,int c)
- {
- m_row = r;
- m_col = c;
- m_data = new double[r*c];
- for (int i = 0;i<r*c;i++)
- {
- m_data[i] = (double)d[i];
- }
- }
- CMatrix::CMatrix(CMatrix& m)
- {
- this->m_row = m.m_row;
- this->m_col = m.m_col;
- m_data = new double[m_row*m_col];
- for (int i = 0;i<m_row*m_col;i++)
- {
- this->m_data[i] = m.m_data[i];
- TRACE(_T("data[%d]=%f\n"),i,this->m_data[i]);
- }
- }
- CMatrix::~CMatrix()
- {
- delete[] m_data;
- }
- int CMatrix::inital(int type)
- {
- switch(type)
- {
- case IDENTITY:
- if (m_row != m_col)
- {
- return UNSQUARE;
- }
- for (int i=0;i<m_col;i++)
- {
- m_data[i*m_row+i] = 1;
- }
- break;
- case HAAR:
- if (m_row != m_col)
- {
- return UNSQUARE;
- }
- if (m_row%2 != 0)
- {
- return UNEVEN;
- }
- for(int i = 0;i<m_row/2;i++)
- {
- m_data[i*m_row+i*2] = 1;
- m_data[i*m_row+i*2+1] = 1;
- }
- for (int i = m_row/2,j = 0;i<m_row;i++,j++)
- {
- m_data[i*m_row+j*2] = -1;
- m_data[i*m_row+j*2+1] = 1;
- }
- break;
- default:
- break;
- }
- return type;
- }
- CMatrix& CMatrix::operator=(CMatrix& m1)
- {
- ASSERT(m_row == m1.getRow() && m_col == m1.getCol());
- for (int i = 0;i<m_row*m_col;i++)
- {
- m_data[i] = m1.getElem(i/m_row,i%m_row);
- TRACE(_T("\'=\'data[%d]=%f\n"),i,m_data[i]);
- }
- return *this;
- }
- CMatrix operator+(CMatrix& m1,CMatrix& m2)
- {
- ASSERT(m1.m_row == m2.m_row && m1.m_col==m2.m_col);
- CMatrix ret(m1.m_row,m1.m_col);
- for (int i = 0;i<m1.m_row*m1.m_col;i++)
- {
- ret.m_data[i] = m1.m_data[i]+m2.m_data[i];
- TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);
- }
- return ret;
- }
- CMatrix operator-(CMatrix& m1,CMatrix& m2)
- {
- ASSERT(m1.m_row == m2.m_row && m1.m_col==m2.m_col);
- CMatrix ret(m1.m_row,m1.m_col);
- for (int i = 0;i<m1.m_row*m1.m_col;i++)
- {
- ret.m_data[i] = m1.m_data[i]-m2.m_data[i];
- TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);
- }
- return ret;
- }
- CMatrix operator*(CMatrix& m1,double& a)
- {
- CMatrix ret(m1);
- for (int i = 0;i<m1.m_row*m1.m_col;i++)
- {
- ret.m_data[i] *=a;
- TRACE(_T("ret[%d]=%f\n"),i,ret.m_data[i]);
- }
- return ret;
- }
- CMatrix operator*(CMatrix& m1,CMatrix& m2)
- {
- ASSERT(m1.m_col == m2.m_row);
- CMatrix ret(m1.m_row,m2.m_col);
- for (int i= 0;i<m1.m_row;i++)
- {
- for (int j = 0;j<m2.m_col;j++)
- {
- double _temp = 0;
- for (int k = 0;k<m1.m_col;k++)
- {
- _temp += m1.m_data[i*m1.m_row+k]*m2.m_data[k*m2.m_row+j];
- }
- ret.m_data[i*m1.m_row+j] = _temp;
- }
- }
- return ret;
- }
- CMatrix& CMatrix::transpose()
- {
- double* _newData = new double[m_row*m_col];
- for (int i = 0;i<m_row;i++)
- {
- for (int j=0;j<m_col;j++)
- {
- _newData[j*m_col+i] = m_data[i*m_row+j];
- }
- }
- delete m_data;
- m_data = _newData;
- return *this;
- }
- void CMatrix::nonZero()
- {
- for (int i = 0;i<m_row;i++)
- {
- for (int j = 0;j<m_col;j++)
- {
- if(m_data[i*m_row+j]<0)
- {
- m_data[i*m_row+j]=0;
- }
- }
- }
- }
- #ifdef _DEBUG
- void CMatrix::display()
- {
- std::cout<<"[\n";
- for (int i = 0;i<m_row*m_col;i++)
- {
- std::cout<<m_data[i]<<" ,";
- if ((i+1)%m_row == 0)
- {
- std::cout<<std::endl;
- }
- }
- std::cout<<"]"<<std::endl;
- }
- #endif
哈爾小波變換函數
- /********************************************
- * HAAR小波變換 *
- ********************************************/
- void CBitMapFile::haarTransform(CFile& file)
- {
- CMatrix imageMatrix(m_realImageArray,m_height,m_width);
- CMatrix haarMatrix_r(m_height,m_height);
- CMatrix haarMatrix_c(m_width,m_width);
- #ifdef _DEBUG
- imageMatrix.display();
- #endif
- haarMatrix_c.inital(HAAR);
- haarMatrix_c = haarMatrix_c.transpose();
- haarMatrix_r.inital(HAAR);
- imageMatrix = haarMatrix_r*imageMatrix;
- double _d = 0.25*sqrt(2.0);
- imageMatrix = imageMatrix*_d;
- imageMatrix = imageMatrix*haarMatrix_c;
- imageMatrix = imageMatrix*_d;
- imageMatrix.nonZero();
- #ifdef _DEBUG
- imageMatrix.display();
- #endif
- double* _correctData = imageMatrix.getData();
- BYTE* _writeArray = new BYTE[m_sizeImage];
- memset(_writeArray,0,sizeof(BYTE)*m_sizeImage);
- for (int i = 0,j = 0;i<m_sizeImage;)
- {
- _writeArray[i] = (BYTE)_correctData[j];
- _writeArray[i+1] = (BYTE)_correctData[j];
- _writeArray[i+2] = (BYTE)_correctData[j];
- j++;
- i += 3;
- if (j%m_width == 0)
- {
- for (int k = 0;k<m_addByte;k++)
- {
- _writeArray[i+k] = 0;
- }
- i += m_addByte;
- }
- }
- file.Write(&m_file_header,sizeof(BITMAPFILEHEADER));
- file.Write(&m_info_header,sizeof(BITMAPINFOHEADER));
- file.Write(_writeArray,sizeof(BYTE)*m_sizeImage);
- delete _writeArray;
- //delete _correctData;
- }
處理後圖像
由於bmp格式是倒着存儲圖像數據的,因爲個人時間原因沒有將其倒回,所以出現這種現象。
實驗軟件可以在這裏下載:http://download.csdn.net/detail/smells2/4162515