对比度限制直方图均衡化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上实现。

posted @ 2013-05-30 23:59  Pony_s  阅读(10413)  评论(0编辑  收藏  举报