Opencv Cookbook阅读笔记(四):用直方图统计像素

灰度直方图的定义

灰度直方图是灰度级的函数,描述图像中该灰度级的像素个数(或该灰度级像素出现的频率):其横坐标是灰度级,纵坐标表示图像中该灰度级出现的个数(频率)。
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <iostream>  

using namespace cv;
using namespace std;

class Histogram1D
{
    //定义一个处理单通道的类
private:
    int histSize[1];//bin的数量
    float hranges[2];//值范置 
    const float* ranges[1];//值范围的指针.指向常量的指针(所指对像不一定是个常量),不能通过指针修改其值
    int channels[1];//通道数量


    Mat getHistogram(const Mat &image)
    {
        //统计直方图
        Mat hist;
        calcHist(&image, 1,//一个图像的直方图
            channels,//使用的通道
            Mat(),//不使用掩码
            hist,//作为结果的直方图
            1,//一维直方图
            histSize,
            ranges
            );

        return hist;
    }

public:
    Histogram1D()
    {
        histSize[0] = 256;
        hranges[0] = 0;//从0到256
        hranges[1] = 256;

        ranges[0] = hranges;

        channels[0] = 0;
    }

    Mat getImageOfHistogram(const Mat &image, int zoom=1)
    {
        //zoom通道数
        //画出直方图

        Mat hist = getHistogram(image);

        return getImageOfHistogram1(hist, zoom);
    }

    //定义为静态,不对成员变量进行操作
    static Mat getImageOfHistogram1(const Mat &hist, int zoom)
    {
        //取得箱子的最大值和最小值
        double maxVal = 0, minVal = 0;
        minMaxLoc(hist, &minVal, &maxVal,0,0);

        int histSize = hist.rows;
        //用于显示的直方图
        Mat histImg(histSize*zoom, histSize*zoom, CV_8U, Scalar(255));
        //设置最高点为90%的箱子个数
        int hpt = static_cast<int>(0.9*histSize);

        //为每个箱子画垂线
        for (int h = 0; h < histSize; h++)
        {
            float binVal = hist.at<float>(h);
            if (binVal>0)
            {
                int intensity = static_cast<int>(binVal*hpt / maxVal);//相对高度
                line(histImg, Point(h*zoom, histSize*zoom),
                    Point(h*zoom, (histSize - intensity)*zoom),
                    Scalar(0), zoom);
            }
        }

        return histImg;
    }
};

int main()
{

    Mat image = imread("1.jpg");
    //判断是否为空
    Histogram1D h;
    //Mat histo = h.getHistogram(image);
    Mat histo = h.getImageOfHistogram(image);
    //namedWindow("Histogram");
    //imshow("Histogram",histo);
    //输出二值图像
    Mat thresholded;
    threshold(image, thresholded, 200,//阈值
        255,//对超过域值的像素赋值
        THRESH_BINARY);//阈值化类型

    imshow("threshold", thresholded);
    waitKey(0);

    return 0;
}
View Code

上面的程序是计算并画出单通下图像的直方图,主要就是calcHist函数。类似的可以定义一个计算彩色直方图的类。

class ColorHistgoram
{
private:
    int histSize[3];
    float hranges[2];
    const float*ranges[3];
    int channels[3];
public:
    ColorHistgoram()
    {
        histSize[0] = histSize[1] = histSize[2] = 256;
        hranges[0] = 0;
        hranges[1] = 256;

        ranges[0] = hranges;
        ranges[1] = hranges;
        ranges[2] = hranges;

        channels[0] = 0;
        channels[1] = 1;
        channels[2] = 2;
    }

    Mat getHistogram(const Mat &image)
    {
        Mat hist;

        calcHist(&image,1, channels, Mat(), hist, 3, histSize, ranges);

        return hist;
    }
};
View Code

提高图像对比度

有两种方法,一是应用查找表来伸展直方图(有的强度值范围没有被利用),另一种是直方图均衡化(对所有可用的像素强度值都均衡使用)。

//查找表函数
    static Mat applyLookUp(const Mat &image, const Mat &lookup)
    {
        Mat result;
        LUT(image, lookup, result);

        return result;
    }

    //通过查找表提高图像的对比度
    Mat stretch(const Mat &image, int minValue = 0)
    {
        Mat hist = getHistogram(image);

        //找到直方图的左右限值
        float imin;
        for (imin=0;imin < histSize[0]; imin++)
        {
            //忽略数量较少的箱子
            float x = hist.at<float>(imin);
            if (x>minValue)
                break;
        }
        int imax = histSize[0] - 1;
        for (; imax >= 0; imax--)
        {
            if (hist.at<float>(imax)>minValue)
                break;
        }

        //创建查找表
        int dim(256);
        Mat lookup(1,//一维
            &dim, CV_8U);
        for (int i = 0; i < 256; i++)
        {
            //
            if (i < imin)lookup.at<uchar>(i) = 0;
            else if (i>imax)lookup.at<uchar>(i) = 255;
            else
                lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
        }

        Mat result;
        result = applyLookUp(image, lookup);

        return result;
    }
View Code

 通过如下的函数可实现直方图均衡化。

//灰度图
    equalizeHist(image, result);
原文地址:https://www.cnblogs.com/573177885qq/p/5672841.html