對比度限制直方圖均衡化CLHE


其實實現了半個月了,不過一直沒更新,囧。

上次講到對比度限制的直方圖均衡化,糾結了一段時間。

不知道為什么思維總是會想到改變圖像的像素值,其實CLHE的目的是獲取一個不那么陡峭的轉換的映射函數,所以操作只要在直方圖層面完成就行了。

確定閥值,切割直方圖,將大於閥值的面積平均分到各個bins(之前就在糾結這里……),得到一個CL的直方圖之后再求映射函數,並不用對原圖進行操作。

代碼:

這里的實現是多出來的面積按平局分布到各個bins,其實可以用高斯分布,效果可能會更好。

//核心部分
/*


            //限制對比度
        {
            
            //獲取最大值
            cvGetMinMaxHistValue(histo_src,&histmin,&histmax);
            thresh*=histmax;
            cout<<thresh<<"\n";

            //遍歷get頂部面積
            S=0;
            for(i=1;i<=255;i++)
            {
                if(cvQueryHistValue_1D(histo_src,i)>thresh)
                    {
                        S+=(cvQueryHistValue_1D(histo_src,i)-thresh);
                        cvSetReal1D(histo_src->bins,i,thresh);
                    }
            }
            S/=255;

            //遍歷+平均面積;
            for(i=1;i<=255;i++)
            {
                        cvSetReal1D(histo_src->bins,
                                    i,
                                    S+cvQueryHistValue_1D(histo_src,i)
                                    );
            }
            

        }

*/

//程序部分---------------------------------------------------------------------------------------------

//滑塊調節CLHE
#include <iostream>
#include <string>
#include <io.h>
#include <opencv2/opencv.hpp>
#include<math.h>
#include<cv.h>

using namespace std;
using namespace cv;

//全局變量2個
  int position;
  float thresh;

//好吧,全部都是全局變量
  //變量定義
        //圖片類
        IplImage *src , *dst;
        IplImage *histframesrc , *histframedst;
        CvSize     size;
        //直方圖類
        CvHistogram *histo_src , *histo_dst;
        int scale;
        float histmin,histmax;

        int bins=256;
        float range[]={0,255};
        float *ranges[]={range};
        //雜家
        int i,j,k,m,n;                                //循環變量……而已 
        float s_r[256];                                //S(r)映射函數
        float  S;                                   //頂部面積

  void on_trackbar(int position)
 {
     thresh=float(position)/100;
     cout<<thresh<<"\t";
        
     cvCalcHist(&src,histo_src,0,0);                //計算直方圖
        cvNormalizeHist(histo_src,255);                //歸一



            //限制對比度
        {
            
            //獲取最大值
            cvGetMinMaxHistValue(histo_src,&histmin,&histmax);
            thresh*=histmax;
            cout<<thresh<<"\n";

            //遍歷get頂部面積
            S=0;
            for(i=1;i<=255;i++)
            {
                if(cvQueryHistValue_1D(histo_src,i)>thresh)
                    {
                        S+=(cvQueryHistValue_1D(histo_src,i)-thresh);
                        cvSetReal1D(histo_src->bins,i,thresh);
                    }
            }
            S/=255;

            //遍歷+平均面積;
            for(i=1;i<=255;i++)
            {
                        cvSetReal1D(histo_src->bins,
                                    i,
                                    S+cvQueryHistValue_1D(histo_src,i)
                                    );
            }
            

        }

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

        //累加,求S(r)映射
        s_r[0]=cvQueryHistValue_1D(histo_src,0);
        for(i=1;i<=255;i++)
        {
                s_r[i]=s_r[i-1]+cvQueryHistValue_1D(histo_src,i);    
        }



        //遍歷圖像並由sr關系進行直方圖均衡化啦
        CvScalar s;
        for(m=0;m<size.height;m++)
        {
            for(n=0;n<size.width;n++)
            {
                s=cvGet2D(src,m,n);
                i=s.val[0];//得到像素值
                i=s_r[i];//得到映射值
                s.val[0]=i;//設置像素通道值
                cvSet2D(dst,m,n,s);
            }
        }
        
        //SHOWOFF一下啦
        cvSmooth(dst,dst,CV_GAUSSIAN );
        cvShowImage("dst",dst);
        
        //計算dst直方圖
        cvCalcHist(&dst,histo_dst,0,0);
        cvNormalizeHist(histo_dst,255);
        
        scale=2;
        //畫出src和dst的直方圖
        histframesrc=cvCreateImage( cvSize(bins*scale,256),8,1);
        histframedst=cvCreateImage( cvSize(bins*scale,256),8,1);

        //src的
        cvGetMinMaxHistValue(histo_src , &histmin , &histmax , 0 , 0 );
        for(int i = 0; i < bins; i++)
            {
                
                /** 獲得直方圖中的統計次數,計算顯示在圖像中的高度 */
                float bin_val = cvGetReal1D(histo_src->bins,i);
                bin_val=bin_val*255/histmax;
                s.val[0]=cvRound(bin_val);
                cvRectangle(histframesrc,cvPoint(i*scale,256),cvPoint((i+1)*scale,256-bin_val),s,-1,8,0);
            }
        cvShowImage("src's hisogram",histframesrc);

        //dst的
        cvGetMinMaxHistValue(histo_dst , &histmin , &histmax , 0 , 0 );
        for(int i = 0; i < bins; i++)
            {
                
                /** 獲得直方圖中的統計次數,計算顯示在圖像中的高度 */
                float bin_val = cvGetReal1D(histo_dst->bins,i);
                bin_val=bin_val*255/histmax;
                s.val[0]=cvRound(bin_val);
                cvRectangle(histframedst,cvPoint(i*scale,256),cvPoint((i+1)*scale,256-bin_val),s,-1,8,0);
            }
        cvShowImage("dst's hisogram",histframedst);
        




 }




void main(int argc, char** argv)
{
    
        
        
        src=cvLoadImage("11.jpg",0);                //圖片變量初始化
        cvShowImage("src",src);
        size=cvGetSize(src);
        dst=cvCreateImage(size,8,1);

        histo_src=cvCreateHist(1,&bins,CV_HIST_ARRAY,ranges);        //直方圖初始化
        histo_dst=cvCreateHist(1,&bins,CV_HIST_ARRAY,ranges);
        
        cvNamedWindow("dst");
        cvCreateTrackbar("\%","dst",&position,100,on_trackbar);//創建滑動條
        on_trackbar(position);//回調滑動條

        for(;;)if(cvWaitKey(0)==27)break;
        /////////////////////////////////////

}


 

實現結果:

閥值=0.14

 

閥值=0.91

 

在CLHE之后對圖像進行了高斯平滑,所以直方圖會比較奇怪。

對比結果可以得出CLHE之后的直方圖並沒有平均布滿整個空間,從而達到了對比度限制的目的。

 

 

 

另:

1、關於上次的AHE,因為試用了區塊加速,所以不可避免的出現了區塊效應,實際中的AHE需要對每個像素周圍MxN范圍內外的圖像求映射,並按特定比例相加,耗時慢。

2、接下來可能會實現SIFT或者是霍夫變換,前者掌握的比較早,但是后者實現更加簡單,應該會先做后者。盡量在Matlab上實現。


免責聲明!

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



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