OpenCV计算和显示图像直方图

要在OpenCV中计算直方图,可调用函数calcHist(),

void calcHist(const Mat* images,//源图像
 int nimages,//源图像的个数。设为1,则仅为一个图像的直方图
  const int* channels,//使用的通道
  InputArray mask, //掩码,(可设置哪些像素不参与直方图计算)
  OutputArray hist, //作为结果的直方图
  int dims, //直方图的维数
  const int* histSize,//直方图箱子的数量
  const float** ranges, //像素值的范围
  bool uniform=true, 
  bool accumulate=false )

这是一个通用的直方图计算函数,可处理包含任何值类型和范围的多通道图像。为了简化使用,在这里构建两个计算直方图的类:分别处理单通道图像和彩色图像。

单通道图像

比如单通道图像可以这样调用类函数来计算直方图:

Histogram1D h;//直方图计算得算法类
h.setHistSize(256);//设置直方图的箱子数量
cv::Mat hist=h.getHistogram(image);//计算直方图
cv::Mat histImg = h.getHistogramImage(image, 1);//将直方图画出来,返回直方图图像
cv::imshow("histogram", histImg);

单通道图像计算直方图的算法类如下:

//头文件 Histogram1D.h
#pragma once
#include"opencv2/opencv.hpp"
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"

class Histogram1D
{
private:
    int channels[1];//使用的通道数量
    int histSize[1];//直方图箱子(bin)的数量
    const float* ranges[1];//像素值范围
    float hranges[2];
public:
    Histogram1D();
    cv::Mat getHistogram(const cv::Mat& image);//得到直方图
    void setHistSize(int n);//设置直方图箱子数量
    int* getHistSize();
    static cv::Mat applyLookUp(const cv::Mat& image,const cv::Mat& lookup);//应用查找表
    cv::Mat getHistogramImage(const cv::Mat& image,int zoom);//得到直方图图像
    ~Histogram1D();
};
//实现文件 Histogram1D.cpp
#include "Histogram1D.h"

Histogram1D::Histogram1D()
{
    histSize[0] = 256;//箱子个数设为256
    channels[0] = 0;//使用一个通道,默认为0
    hranges[0] = 0.0;
    hranges[1] = 256.0;
    ranges[0] = hranges;//值范围
}

Histogram1D::~Histogram1D()
{
}

cv::Mat Histogram1D::getHistogram(const cv::Mat& image)
{
    cv::Mat hist;
    cv::calcHist(&image,
        1,//单幅图像的直方图
        channels,
        cv::Mat(),
        hist,
        1,//一维直方图
        histSize,
        ranges);
    return hist;
}

cv::Mat Histogram1D::getHistogramImage(const cv::Mat& image, int zoom = 1)
{
    cv::Mat hist = getHistogram(image);
    //这里调用静态方法
    return getImageOfHistogram(hist,zoom);
}

cv::Mat getImageOfHistogram(const cv::Mat& hist, 
    int zoom//设置缩放系数
    )
{
    double minVal = 0;
    double maxVal = 0;
    cv::minMaxLoc(hist,&minVal,&maxVal,0,0);

    int histSize = hist.rows;

    //用于显示直方图的方形图像
    cv::Mat histImg(histSize*zoom,histSize*zoom,CV_8U,cv::Scalar(255));

    //设置最高点为90%的箱子个数
    int hmax = static_cast<int>(histSize*0.9);

    //画线
    for (int h = 0; h < histSize;h++)
    {
        float binVal= hist.at<float>(h);
        if (binVal > 0)
        {
            int intensity = binVal*hmax / maxVal;
            cv::line(histImg, cv::Point(h*zoom, histSize*zoom), cv::Point(h*zoom, (histSize-intensity)*zoom), cv::Scalar(0), zoom);
        }
    }
    return histImg;
}
//应用查找表相关的函数
cv::Mat Histogram1D::applyLookUp(const cv::Mat& image, const cv::Mat& lookup)
{
    cv::Mat result;
    cv::LUT(image,lookup,result);
    return result;
}
//get方法,获取成员变量histSize
int*  Histogram1D::getHistSize()
{
    return histSize;
}
//set方法,设置成员变量histSize
void  Histogram1D::setHistSize(int n)
{
    histSize[0] = n;
}

运行效果如下:
输入图像
这里写图片描述
直方图
这里写图片描述


彩色图像

再比如,彩色图像可以这样调用类函数来计算直方图:

ColorHistogram hc;//直方图计算得算法类
hc.setSize(16);//设置每个通道直方图箱子数量
cv::Mat hist=hc.getHistogram(image);//计算直方图
//或者
//cv::Mat hist=hc.getHueHistogram(image);//计算H通道直方图
//cv::Mat histImg=hc.getHistImage(hist,16);//放大16倍,使图像能以256*256大小显示
//imshow("histImg",histImg);

彩色图像计算直方图的算法类如下:

//头文件 ColorHistogram.h
#pragma once
#include"opencv2/opencv.hpp"
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"

class ColorHistogram
{
private:
    int channels[3];//使用的通道数量
    int histSize[3];//直方图箱子(bin)的数量
    const float* ranges[3];//存放值范围(3个通道)
    float hranges[2];
public:
    ColorHistogram();
    cv::Mat getHistogram(const cv::Mat& image);
    cv::Mat getHueHistogram(const cv::Mat& image,int minSaturation);//设置饱和度阈值的原因是低饱和度图像RGB分量几乎相同,                                                               //很难确定准确颜色,故排除

    void setSize(int n);//设置直方图箱子数量
    ~ColorHistogram();
};
//实现文件 ColorHistogram.cpp
#include "ColorHistogram.h"

ColorHistogram::ColorHistogram()
{
    histSize[0] = 256;//箱子个数设为256
    histSize[1] = 256;//箱子个数设为256
    histSize[2] = 256;//箱子个数设为256

    channels[0] = 0;//使用通道0
    channels[1] = 1;//使用通道1
    channels[2] = 2;//使用通道2

    hranges[0] = 0.0;
    hranges[1] = 256.0;
    ranges[0] = hranges;//值范围
    ranges[1] = hranges;//值范围
    ranges[2] = hranges;//值范围
}

cv::Mat ColorHistogram::getHistogram(const cv::Mat& image)
{
    cv::Mat hist;
    cv::calcHist(&image,
        1,//单个图像的直方图
        channels,
        cv::Mat(),
        hist,
        3,//3维直方图
        histSize,
        ranges);
    return hist;
}

void  ColorHistogram::setSize(int n)
{
    histSize[0] = n;
    histSize[1] = n;
    histSize[2] = n;

}

cv::Mat ColorHistogram::getHueHistogram(const cv::Mat& image, int minSaturation)
{
    cv::Mat hist;
    cv::Mat hsv;
    cv::cvtColor(image,hsv,CV_BGR2HSV);

    //掩码,计算直方图时掩盖低饱和度像素贡献
    cv::Mat mask;
    if (minSaturation > 0)
    {
        std::vector<cv::Mat> v;
        cv::split(hsv,v);
        //饱和度通道
        cv::threshold(v[1],mask,minSaturation,255,cv::THRESH_BINARY );
    }

    hranges[0] = 0.0;
    hranges[1] = 180;
    channels[0] = 0;

    cv::calcHist(&hsv,
        1,//单个图像的直方图
        channels,
        mask,
        hist,
        1,//3维直方图
        histSize,
        ranges);
    return hist;
}

ColorHistogram::~ColorHistogram()
{
}

运行效果如下:
输入图像
这里写图片描述
这里插几句嘴。。

cv::Mat hist=hc.getHistogram(image);//计算直方图

上述方法返回的是三维的cv::Mat实例。如果选用含有256个箱子的直方图,这个矩阵的像素个数为256^3。形象的讲,它是一个正方体。所以无法显示。
类中计算直方图还有一种方法:

cv::Mat hist=hc.getHueHistogram(image);//计算H通道直方图

首先将输入图像转化为HSV格式,H代表色调,代表颜色信息。这样得到的是一维直方图,结果如下(这里将直方图箱子数量设为16):
这里写图片描述

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值