OpenCV计算和显示图像直方图

来源:互联网 发布:网络机顶盒直播节目源 编辑:程序博客网 时间:2024/05/21 10:28

要在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方法,获取成员变量histSizeint*  Histogram1D::getHistSize(){    return histSize;}//set方法,设置成员变量histSizevoid  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):
这里写图片描述

0 0
原创粉丝点击