OpenCV 学习(计算图像的直方图)

OpenCV 计算图像的直方图

计算图像的直方图是图像处理领域一个非常常见的基本操作。 OpenCV 中提供了 calcHist 函数来计算图像直方图。不过这个函数说实话挺难用的,研究了好久才掌握了些基本的用法。

calcHist 函数 C++ 的函数原型如下:

void calcHist(const Mat* images,
    int nimages,
    const int* channels,
    InputArray mask,
    SparseMat& hist,
    int dims,
    const int* histSize,
    const float** ranges,
    bool uniform=true,
    bool accumulate=false )

各个参数的含义如下:

  • images:输入的图像的指针,可以是多幅图像,但是所有的图像必须有同样的深度(CV_8U or CV_32F)。一副图像可以有多个 channels。
  • nimages:输入的图像的个数。
  • channels:用来计算直方图的 channels 的数组。
  • mask:掩码,如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和输入的图像的大小相同,值非 0 的点将用来计算直方图。
  • hist:输出参数,计算出来的直方图。
  • dims:直方图的维数,不能大于 CV_MAX_DIMS (在现有版本中是 32)。
  • histSize: 在每一维上直方图的元素个数。
  • ranges: 所需计算直方图的每一维的范围。ranges 是个指向数组的数组。我们称它指向的那些数组为 ranges 的元素,元素大小也就是这些数组的长度。

如果参数 uniform 为 true,这此时的ranges 里元素的大小为 2(也就是说 ranges 指向一系列长度为 2 的数组),存储的是每一维的上下限这两个数字;如果参数 uniform 为 false,则此时的 ranges 的元素大小为 bin 的个数,存储的是一个个颜色值,即每一维的坐标值不一定是均匀的,需要人为指定。

  • uniform: 如果为 true 的话,则说明所需计算的直方图的每一维按照它的范围和尺寸大小均匀取值;如果为 false 的话,说明直方图的每一维不是均匀分布取值的,参考参数 ranges 的解释。
  • accumulate: 表示是否对传入的 hist 清零。不清零的话可以将多幅图像的直方图累加。

看上面这个解释大家应该就能感觉出这个函数有多麻烦了吧。不过好在我们一般只会用到一些最基本的功能。比如计算个单通道灰度图像的直方图。直方图的取值范围一般来说也会是 0 到 255。 这时我们可以把这个函数再进行一次封装,使其更好用一些。

下面的代码来自 《OpenCV 2 Computer Vision Application Programming Cookbook》。 书的作者写了一个类,叫做 Histogram1D。

这个类的声明如下:

class Histogram1D
{
public:
    Histogram1D()
    {
        // Prepare arguments for 1D histogram
        histSize[0] = 256;
        hranges[0] = 0.0;
        hranges[1] = 255.0;
        ranges[0] = hranges;
        channels[0] = 0; // by default, we look at channel 0
    }
    ~Histogram1D();
    // Computes the 1D histogram and returns an image of it.
    cv::Mat getHistogramImage(const cv::Mat &image);
    // Computes the 1D histogram.
    cv::MatND getHistogram(const cv::Mat &image);
private:
    int histSize[1]; // number of bins
    float hranges[2]; // min and max pixel value
    const float* ranges[1];
    int channels[1]; // only 1 channel used here

};

getHistogram 函数用来计算直方图。实现如下:

// Computes the 1D histogram.
cv::MatND Histogram1D::getHistogram(const cv::Mat &image)
{
    cv::MatND hist;
    // Compute histogram
    cv::calcHist(&image,
        1, // histogram from 1 image only
        channels, // the channel used
        cv::Mat(), // no mask is used
        hist, // the resulting histogram
        1, // it is a 1D histogram
        histSize, // number of bins
        ranges // pixel value range
    );
    return hist;
}

getHistogramImage 函数用来生成直方图的图像:

// Computes the 1D histogram and returns an image of it.
cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image)
{
    // Compute histogram first
    cv::MatND hist = getHistogram(image);
    // Get min and max bin values
    double maxVal = 0;
    double minVal = 0;
    cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
    // Image on which to display histogram
    cv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255));
    // set highest point at 90% of nbins
    int hpt = static_cast<int>(0.9 * histSize[0]);
    // Draw a vertical line for each bin
    for( int h = 0; h < histSize[0]; h++ )
    {
        float binVal = hist.at<float>(h);
        int intensity = static_cast<int>(binVal * hpt / maxVal);
        // This function draws a line between 2 points
        cv::line(histImg, cv::Point(h, histSize[0]),
        cv::Point(h,histSize[0]-intensity), cv::Scalar::all(0));
    }
    return histImg;
}

还有另外一个类可以计算彩色图像的直方图。不过这个用途不是很大。因为彩色图像的颜色空间太大了。而且形成的直方图是个三维的数组。用起来也不方便。为了完整,这里还是把代码列了出来。

class ColorHistogram
{
public:
    ColorHistogram()
    {
        // Prepare arguments for a color histogram
        histSize[0] = histSize[1] = histSize[2] = 256;
        hranges[0] = 0.0; // BRG range
        hranges[1] = 255.0;
        ranges[0] = hranges; // all channels have the same range
        ranges[1] = hranges;
        ranges[2] = hranges;
        channels[0] = 0; // the three channels
        channels[1] = 1;
        channels[2] = 2;
    }
    cv::MatND getHistogram(const cv::Mat &image) ;
    cv::SparseMat getSparseHistogram(const cv::Mat &image) ;
private:
    int histSize[3];
    float hranges[2];
    const float* ranges[3];
    int channels[3];
};

这里实现了两个函数 getHistogram 和 getSparseHistogram。 唯一的区别就是 getSparseHistogram 返回的是个稀疏矩阵。

cv::MatND ColorHistogram::getHistogram(const cv::Mat &image)
{
    cv::MatND hist;
    // Compute histogram
    cv::calcHist(&image,
                 1, // histogram of 1 image only
                 channels, // the channel used
                 cv::Mat(), // no mask is used
                 hist, // the resulting histogram
                 3, // it is a 3D histogram
                 histSize, // number of bins
                 ranges // pixel value range
                 );
    return hist;
}

cv::SparseMat ColorHistogram::getSparseHistogram(const cv::Mat &image)
{
    cv::SparseMat hist(3,histSize,CV_32F);
    // Compute histogram
    cv::calcHist(&image,
                 1, // histogram of 1 image only
                 channels, // the channel used
                 cv::Mat(), // no mask is used
                 hist, // the resulting histogram
                 3, // it is a 3D histogram
                 histSize, // number of bins
                 ranges // pixel value range
                 );
    return hist;
}
时间: 2024-10-26 18:50:05

OpenCV 学习(计算图像的直方图)的相关文章

OpenCV2+入门系列(四):计算图像的直方图,平均灰度,灰度方差

本篇懒得排版,直接在网页html编辑器编辑 在图像处理时,我们常常需要求出图像的直方图.灰度平均值.灰度的方差,这里给出一个opencv2+自带程序,实现这些功能. 直方图 对于直方图,使用cv::calcHist函数可以求出. 原型 void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize,

opencv学习笔记-图像叠加、混合

在图像处理中,目标区域定义为感兴趣区域ROI(region of Interest),这是后期图像处理的基础,在获取ROI后,进行一些列的处理.ROI区域在Opencv中就是Rect,先构建Rect,然后给予ROI一些特点,形成了图像掩膜. 一.ROI创建 //定义一个Mat类型并给其设定ROI区域 Mat imageROI; //方法一 imageROI=image(Rect(500,250,logo.cols,logo.rows)); //方法二 imageROI=Image(Range(2

Python下的OpenCV学习 02 —— 图像的读取与输出

OpenCV提供了众多对图片操作的函数,其中最基本的就是图片的读取与输出了. 一.读取图片 利用OpenCV读取一张图片是非常容易的,只需要用到 imread() 函数,我们进入IPython,输入help(cv2.imread)获取该函数的文档,得到: imread(...)     imread(filename[, flags]) -> retval 可见, imread需要提供两个参数,第一个是图片的路径,第二个是图片读取的模式(flags),函数返回一个存储着图片像素数据的矩阵. fl

OpenCV学习:图像的载入和显示

一.使用IplImage结构读取并显示图像文件: 运行结果: 二.使用Mat类读取并显示图像文件: 使用 Mat 类,内存管理变得简单,不再像使用 IplImage 那样需要自己申请和释放内存,而且一些函数,如imread.imshow以及imwrite等与之前用过的matlab图像处理工具箱同名,使用起来非常方便. 运行结果:

opencv 小任务3 灰度直方图

#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> using namespace cv; using namespace std; int main() { Mat srcImage = imread("F://19.jpg"); imshow("原图", srcImag

OpenCV学习之六: 使用方向梯度直方图估计图像旋转角度

在备份ltedecoder程序时,需要把此目录拷由到bak目录下,但decoder目录下有个大文件,不需要备份,还有日志问题,也不需要备份,如何实现呢?? 方法: cd /source-dir find . -name .snapshot -prune -o -print0 | cpio -pmd0 /dest-dir 解释: This command copies the contents of /source-dir to /dest-dir, but omits files and dir

【OpenCV学习】计算两幅图像的重叠区域

问题描述:已知两幅图像Image1和Image2,计算出两幅图像的重叠区域,并在Image1和Image2标识出重叠区域. 算法思想: 若两幅图像存在重叠区域,则进行图像匹配后,会得到一张完整的全景图,因而可以转换成图像匹配问题. 图像匹配问题,可以融合两幅图像,得到全景图,但无法标识出在原图像的重叠区域. 将两幅图像都理解为多边形,则其重叠区域的计算,相当于求多边形的交集. 通过多边形求交,获取重叠区域的点集,然后利用单应矩阵还原在原始图像的点集信息,从而标识出重叠区域. 算法步骤: 1.图像

OpenCV2学习笔记(二):图像的直方图

直方图(Histogram)又称质量分布图.是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况.一般用横轴表示数据类型,纵轴表示分布情况.众所周知,一幅图像是由不同颜色值的像素组成,因此像素值在图像中的分布情况是这幅图像的一个重要特征,因此直方图广泛应用在数字图像处理中. 拍照是现实生活中必不可少的一部分,由于环境亮度.图像拍摄过程中透视光圈设置错误等影响,经常会拍出一些"过暗"的照片,此时美图.PS等美化工具可以派上用场.但是这些工具的算法通常都是不公开的,鉴于研究

opencv python:图像直方图 histogram

直接用matplotlib画出直方图 def plot_demo(image): plt.hist(image.ravel(), 256, [0, 256]) # image.ravel()将图像展开,256为bins数量,[0, 256]为范围 plt.show() 图像直方图 def image_hist(image): color = ('blue', 'green', 'red') for i, color in enumerate(color): # 计算出直方图,calcHist(i