[OpenCV] Image Processing - Grayscale Transform & Histogram

颜色直方图


首先,先介绍一些Hist的基本使用。

Ref:【OpenCV】数字图像灰度直方图

官方文档:https://docs.opencv.org/trunk/d8/dbc/tutorial_histogram_calculation.html

不错博文:利用OpenCV的calcHist绘制灰度直方图、H-S直方图、BGR直方图和自定义直方图的源码及说明

From: compare histograms of grayscale images in opencv

#include <opencv2/opencv.hpp>

void show_histogram(std::string const& name, cv::Mat1b const& image)
{
    // Set histogram bins count
    int bins = 256;
    int histSize[] = {bins};
    // Set ranges for histogram bins
    float lranges[] = {0, 256};
    const float* ranges[] = {lranges};
    // create matrix for histogram
    cv::Mat hist;
    int channels[] = {0};

    // create matrix for histogram visualization
    int const hist_height = 256;
    cv::Mat3b hist_image = cv::Mat3b::zeros(hist_height, bins);

    cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges, true, false);

    double max_val=0;
    minMaxLoc(hist, 0, &max_val);

    // visualize each bin
    for(int b = 0; b < bins; b++) {
        float const binVal = hist.at<float>(b);
        int   const height = cvRound(binVal*hist_height/max_val);
        cv::line
            ( hist_image
            , cv::Point(b, hist_height-height), cv::Point(b, hist_height)
            , cv::Scalar::all(255)
            );
    }
    cv::imshow(name, hist_image);
}

int main (int argc, const char* argv[])
{
    // here you can use cv::IMREAD_GRAYSCALE to load grayscale image, see image2
    cv::Mat3b const image1 = cv::imread("C:\\workspace\\horse.png", cv::IMREAD_COLOR);
    cv::Mat1b image1_gray;
    cv::cvtColor(image1, image1_gray, cv::COLOR_BGR2GRAY);
    cv::imshow("image1", image1_gray);
    show_histogram("image1 hist", image1_gray);

    cv::Mat1b const image2 = cv::imread("C:\\workspace\\bunny.jpg", cv::IMREAD_GRAYSCALE);
    cv::imshow("image2", image2);
    show_histogram("image2 hist", image2);

    cv::waitKey();
    return 0;
}

 

 

 

Histogram equalization


参考:笑得很甜

 

偏差、增益参数

 

线性混合算子

 

 

非线性算子

 

 

覆盖算子

 


 

直方图均衡化

直方图的观看规则就是“左黑右白”,左边代表暗部,右边代表亮部,而中间则代表中间调。 纵向上的高度代表像素密集程度,越高,代表的就是分布在这个亮度上的像素很多。

如何看懂照片的直方图?

 

 

对比度

对比度在直方图上的体现就是高光和阴影部分都有像素。
它可以很少,但是必须有,否则照片看起来就很灰了。正常照片变为低对比度后的直方图对比:
                     

  当然,也有看起来不错的低对比度图片,但它的直方图不会像上图那样极端,一般都是没有纯黑,但高光都比较足:
  

 

均衡化

(a) vs (e)  对比度有所加强。

However,可能放大暗区域的噪声。 

它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。

http://blog.csdn.net/xiaowei_cqu/article/details/7606607
从分布图上的理解就是希望原始图像中y轴的值在新的分布中尽可能的展开。
变换过程是利用累积分布函数对原始分布进行映射,生成新的均匀拉伸的分布。
因此,对应每个点的操作是寻找原始分布中y值在均匀分布中的位置,如下图是理想的单纯高斯分布映射的示意图:

int main()  
{  
    IplImage * image= cvLoadImage("baboon.jpg");  
    //显示原图及直方图  
    myShowHist("Source",image);  
      
    IplImage* eqlimage=cvCreateImage(cvGetSize(image),image->depth,3);  
    //分别均衡化每个信道  
    IplImage* redImage=cvCreateImage(cvGetSize(image),image->depth,1);  
    IplImage* greenImage=cvCreateImage(cvGetSize(image),image->depth,1);  
    IplImage* blueImage=cvCreateImage(cvGetSize(image),image->depth,1);  
    cvSplit(image,blueImage,greenImage,redImage,NULL);  
  
    cvEqualizeHist(redImage,redImage);  
    cvEqualizeHist(greenImage,greenImage);   
    cvEqualizeHist(blueImage,blueImage);   
    //均衡化后的图像  
    cvMerge(blueImage,greenImage,redImage,NULL,eqlimage);  
    myShowHist("Equalized",eqlimage);  
}  
cvEqualizeHist

此函数只能处理单通道的灰色图像,对于彩色图像,我们可以把每个信道分别均衡化,再Merge为彩色图像。

 

算法演示:

 

 

 

自定义均衡化

(直方图匹配 or 直方图规定化)

 

//将图像与特定函数分布histv[]匹配  
void myHistMatch(IplImage *img,double histv[])  
{  
    int bins = 256;  
    int sizes[] = {bins};  
    CvHistogram *hist = cvCreateHist(1,sizes,CV_HIST_ARRAY);  
    cvCalcHist(&img,hist);  
    cvNormalizeHist(hist,1);  
    double val_1 = 0.0;  
    double val_2 = 0.0;  
    uchar T[256] = {0};  
    double S[256] = {0};  
    double G[256] = {0};  
    for (int index = 0; index<256; ++index)  
    {  
        val_1 += cvQueryHistValue_1D(hist,index);  
        val_2 += histv[index];  
        G[index] = val_2;  
        S[index] = val_1;  
    }  
  
    double min_val = 0.0;  
    int PG = 0;  
    for ( int i = 0; i<256; ++i)  
    {  
        min_val = 1.0;  
        for(int j = 0;j<256; ++j)  
        {  
            if( (G[j] - S[i]) < min_val && (G[j] - S[i]) >= 0)  
            {  
                min_val = (G[j] - S[i]);  
                PG = j;  
            }  
  
        }  
        T[i] = (uchar)PG;  
    }  
  
    uchar *p = NULL;  
    for (int x = 0; x<img->height;++x)  
    {   
        p = (uchar*)(img->imageData + img->widthStep*x);  
        for (int y = 0; y<img->width;++y)  
        {  
            p[y] = T[p[y]];  
        }  
    }  
}  
  
// 生成高斯分布  
void GenerateGaussModel(double model[])  
{  
    double m1,m2,sigma1,sigma2,A1,A2,K;  
    m1 = 0.15;  
    m2 = 0.75;  
    sigma1 = 0.05;  
    sigma2 = 0.05;  
    A1 = 1;  
    A2 = 0.07;  
    K = 0.002;  
  
    double c1 = A1*(1.0/(sqrt(2*CV_PI))*sigma1);  
    double k1 = 2*sigma1*sigma1;  
    double c2 = A2*(1.0/(sqrt(2*CV_PI))*sigma2);  
    double k2 = 2*sigma2*sigma2;  
    double p = 0.0,val= 0.0,z = 0.0;  
    for (int zt = 0;zt < 256;++zt)  
    {  
        val = K + c1*exp(-(z-m1)*(z-m1)/k1) + c2*exp(-(z-m2)*(z-m2)/k2);  
        model[zt] = val;  
        p = p +val;  
        z = z + 1.0/256;  
    }  
    for (int i = 0;i<256; ++i)  
    {  
        model[i] = model[i]/p;  
    }  
}   
cvCalcHist

将图像规定化为高斯分布函数。

 

算法演示:

计算变换函数 根据 规定的直方图 得来。但非严格单调,所以需要:

    (a:s值) --> (b:z值)    

 

 发现:S0G(Z3)竟然一致,正好匹配。 

 

 

 

 

对比直方图

通过直方图匹配,可以使图像的相似度变高,但也仅仅是从颜色的角度。

int main()  
{  
    IplImage * image= cvLoadImage("myhand1.jpg");  
    IplImage * image2= cvLoadImage("myhand2.jpg");  
    int hist_size=256;  
    float range[] = {0,255};  
    float* ranges[]={range};  
      
    IplImage* gray_plane = cvCreateImage(cvGetSize(image),8,1);  
    cvCvtColor(image,gray_plane,CV_BGR2GRAY);  
    CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);  
    cvCalcHist(&gray_plane,gray_hist,0,0);  
  
  
    IplImage* gray_plane2 = cvCreateImage(cvGetSize(image2),8,1);  
    cvCvtColor(image2,gray_plane2,CV_BGR2GRAY);  
    CvHistogram* gray_hist2 = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);  
    cvCalcHist(&gray_plane2,gray_hist2,0,0);  
    
    //相关:CV_COMP_CORREL      
    //卡方:CV_COMP_CHISQR  
    //直方图相交:CV_COMP_INTERSECT  
    //Bhattacharyya距离:CV_COMP_BHATTACHARYYA  
    double  com=cvCompareHist(gray_hist,gray_hist2,CV_COMP_BHATTACHARYYA);  
  
    cout<<com<<endl;  
}  
cvCompareHist

cvCompareHist的结果为【0,1】的浮点数,越小表示两幅图匹配度越高,0.0时两幅图精确匹配。  

提供的对比方法有四种:

     

 

局部增强 (涉及到统计,大有可为)

分辨亮区域与暗区域的不同,同时只增强暗区域。

 

posted @ 2016-07-18 18:22  郝壹贰叁  阅读(1344)  评论(0编辑  收藏  举报