圖像處理之直方圖均衡化及C源碼實現


直方圖均衡化(Histogram Equalization)簡介

  圖像對比度增強的方法可以分成兩類:一類是直接對比度增強方法;另一類是間接對比度增強方法。直方圖拉伸和直方圖均衡化是兩種最常見的間接對比度增強方法。直方圖拉伸是通過對比度拉伸對直方圖進行調整,從而“擴大”前景和背景灰度的差別,以達到增強對比度的目的,這種方法可以利用線性或非線性的方法來實現;直方圖均衡化則通過使用累積函數對灰度值進行“調整”以實現對比度的增強。

  如果一副圖像的像素占有很多的灰度級而且分布均勻,那么這樣的圖像往往有高對比度和多變的灰度色調。直方圖均衡化就是一種能僅靠輸入圖像直方圖信息自動達到這種效果的變換函數。它的基本思想是對圖像中像素個數多的灰度級進行展寬,而對圖像中像素個數少的灰度進行壓縮,從而擴展像原取值的動態范圍,提高了對比度和灰度色調的變化,使圖像更加清晰。

直方圖均衡化原理

  設變量r代表圖像中像素的灰度級,直方圖變換就是假定一個變換式:

                              

  也就是,通過上述變換,每個原始圖像的像素灰度級r都會產生一個s值。變換函數T(r)應滿足以下條件:

  (1) T(r)在區間中為單值且單調遞增;

  (2) 當 時,T(r)的取值范圍與r相同。

  直方圖均衡化:對於離散值,我們處理其概率與求和,而不是概率密度函數與積分。一幅圖像中灰度級rk出現的概率近似為

                           

  其中,n是圖像中像素的總和, 是灰度級 的像素個數,L為圖像中可能的灰度級總數。

                             

       上式中變換函數的離散形式為:

                     

    式給出的變換(映射)稱為直方圖均衡化或直方圖線性化。

    根據上面公式推導,直方圖均衡化步驟如下:

    (1) 統計原圖每灰度級像素個數

    (2) 統計原圖像每灰度級像素的累積個數

    (3) 建立灰度級的映射規則

    (4) 將原圖每個像素點的灰度映射到新圖

直方圖均衡化優缺點

  這種方法對於背景和前景都太亮或者太暗的圖像非常有用,這種方法尤其是可以帶來X光圖像中更好的骨骼結構顯示以及曝光過度或者曝光不足照片中更好的細節。這種方法的一個主要優勢是它是一個相當直觀的技術並且是可逆操作,如果已知均衡化函數,那么就可以恢復原始的直方圖,並且計算量也不大。

  這種方法的一個缺點是它對處理的數據不加選擇,它可能會增加背景雜訊的對比度並且降低有用信號的對比度;變換后圖像的灰度級減少,某些細節消失;某些圖像,如直方圖有高峰,經處理后對比度不自然的過分增強。

直方圖均衡化源碼實現

 

  1 #include <windows.h> 
  2 #include <stdafx.h>
  3 #include <stdlib.h> 
  4 #include <string.h>
  5 #include <stdio.h>
  6 #include<conio.h>
  7 #pragma pack(1)
  8  
  9 typedef  unsigned char BYTE;
 10 typedef  short unsigned int WORD;
 11 typedef  unsigned long DWORD;
 12 
 13 
 14 
 15 
 16 typedef struct BMP_FILEHEADER
 17 {//定義bmp文件頭
 18 
 19     WORD bmpType;/*位圖標識*/
 20     DWORD bmpSize;/*說明文件的大小,用字節為單位*/
 21     DWORD bmpReserved;/*保留,必須設置為0*/
 22     DWORD bmpOffset;/*從文件頭開始到實際的圖象數據之間的字節的偏移量*/
 23     DWORD bmpHeaderSize;/*說明BITMAP_INFOHEADER結構所需要的字數*/
 24     DWORD bmpWidth;/*說明圖象的寬度,以象素為單位*/
 25     DWORD bmpHeight;/*說明圖象的高度,以象素為單位.大多數的BMP文件都是倒向的位圖*/
 26     WORD bmpPlanes;/*為目標設備說明位面數,其值將總是被設為1*/
 27 
 28 } BMP_FILEHEADER;
 29 
 30 typedef struct BMP_INFOHEADER
 31 {//定義bmp信息頭
 32 
 33     WORD bitsPerPixel;/*說明比特數/象素*/
 34     DWORD bmpCompression;/*說明圖象數據壓縮的類型*/
 35     DWORD bmpDataSize;   /*說明圖象的大小,以字節為單位。當用BI_RGB格式時,可設置為0*/
 36     DWORD bmpHResolution;/*說明水平分辨率,用象素/米表示*/
 37     DWORD bmpVResolution;/*說明垂直分辨率,用象素/米表示*/
 38     DWORD bmpColors;/*實際使用的顏色數,0說明使用所有調色板項*/
 39     DWORD bmpImportantColors;/*重要影響的顏色索引的數目,如果是0,表示都重要*/
 40 
 41 } BMP_INFOHEADER;
 42 
 43 typedef struct RGBPALETTE
 44 {//定義8位顏色表
 45 
 46     BYTE rgbBlue;/*指定藍色強度*/
 47     BYTE rgbGreen;/*指定綠色強度*/
 48     BYTE rgbRed;/*指定紅色強度*/
 49     BYTE rgbReserved;/*保留,設為0*/
 50 
 51 } RGBPALETTE;
 52 
 53 typedef struct RGBPALETTE_24
 54 {//定義24位顏色表
 55      BYTE rgbBlue;/*指定藍色強度*/
 56      BYTE rgbGreen;/*指定綠色強度*/
 57      BYTE rgbRed;/*指定紅色強度*/
 58 }RGBPALETTE_24;
 59 
 60 typedef struct BMPFILEPTR
 61 {//定義bmp文件指針類型
 62     BMP_FILEHEADER *bmpFileHeader;//bmp文件頭指針
 63     BMP_INFOHEADER *bmpInfoHeader;//bmp信息頭指針
 64     RGBPALETTE  *bmpColorTable;//顏色表指針
 65     unsigned char *bmpDataPtr;//bmp數據指針
 66 }BMPFILEPTR;
 67 
 68 typedef struct HE
 69 {//定義直方圖均衡化結構
 70     float ohs[256];//原始灰度級概率
 71     float integs[256];//原始灰度概率累計值
 72 }HE;
 73 
 74 long FileLength(FILE *fp);//返回文件長度
 75 void WriteData(unsigned char *pBmpData,FILE *fp);//寫數據,將文件數據寫入pBmpData所指內存單元
 76 unsigned char* MemoryAlloc(int length);//分配length長度的內存單元
 77 void MemoryFree(unsigned char *pBmpData);//釋放內存單元
 78 int GetPixelColor(BMPFILEPTR bmpFile,unsigned int index,int bitsperpixel);//獲得顏色值
 79 void InputPicture(BMPFILEPTR *bmpFile,unsigned char *pBmpData,FILE *fp);//輸入圖片,文件指針初始化
 80 void DisplayPicture(HDC hdc,BMPFILEPTR bmpFile,POINT spoint);//顯示圖片,將圖片顯示在畫板上
 81 void ComputeOriginalProbabilty(BMPFILEPTR bmpFile,HE *hequal);//計算原始圖片灰度級概率
 82 void ComputeEqualizedProbabilty(BMPFILEPTR bmpFile,HE *hequal);//計算均衡化后的灰度級概率
 83 void GenerateEqualizedBmpFile(BMPFILEPTR bmpFile,FILE *fp1,HE hequal);//生成均衡化之后的bmp文件
 84 
 85 long WINAPI WndProc(HWND,UINT,UINT,LONG); //處理消息響應的函數
 86 BOOL InitWindowsClass(HINSTANCE); //初始化窗口類
 87 BOOL InitWindows(HINSTANCE,int); //初始化窗口函數
 88 HWND hWndMain;//窗口句柄
 89  
 90 long FileLength(FILE *fp)
 91 {//返回文件長度
 92     long curpos, length;
 93 
 94     curpos = ftell(fp);
 95     fseek(fp, 0L, SEEK_END);
 96     length = ftell(fp);
 97     fseek(fp, curpos, SEEK_SET);
 98     return length;
 99 }
100 
101 unsigned char* MemoryAlloc(int length)
102 {//按照length長度分配內存單元,返回內存首地址
103     unsigned char *pBmpData;
104 
105     if(NULL==(pBmpData=(unsigned char*)malloc(length*sizeof(unsigned char))))
106     {
107         MessageBox(NULL,(LPCWSTR )"memory allocation failure,error!",NULL,NULL);
108         exit(1);
109     }
110     return pBmpData;
111 }
112 
113 void MemoryFree(unsigned char *pBmpData)
114 {//釋放內存單元
115     free(pBmpData);
116 }
117 
118 void WriteData(unsigned char *pBmpData,FILE *fp)
119 {//寫數據,將文件數據寫入字節流中
120     int ind=0;
121     fseek(fp, 0, SEEK_SET);
122     while(!feof(fp))
123     {
124         pBmpData[ind++]=fgetc(fp);
125     }
126 }
127 
128 int GetPixelColor(BMPFILEPTR bmpFile,unsigned int index,int bitsperpixel)
129 {//取像素點的顏色值,在VC++中顏色值是0x00bbggrr,返回顏色值
130      unsigned int pixelcolor=0;
131     switch(bitsperpixel)
132     {
133     case 8: pixelcolor+=(bmpFile.bmpColorTable+*(bmpFile.bmpDataPtr+index))->rgbBlue;
134             pixelcolor<<=8;
135             pixelcolor+=(bmpFile.bmpColorTable+*(bmpFile.bmpDataPtr+index))->rgbGreen;
136             pixelcolor<<=8;
137             pixelcolor+=(bmpFile.bmpColorTable+*(bmpFile.bmpDataPtr+index))->rgbRed;
138             break;
139     case 16:
140             break;
141     case 24:pixelcolor+=((RGBPALETTE_24*)bmpFile.bmpDataPtr+index)->rgbBlue;
142             pixelcolor<<=8;
143             pixelcolor+=((RGBPALETTE_24*)bmpFile.bmpDataPtr+index)->rgbGreen;
144             pixelcolor<<=8;
145             pixelcolor+=((RGBPALETTE_24*)bmpFile.bmpDataPtr+index)->rgbRed;
146             break;
147     case 32:
148             break;
149     default:
150             ;
151     }
152      return pixelcolor;
153 
154 }
155 void InputPicture(BMPFILEPTR *bmpFile,unsigned char *pBmpData,FILE *fp)
156 {//將bmp文件輸入,存到pBmpData指針所指存儲空間中,初始化bmpFile變量
157         WriteData(pBmpData,fp);
158         bmpFile->bmpFileHeader=(BMP_FILEHEADER*)(pBmpData);
159         bmpFile->bmpInfoHeader=(BMP_INFOHEADER*)((char*)bmpFile->bmpFileHeader+sizeof(BMP_FILEHEADER));
160         bmpFile->bmpColorTable=(RGBPALETTE*)((char*)bmpFile->bmpInfoHeader+sizeof(BMP_INFOHEADER));
161         bmpFile->bmpDataPtr=pBmpData+bmpFile->bmpFileHeader->bmpOffset;
162 
163 }
164 void DisplayPicture(HDC hdc,BMPFILEPTR bmpFile,POINT spoint)
165 {//顯示圖片,spoint為圖片起始點,左上角
166      static int bmpHeight,bmpWidth;
167      int h,w;
168      unsigned int index=0;
169      static int bitsperpixel;
170      static int pixelcolor;
171      bmpHeight=bmpFile.bmpFileHeader->bmpHeight;
172      bmpWidth=bmpFile.bmpFileHeader->bmpWidth;
173      bitsperpixel=bmpFile.bmpInfoHeader->bitsPerPixel;
174      if(8==bmpFile.bmpInfoHeader->bitsPerPixel)
175          bmpWidth=((bmpWidth*bitsperpixel+31)>>5)<<2;//若寬度不是4的整數倍則對齊
176 
177      Rectangle(hdc,spoint.x,spoint.y,bmpWidth,bmpHeight);//畫圖片外框架 
178      for(h=spoint.y+bmpHeight;h>spoint.y;h--)//從圖片左下角開始逐點填充
179         for(w=spoint.x;w<spoint.x+bmpWidth;w++)
180         {
181             pixelcolor=GetPixelColor(bmpFile,index++,bitsperpixel);
182             SetPixel(hdc,w,h,pixelcolor);
183         }
184 }
185 void ComputeOriginalProbabilty(BMPFILEPTR bmpFile,HE *hequal)
186 {//計算原始灰度級概率
187     int i;
188     int pixels=(bmpFile.bmpFileHeader->bmpHeight)*(bmpFile.bmpFileHeader->bmpWidth);
189 
190     for(i=0;i<pixels;i++)
191         hequal->ohs[bmpFile.bmpDataPtr[i]]++;//累計相同灰度級點個數
192 
193 
194     FILE *p1; 
195     p1=fopen("p1.txt","w");
196    int p[256];
197       for(i=0;i<256;i++)
198       {
199            p[i]=hequal->ohs[i];
200             
201               fprintf(p1,"p[%d]=%d\n ",i,p[i]);
202       }
203 
204 
205 
206     for(i=0;i<256;i++)
207         hequal->ohs[i]=hequal->ohs[i]/pixels;//計算每個灰度級概率
208 }
209 void ComputeEqualizedProbabilty(BMPFILEPTR bmpFile,HE *hequal)
210 {// 計算原始灰度級概率的累計概率,為生成均衡化之后概率
211     int i;
212         FILE *p2; 
213     p2=fopen("p2.txt","w");
214     int a[256];
215 
216     hequal->integs[0]=hequal->ohs[0];
217     for(i=1;i<256;i++)
218     {
219         hequal->integs[i]=hequal->integs[i-1]+hequal->ohs[i];
220 
221         a[i]=(hequal->integs[i])*256;
222         fprintf(p2,"a[%d]=%d\n ",i,a[i]);
223     }
224 
225 
226 }
227 void GenerateEqualizedBmpFile(BMPFILEPTR bmpFile,FILE *fp1,HE hequal)
228 {//生成均衡化后的bmp文件
229      unsigned long i,j;
230      unsigned char c;
231      fwrite(bmpFile.bmpFileHeader,sizeof(BMP_FILEHEADER),1,fp1);//將bmp文件頭結構數據賦給新文件相應部分
232      fwrite(bmpFile.bmpInfoHeader,sizeof(BMP_INFOHEADER),1,fp1);
233      fwrite(bmpFile.bmpColorTable,256*sizeof(RGBPALETTE),1,fp1);
234      for(i=0;i<bmpFile.bmpFileHeader->bmpSize-bmpFile.bmpFileHeader->bmpOffset;i++)
235      {//將灰度級數據賦給新文件數據部分
236          for(j=0;j<256;j++)
237          {
238              if(*(bmpFile.bmpDataPtr+i)==j)
239              {
240                  c=hequal.integs[j]*255;
241                  break;
242              }
243               
244          }
245          fwrite(&c,sizeof(unsigned char),1,fp1);
246      }
247 }
248 BMPFILEPTR bmpFile,newbmpFile;
249 HE hequal={0,0},newhequal={0,0};//初始化直方圖結構體變量
250 
251 
252 
253 
254 
255 int WINAPI WinMain( 
256                     HINSTANCE hInstance,      
257                     HINSTANCE hPrevInstance,  
258                     LPSTR lpCmdLine,        
259                     int nCmdShow   
260                    ) 
261 { //windows API 主函數
262     MSG Message; 
263 
264     static FILE *fp = NULL,*newfp=NULL;//定義兩個文件指針,分別指向兩個bmp文件
265     static unsigned char *pBmpData,*newpBmpData;//定義兩個數據指針,分別指向兩處內存首地址
266     static int filesize=0;
267     if(NULL==(fp=fopen("Fig4.bmp","rb+")))
268      {
269          MessageBox(NULL,(LPCWSTR )"file open failure,error!",NULL,NULL);
270          exit(1);
271      }
272     if(NULL==(newfp=fopen("newFig.bmp","wb+")))
273      {
274          MessageBox(NULL,(LPCWSTR )"file open failure,error!",NULL,NULL);
275          exit(1);
276      }    
277     filesize=FileLength(fp);
278     pBmpData=MemoryAlloc(filesize);
279     newpBmpData=MemoryAlloc(filesize);
280     InputPicture(&bmpFile,pBmpData,fp);
281     ComputeOriginalProbabilty(bmpFile,&hequal);
282     ComputeEqualizedProbabilty(bmpFile,&hequal);
283     GenerateEqualizedBmpFile(bmpFile,newfp,hequal);
284     InputPicture(&newbmpFile,newpBmpData,newfp);
285     ComputeOriginalProbabilty(newbmpFile,&newhequal);
286     fclose(fp);
287     fclose(newfp);
288 
289     if(!InitWindowsClass(hInstance)) 
290          return FALSE; 
291     if(!InitWindows(hInstance,nCmdShow)) 
292          return FALSE; 
293     while(GetMessage(&Message,NULL,0,0)) 
294     { 
295          TranslateMessage(&Message); 
296          DispatchMessage(&Message); 
297     }
298     return Message.wParam;
299 }
300 
301 
302 
303 int InitWindows(HINSTANCE hInstance,int nCmdShow) 
304 { 
305      hWndMain=CreateWindow( 
306                            (LPCWSTR )"WinFill",  // registered class name 
307                            (LPCWSTR )"直方圖均衡化", // window name 
308                            WS_OVERLAPPEDWINDOW,        // window style 
309                            0,                // horizontal position of window 
310                            0,                // vertical position of window 
311                            1100,           // window width 
312                            550,          // window height 
313                            NULL,      // handle to parent or owner window 
314                            NULL,          // menu handle or child identifier 
315                            hInstance,  // handle to application instance 
316                            NULL        // window-creation data 
317                            ); 
318      if(!hWndMain) 
319          return FALSE; 
320      ShowWindow(hWndMain,nCmdShow); 
321      UpdateWindow(hWndMain); 
322      return TRUE; 
323 }
324  
325 int InitWindowsClass(HINSTANCE hInstance) 
326 { //初始化窗口類,對窗口類的對象賦初始值
327      WNDCLASS wndclass; 
328      wndclass.style=0; 
329      wndclass.cbClsExtra=0; 
330      wndclass.cbWndExtra=0; 
331      wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); 
332      wndclass.hCursor=LoadCursor( 
333                                  hInstance,  
334                                  IDC_ARROW  
335                                  ); 
336      wndclass.hIcon=LoadIcon( 
337                              hInstance, 
338                              IDI_APPLICATION   
339                              ); 
340      wndclass.hInstance=hInstance; 
341      wndclass.lpfnWndProc=WndProc; 
342      wndclass.lpszClassName=(LPCWSTR )"WinFill"; 
343      wndclass.lpszMenuName=NULL; 
344      return RegisterClass(&wndclass); 
345 } 
346 
347 long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam) 
348 { 
349      HDC hdc;  
350      HPEN hpen; 
351      PAINTSTRUCT ps; 
352      POINT originpoint,pstartpoint;
353      
354      switch(iMessage) 
355      { 
356        case WM_PAINT: hdc=BeginPaint(hWnd,&ps);//繪圖             
357 
358                       hpen=CreatePen(PS_SOLID,1,RGB(0,255,0)); 
359                       SelectObject(hdc,hpen);
360                     ////////////////畫原始的bmp圖//////////////////
361                       pstartpoint.x=0;
362                       pstartpoint.y=0;
363                       DisplayPicture(hdc,bmpFile,pstartpoint);
364                      
365 
366                     ///////////畫均衡化后的bmp圖/////////////////
367                       pstartpoint.x=550;
368                       pstartpoint.y=0;
369                       DisplayPicture(hdc,newbmpFile,pstartpoint);
370                     
371                       return 0; 
372       case WM_DESTROY:PostQuitMessage(0); 
373                       return 0; 
374       default:  return (DefWindowProc(hWnd,iMessage,wParam,lParam)); 
375      } 
376 } 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM