MFC圖像點運算之灰度線性變化、灰度非線性變化、閾值化和均衡化處理

 本文主要講述基於VC++6.0 MFC圖像處理的應用知識,主要結合自己大三所學課程《數字圖像處理》及課件進行講解,主要通過MFC單文檔視圖實現顯示BMP圖片點運算處理,包括圖像灰度線性變換、灰度非線性變換、圖像閾值化處理、圖像均衡化處理等知識,並結合前一篇論文灰度直方圖進行展示 。同時文章比較詳細基礎,希望該篇文章對你有所幫助,尤其是初學者和學習圖像處理的學生。
       【數字圖像處理】一.MFC詳解顯示BMP格式圖片
       【數字圖像處理】二.MFC單文檔分割窗口顯示圖片
       【數字圖像處理】三.MFC實現圖像灰度、採樣和量化功能詳解
       【數字圖像處理】四.MFC對話框繪製灰度直方圖
        免費資源下載地址:
        http://download.csdn.net/detail/eastmount/8764373

 

一. 點運算與初始操作

        圖像的點運算是圖像處理中非常基礎的技術,它主要用於改變一篇圖像的灰度分佈範圍,通過一定的變換函數將圖像的像素進行轉換,最終生成一幅新的圖像。點運算的最大特點就是輸出像素值只與當前輸入像素值相關。定義如下。
        點運算(Point Operation)指對於一幅輸入圖像,將產生一幅輸出圖像,輸出圖像的每個像素點的灰度值由輸入像素點決定。
        點運算由灰度變換函數(Grap Scale Transformation,GST)確定:B(x,y)=F[A(x,y)]
        需要注意一下幾點:
        (1).與局部或鄰域運算的差別,輸入像素和輸出像素是一一對應的;(2).與幾何運算的差別,不改變圖像的空間關係;(3).又稱爲對比增強,對比拉伸或灰度變換。

        在前面第四篇博客的基礎上增加點運算處理。
        第一步:在資源視圖中Menu中添加“圖像點運算”菜單欄如下所示:


        對應的ID值爲:
        線性變換 ID_DYS_XXYD(點運算 線性移動) ID_DYS_XXZQ( 點運算 線性增強)
                       ID_DYS_XXJX(點運算 線性減小)  ID_DYS_XXQB(點運算 線性求補)
        非線性變換 ID_DYS_FXXPF(點運算 非線性平方) ID_DYS_FXXHS(非線性函數)
        閾值變換 ID_DYS_YZBH(點運算 閾值變換) 圖像均衡化 ID_DYS_JHH

        第二步:打開類嚮導(Ctrl+W),爲點運算每個ID菜單添加相應的功能處理函數,如下圖所示:選擇類CImageProcessingView,在選擇IDs爲ID_DYS_...(點運算)添加函數OnDysXxqb()線性求補。

 

 

二. 線性變換

        圖像線性變換是通過建立灰度映射來調整資源圖像的灰度,從而達到圖像增強的目的。其中GST函數f(D)爲線性的,即:


        若a=1,b=0圖像像素不發生變化
        若a=1,b!=0圖像所有灰度值上移或下移
        若a>1輸出圖像對比度增強
        若0<a<1輸出圖像對比度減小
        若a<0暗區域變亮,亮區域變暗,圖像求補


 

        1.D(B)=D(A)+50
        首先是圖像移動,代碼如下:


 
  1. /**********************************************************************/

  2. /* 圖像點運算 4種線性變化直方圖:

  3. /* ID_DYS_XXYD:表示線性灰度變化移動 D(B)=D(A)+50 灰度值上移下移

  4. /* ID_DYS_XXZQ:表示線性灰度變化增強 D(B)=1.5*D(A) 圖像對比度增強

  5. /* ID_DYS_XXJX:表示線性灰度變化減小 D(B)=0.8*D(A) 圖像對比度減小

  6. /* ID_DYS_XXQB:表示線性灰度求補 D(B)=-1*D(A)+255 圖像暗區變亮,亮區變暗

  7. /**********************************************************************/

  8.  
  9. // 1.點運算 線性灰度變化移動 D(B)=D(A)+50

  10. void CImageProcessingView::OnDysXxyd()

  11. {

  12. // TODO: Add your command handler code here

  13. if(numPicture==0) {

  14. AfxMessageBox("載入圖片後才能線性灰度運算!",MB_OK,0);

  15. return;

  16. }

  17. AfxMessageBox("線性灰度直方圖-灰度變化移動 D(B)=D(A)+50!",MB_OK,0);

  18. int i;

  19. //打開臨時的圖片

  20. FILE *fpo = fopen(BmpName,"rb");

  21. FILE *fpw = fopen(BmpNameLin,"wb+");

  22. //讀取文件

  23. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  24. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  25. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  26. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  27. //灰度圖像

  28. unsigned char color;

  29. unsigned char red,green,blue;

  30. for( i=0; i<m_nImage/3; i++ )

  31. {

  32. fread(&red,sizeof(char),1,fpo);

  33. fread(&green,sizeof(char),1,fpo);

  34. fread(&blue,sizeof(char),1,fpo);

  35.  
  36. if( (int)red+50 >255 )

  37. red=255;

  38. else

  39. red=(int)red+50;

  40.  
  41. if( (int)green+50>255 )

  42. green=255;

  43. else

  44. green=(int)green+50;

  45.  
  46. if( (int)blue+50>255 )

  47. blue=255;

  48. else

  49. blue=(int)blue+50;

  50.  
  51. fwrite(&red,sizeof(char),1,fpw);

  52. fwrite(&green,sizeof(char),1,fpw);

  53. fwrite(&blue,sizeof(char),1,fpw);

  54. }

  55. fclose(fpo);

  56. fclose(fpw);

  57. numPicture = 2;

  58. level=101; //賦值101在ShowBitmap中調用顯示處理後的圖片

  59. Invalidate();

  60. }

        同時修改void CImageProcessingView::ShowBitmap(CDC *pDC, 
CString BmpName)函數中的代碼:


 
  1. else //圖像點運算 線性變化

  2. if(level=101)

  3. {

  4. m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,

  5. LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);

  6. }

        運行效果如下圖所示,同時我截取了直方圖(RGB相同只顯示一種)。

        可以發現圖像的灰度上移了50,圖像更白了(黑0-255白)。

        2.D(B)=1.5*D(A)


 
  1. // 2.點運算 線性灰度變化增強 D(B)=1.5*D(A)

  2. void CImageProcessingView::OnDysXxzq()

  3. {

  4. if(numPicture==0) {

  5. AfxMessageBox("載入圖片後才能線性灰度運算!",MB_OK,0);

  6. return;

  7. }

  8. AfxMessageBox("線性灰度直方圖-灰度變化增強 D(B)=1.5*D(A)!",MB_OK,0);

  9. int i;

  10. //打開臨時的圖片

  11. FILE *fpo = fopen(BmpName,"rb");

  12. FILE *fpw = fopen(BmpNameLin,"wb+");

  13. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  14. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  15. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  16. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  17. //灰度圖像

  18. unsigned char color;

  19. unsigned char red,green,blue;

  20. for( i=0; i<m_nImage/3; i++ )

  21. {

  22. fread(&red,sizeof(char),1,fpo);

  23. fread(&green,sizeof(char),1,fpo);

  24. fread(&blue,sizeof(char),1,fpo);

  25.  
  26. if( (int)red*1.5 >255 )

  27. red=255;

  28. else

  29. red=(int)red*1.5;

  30.  
  31. if( (int)green*1.5>255 )

  32. green=255;

  33. else

  34. green=(int)green*1.5;

  35.  
  36. if( (int)blue*1.5>255 )

  37. blue=255;

  38. else

  39. blue=(int)blue*1.5;

  40.  
  41. fwrite(&red,sizeof(char),1,fpw);

  42. fwrite(&green,sizeof(char),1,fpw);

  43. fwrite(&blue,sizeof(char),1,fpw);

  44. }

  45. fclose(fpo);

  46. fclose(fpw);

  47. numPicture = 2;

  48. level=101; //線性變化 ShowBitmap中調用

  49. Invalidate();

  50. }

        運行效果如下圖所示,圖像對比度增強,平均灰度122*1.5=181

 

 

        3.D(B)=0.8*D(A)


 
  1. // 3.點運算 線性灰度變化減小D(B)=0.8*D(A)

  2. void CImageProcessingView::OnDysXxjx()

  3. {

  4. if(numPicture==0) {

  5. AfxMessageBox("載入圖片後才能線性灰度處理!",MB_OK,0);

  6. return;

  7. }

  8. AfxMessageBox("線性灰度直方圖-灰度減小 D(B)=0.8*D(A)!",MB_OK,0);

  9. int i;

  10. //打開臨時的圖片

  11. FILE *fpo = fopen(BmpName,"rb");

  12. FILE *fpw = fopen(BmpNameLin,"wb+");

  13. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  14. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  15. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  16. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  17. //灰度圖像

  18. unsigned char color;

  19. unsigned char red,green,blue;

  20. for( i=0; i<m_nImage/3; i++ )

  21. {

  22. fread(&red,sizeof(char),1,fpo);

  23. fread(&green,sizeof(char),1,fpo);

  24. fread(&blue,sizeof(char),1,fpo);

  25.  
  26. red=(int)red*0.8;

  27. green=(int)green*0.8;

  28. blue=(int)blue*0.8;

  29.  
  30. fwrite(&red,sizeof(char),1,fpw);

  31. fwrite(&green,sizeof(char),1,fpw);

  32. fwrite(&blue,sizeof(char),1,fpw);

  33. }

  34. fclose(fpo);

  35. fclose(fpw);

  36. numPicture = 2;

  37. level=101;

  38. Invalidate();

  39. }

        運行如下圖所示,圖像減弱。



        4.D(B)=-1*D(A)+255


 
  1. // 4.點運算 線性灰度求補 D(B)=-1*D(A)+255

  2. void CImageProcessingView::OnDysXxqb()

  3. {

  4. if(numPicture==0) {

  5. AfxMessageBox("載入圖片後才能線性灰度處理!",MB_OK,0);

  6. return;

  7. }

  8. AfxMessageBox("線性灰度直方圖-灰度求補 D(B)=-1*D(A)+255!",MB_OK,0);

  9. int i;

  10. //打開臨時的圖片

  11. FILE *fpo = fopen(BmpName,"rb");

  12. FILE *fpw = fopen(BmpNameLin,"wb+");

  13. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  14. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  15. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  16. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  17. //灰度圖像

  18. unsigned char color;

  19. unsigned char red,green,blue;

  20. for( i=0; i<m_nImage/3; i++ )

  21. {

  22. fread(&red,sizeof(char),1,fpo);

  23. fread(&green,sizeof(char),1,fpo);

  24. fread(&blue,sizeof(char),1,fpo);

  25.  
  26. red=(int)red*(-1)+255;

  27. green=(int)green*(-1)+255;

  28. blue=(int)blue*(-1)+255;

  29.  
  30. fwrite(&red,sizeof(char),1,fpw);

  31. fwrite(&green,sizeof(char),1,fpw);

  32. fwrite(&blue,sizeof(char),1,fpw);

  33. }

  34. fclose(fpo);

  35. fclose(fpw);

  36. numPicture = 2;

  37. level=101;

  38. Invalidate();

  39. }

        運行效果如下圖所示,它是圖像的求補,發現直方圖是互補的。

        PS:注意圖片下面的直方圖應該還有一個處理後的直方圖,但原理都一樣,我不想重複工作,你自己可以去簡單實現下,參考第四篇文章。同時這些圖片製作還挺麻煩的,只是爲了給你更好的呈現它們的變化,希望對你有用和尊重作者,不喜勿噴~

 

 

三. 非線性變換

        灰度非線性變換主要包括對數變換、冪次變換、指數變換、分段函數變換,通過非線性關係對圖像進行灰度處理,下面主要講解課件中的兩個函數對其進行處理。其中對數變換實現了擴展低灰度值而壓縮高灰度值的效果,圖像灰度分佈更符合而你的視覺特徵。


        1.D(B)=D(A)*D(A)/252


 
  1. /************************************************************************/

  2. /* 2種非線性變化直方圖:

  3. /* ID_DYS_FXXPF:表示非線性平方灰度變化,D(B)=D(A)*D(A)/255

  4. /* ID_DYS_FXXHS:表示非線性函數灰度變化,D(B)=D(A)+0.8*D(A)*(255-D(A))/255

  5. /************************************************************************/

  6.  
  7. // 非線性平方灰度變化 D(B)=D(A)*D(A)/252

  8. void CImageProcessingView::OnDysFxxpf()

  9. {

  10. if(numPicture==0)

  11. {

  12. AfxMessageBox("載入圖片後才能非線性灰度處理!",MB_OK,0);

  13. return;

  14. }

  15. AfxMessageBox("非線性灰度變化 D(B)=D(A)*D(A)/255!",MB_OK,0);

  16. int i;

  17. //打開臨時的圖片

  18. FILE *fpo = fopen(BmpName,"rb");

  19. FILE *fpw = fopen(BmpNameLin,"wb+");

  20. //讀取文件

  21. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  22. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  23. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  24. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  25. //灰度圖像

  26. unsigned char color;

  27. unsigned char red,green,blue;

  28. for( i=0; i<m_nImage/3; i++ )

  29. {

  30. fread(&red,sizeof(char),1,fpo);

  31. fread(&green,sizeof(char),1,fpo);

  32. fread(&blue,sizeof(char),1,fpo);

  33.  
  34. red=(int)red*(int)red/255;

  35. green=(int)green*(int)green/255;

  36. blue=(int)blue*(int)blue/255;

  37.  
  38. fwrite(&red,sizeof(char),1,fpw);

  39. fwrite(&green,sizeof(char),1,fpw);

  40. fwrite(&blue,sizeof(char),1,fpw);

  41. }

  42. fclose(fpo);

  43. fclose(fpw);

  44. numPicture = 2;

  45. level=101;

  46. Invalidate();

  47. }

        運行效果如下圖所示:


        2.D(B)=D(A)+0.8*D(A)*(255-D(A))/255


 
  1. // 非線性函數灰度變化 D(B)=D(A)+0.8*D(A)*(255-D(A))/255

  2. void CImageProcessingView::OnDysFxxhs()

  3. {

  4. if(numPicture==0)

  5. {

  6. AfxMessageBox("載入圖片後才能非線性灰度處理!",MB_OK,0);

  7. return;

  8. }

  9. AfxMessageBox("線性灰度直方圖-灰度變化增強 D(B)=D(A)+0.8*D(A)*(255-D(A))/255!",MB_OK,0);

  10. int i;

  11.  
  12. FILE *fpo = fopen(BmpName,"rb");

  13. FILE *fpw = fopen(BmpNameLin,"wb+");

  14. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  15. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  16. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  17. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  18.  
  19. unsigned char color;

  20. unsigned char red,green,blue;

  21. for( i=0; i<m_nImage/3; i++ )

  22. {

  23. fread(&red,sizeof(char),1,fpo);

  24. fread(&green,sizeof(char),1,fpo);

  25. fread(&blue,sizeof(char),1,fpo);

  26.  
  27. if( ((int)red+0.8*(int)red*(255-(int)red)/255) > 255 )

  28. red=255;

  29. else

  30. red=(int)red+0.8*(int)red*(255-(int)red)/255;

  31.  
  32. if( ((int)green+0.8*(int)green*(255-(int)green)/255) > 255 )

  33. green=255;

  34. else

  35. green=(int)green+0.8*(int)green*(255-(int)green)/255;

  36.  
  37. if( ((int)blue+0.8*(int)blue*(255-(int)blue)/255) > 255 )

  38. blue=255;

  39. else

  40. blue=(int)blue+0.8*(int)blue*(255-(int)blue)/255;

  41.  
  42. fwrite(&red,sizeof(char),1,fpw);

  43. fwrite(&green,sizeof(char),1,fpw);

  44. fwrite(&blue,sizeof(char),1,fpw);

  45. }

  46. fclose(fpo);

  47. fclose(fpw);

  48. numPicture = 2;

  49. level=101;

  50. Invalidate();

  51. }

        運行效果如下圖所示:


        寫到此處你會發現圖像灰度的線性變換和非線性變換是非常簡單的,主要是通過以下步驟完成:
        第一步:賦值處理後圖像的BMP頭信息
            FILE *fpo = fopen(BmpName,"rb");
            FILE *fpw = fopen(BmpNameLin,"wb+");
            fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
            fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
            fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
            fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
        第二步:通過循環和線性變換或非線性便函函數處理每一個像素
            for( i=0; i<m_nImage/3; i++ )
            {
                 fread(&red,sizeof(char),1,fpo);
                 處理像素RBG 如:red=(int)red*(int)red/255;
                 fwrite(&red,sizeof(char),1,fpw);
            }
         第三步:調用ShowBitmap自定義函數並重繪圖像
            numPicture = 2;
            level=101;
            Invalidate();
        而它的主要應用包括:光度學標定,希望數字圖像的灰度能夠真實反映圖像的物理特性;對比度增強和對比度擴展;顯示標定和輪廓線確定(閾值化)。

 

 

四. 灰度閾值化

        閾值又稱爲臨界值,它的目的是確定出一個範圍,然後這個範圍內的部分使用同一種方法處理,而閾值之外的部分則使用另一種處理方法或保持原樣。常用的包括產生二值圖:當x<T時y=0,當x>=T時y=255(其中T是閾值)。閾值變換在生物學上的應用比較廣泛,常用語細胞圖像分割等。
        打開類嚮導(Ctrl+W)生成選擇ImageProcessingView類,IDs選擇ID_DYS_YZBH後添加相應的函數。代碼如下:


 
  1. /**************************************************************/

  2. /* ID_DYS_YZBH:表示點運算閾值變換 也看做灰度拉伸

  3. /* 此處的拉伸是:閾值化(thresholding)可以看作是削波的一個特例

  4. /* 只要令削波中的g1old=g2old就實現了閾值化。

  5. /* 閾值就象個門檻,比它大就是白,比它小就是黑,二值

  6. /**************************************************************/

  7.  
  8. void CImageProcessingView::OnDysYzbh()

  9. {

  10. if(numPicture==0)

  11. {

  12. AfxMessageBox("載入圖片後才能點運算閾值化處理!",MB_OK,0);

  13. return;

  14. }

  15. AfxMessageBox("圖像點運算閾值化處理!",MB_OK,0);

  16. //讀寫文件

  17. FILE *fpo = fopen(BmpName,"rb");

  18. FILE *fpw = fopen(BmpNameLin,"wb+");

  19. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  20. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  21. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  22. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  23. //處理

  24. unsigned char color;

  25. unsigned char red,green,blue;

  26. for(int i=0; i<m_nImage/3; i++ )

  27. {

  28. fread(&red,sizeof(char),1,fpo);

  29. fread(&green,sizeof(char),1,fpo);

  30. fread(&blue,sizeof(char),1,fpo);

  31.  
  32. if( (int)red > 128 )

  33. red=255;

  34. else

  35. red=0;

  36.  
  37. if( (int)green > 128 )

  38. green=255;

  39. else

  40. green=0;

  41.  
  42. if( (int)blue > 128 )

  43. blue=255;

  44. else

  45. blue=0;

  46.  
  47. fwrite(&red,sizeof(char),1,fpw);

  48. fwrite(&green,sizeof(char),1,fpw);

  49. fwrite(&blue,sizeof(char),1,fpw);

  50. }

  51. fclose(fpo);

  52. fclose(fpw);

  53. numPicture = 2;

  54. level=101;

  55. Invalidate();

  56. }

        運行效果如下圖所示,感覺還挺好看的,顯然此時的直方圖就是0和255兩條直線。

 

 

五. 灰度均衡化

        灰度均衡化的目的是使一輸入圖像轉換爲在每一灰度級上都有相同的像素點(即輸出的直方圖是平的),它可以產生一幅灰度級分佈概率均衡的圖像。
        換句話說,經過均衡化後的圖像在每一級灰度上像素點的數量相差不大,對應的灰度直方圖的每一級高度也相差不大。它是增強圖像的有效手段之一。
        研究思路是通過直方圖變換公式實現:


        它的步驟如下圖所示:

        例:有一幅圖象,共有16級灰度,其直方圖分佈爲Pi, i=0,1,…,15,求經直方圖均衡化後,量化級別爲10級的灰度圖象的直方圖分佈Qi,其中Pi和Qi爲分佈的概率,即灰度i出現的次數與總的點數之比。
        Pi:0.03, 0, 0.06, 0.10, 0.20, 0.11, 0, 0, 0, 0.03, 0, 0.06, 0.10, 0.20, 0.11, 0
        步驟1:用一個數組s記錄Pi,即s[0]=0.03,s[1]=0,s[2]=0.06,…,s[14]=0.11,s[15]=0
        步驟2:i從1開始,令s[i]=s[i]+s[i-1],得到的結果是s: 0.03,  0.03, 0.09,  0.19,  0.39, 0.50,  0.50,  0.50, 0.50,  0.53,  0.53, 0.59,  0.69,  0.89, 1.0,  1.0
        步驟3:用一個數組L記錄新的調色板索引值,即令L[i]=s[i]×(10-1),得到的結果是L:0,0,1,2,4,5,5,5,5,5,5,5,6,8,9,9
        這樣就找到了原來的調色板索引值和新的調色板索引值之間的對應關係,即
        0→0,  1→0, 2→1,  3→2,  4→4, 5→5,  6→5,  7→5, 8→5,  9→5,  10→5, 11→5,  12→6,  13→8, 14→9,  15→9。
       步驟4:將老的索引值對應的概率合併,作爲對應的新的索引值的概率。例如,原來的索引值0,1都對應了新的索引值0,則灰度索引值爲0的概率爲P0+P1=0.03;新的索引值3和7找不到老的索引值與之對應,所以令Q3和Q7爲0。最後得到的結果是Qi:0.03,  0.06, 0.10,  0,  0.20, 0.20,  0.10,  0, 0.20,  0.11 

        代碼中有詳細註釋如下:


 
  1. // ID_DYS_JHH:表示圖像均衡化 相見算法

  2. void CImageProcessingView::OnDysJhh()

  3. {

  4. if(numPicture==0) {

  5. AfxMessageBox("載入圖片後才能圖像均衡化!",MB_OK,0);

  6. return;

  7. }

  8. AfxMessageBox("圖像均衡化!",MB_OK,0);

  9.  
  10. //第一步:獲取圖像的數據信息

  11. //此操作可以在打開圖片時就進行 在直方圖採樣(ZFTCY)中也有該代碼

  12. FILE *fpo = fopen(BmpName,"rb");

  13. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  14. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  15.  
  16. int i,j,k;

  17. for(j=0;j<256;j++) { //定義數組並清零

  18. Red[j]=0;

  19. Green[j]=0;

  20. Blue[j]=0;

  21. }

  22.  
  23. //計算4個數據

  24. unsigned char red,green,blue;

  25. int IntRed,IntGreen,IntBlue; //強制轉換

  26. double sumRedHD=0,sumGreenHD=0,sumBlueHD=0; //記錄像素總的灰度值和

  27. for(i=0; i<m_nImage/3; i++ )

  28. {

  29. fread(&red,sizeof(char),1,fpo);

  30. IntRed=int(red);

  31. sumRedHD=sumRedHD+IntRed;

  32. if( IntRed>=0 && IntRed<256 ) Red[IntRed]++;

  33.  
  34. fread(&green,sizeof(char),1,fpo);

  35. IntGreen=int(green);

  36. sumGreenHD=sumGreenHD+IntGreen;

  37. if( IntGreen>=0 && IntGreen<256 ) Green[IntGreen]++;

  38.  
  39. fread(&blue,sizeof(char),1,fpo);

  40. IntBlue=int(blue);

  41. sumBlueHD=sumBlueHD+IntBlue;

  42. if( IntBlue>=0 && IntBlue<256 ) Blue[IntBlue]++;

  43. }

  44. fclose(fpo);

  45.  
  46. /*****************************************************************/

  47. /* 圖像均衡化處理

  48. /* 利用全局變量 Red[256] Blue[256] Green[256]

  49. /* 第一步:用3個數組Count..記錄0-255灰度出現的概率,即

  50. /* 概率=該灰度出現次數*3/總得像素 (因爲分成3部分RGB)

  51. /* 第二步:i從1開始,令s[i]=s[i]+s[i-1] 記錄新概率數

  52. /* 第三步:用一個數組L記錄新的調色板索引值,即

  53. /* L[i]=s[i]×(256-1)結果四捨五入2.8即爲3

  54. /* 第四步:將老的索引值對應的概率合併,作爲對應的新的索引值的概率

  55. /* 1.原來的索引值0,1都對應了新的索引值0,則灰度索引值爲0的概率

  56. /* 爲P0+P1=0.03

  57. /* 2.新的索引值3和7找不到老的索引值與之對應,所以令Q3和Q7爲0

  58. /*****************************************************************/

  59.  
  60. //記錄出現的概率,會加到1 用於相加到調色板

  61. float CountRed[256],CountGreen[256],CountBlue[256];

  62. //記錄原始數據,不會相加到1 用於計算新灰度概率

  63. float CountRedLin[256],CountGreenLin[256],CountBlueLin[256];

  64.  
  65. for( k=0 ; k<256 ; k++ )

  66. {

  67. CountRed[k]=(float)(Red[k])*3/m_nImage;

  68. CountRedLin[k]=CountRed[k];

  69. CountGreen[k]=(float)(Green[k])*3/m_nImage;

  70. CountGreenLin[k]=CountGreen[k];

  71. CountBlue[k]=(float)(Blue[k])*3/m_nImage;

  72. CountBlueLin[k]=CountBlue[k];

  73. }

  74.  
  75. for( k=1 ; k<256 ; k++ )

  76. {

  77. CountRed[k]=CountRed[k]+CountRed[k-1];

  78. CountGreen[k]=CountGreen[k]+CountGreen[k-1];

  79. CountBlue[k]=CountBlue[k]+CountBlue[k-1];

  80. }

  81.  
  82. /****************************************************/

  83. /* 此處百度到一個四捨五入浮點型的算法:

  84. /* float a=3.456; 保留到小數點後兩位

  85. /* float b=(int)((a * 100) + 0.5) / 100.0;

  86. /* output b=3.46

  87. /****************************************************/

  88.  
  89. int LRed[256],LGreen[256],LBlue[256]; //記錄調色板

  90. for( k=0 ; k<256 ; k++ )

  91. {

  92. LRed[k]=(int)(CountRed[k]*(256-1)+0.5);

  93. LGreen[k]=(int)(CountGreen[k]*(256-1)+0.5);

  94. LBlue[k]=(int)(CountBlue[k]*(256-1)+0.5);

  95. }

  96.  
  97. //第三步:處理均衡化圖像寫入 打開臨時的圖片

  98. fpo = fopen(BmpName,"rb");

  99. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

  100. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

  101.  
  102. FILE *fpw = fopen(BmpNameLin,"wb+");

  103. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

  104. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

  105.  
  106. //m_nWidth*m_nHeight 讀取圖片最後一行不爲m_nWidth時會報錯 改爲m_nImage/3

  107. for( i=0; i<m_nImage/3 ; i++ )

  108. {

  109. fread(&red,sizeof(char),1,fpo);

  110. fread(&green,sizeof(char),1,fpo);

  111. fread(&blue,sizeof(char),1,fpo);

  112.  
  113. red=LRed[int(red)];

  114. green=LGreen[int(green)];

  115. blue=LBlue[int(blue)];

  116.  
  117. fwrite(&red,sizeof(char),1,fpw);

  118. fwrite(&green,sizeof(char),1,fpw);

  119. fwrite(&blue,sizeof(char),1,fpw);

  120. }

  121. fclose(fpw);

  122. numPicture = 2;

  123. level=101;

  124. Invalidate();

  125. }

        運行結果如下圖所示,圖像增強而且異常清晰:

 


        最後介紹下圖像對比度拉伸,它就是把你感興趣的灰度範圍拉開,使得該範圍內像素,亮的更亮,暗的更暗,從而達到增強對比度的目的。
        如下圖所示,a、b、c爲三段直線的斜率,g1old和g2old表示途中要進行對比度擴展的範圍,g1new和g2new表示對應的新值。當g1old=g2old就是二值圖像閾值化處理。

 

          由於灰度界別也是255這個約束,所以滿足

       其中g1old=100,g2old=150,b=3.0的運行效果如下所示:

 


        

//////////////////////////////////////////////////////////////////

https://blog.csdn.net/eastmount/article/details/46312145

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章