0014-OpenCV环境下计算并绘制灰度直方图的源码!

图像的直方图是图像进行运算时的一个重要的数据特征,许多算法都需要用到图像的直方图数据,OpenCV提供了函数calcHist用来计算图像的直方图数据。这个函数的参数较多,下面介绍这个函数。
calcHist的原型如下
void calcHist(const Mat* images, int nimages,const int* channels, InputArray mask,OutputArray hist, int dims,const int* histSize,const float** ranges, bool uniform = true, bool accumulate = false);
参数意义如下
images:源图像数组,数组内的图片应该有相同的深度和大小,图像深度只能是CV_8U或CV_32F,通道数可以不同,注意这个参数是指针。
nimages:要计算图像的个数。
channel:计算哪些通道的直方图。通道编号方法:第一张图的通道编号为0至images[0].channels()-1,第二张图的通道编号为images[0].channels()至images[0].channels() + images[1].channels()-1,以此类推,注意这个参数是指针。
mask:掩码阵列。掩码中的非0元素对应的图像元素将会被计算,0元素则被屏蔽不参与计算。掩码阵列可以为空。
hist:直方图计算结果存储阵列。
dims:直方图的维度,比如灰度图的直方图为1维,H-S直方图为2维,以此类推,最大不超过CV_MAX_DIMS,目前CV_MAX_DIMS=32。
histSize:各个维度的大小。
ranges:存储每个维度的统计范围。
uniform:直方图是否均匀化的标志,意义暂时不清楚,等以后搞清楚了再来补充说明。
accumulate:记忆标志。表示这个函数空间被再次调用前是否清零,如果不清零,则可以使得用户存储多张图的直方图数据,或者对之前的计算过的直方图进行更新。
OpenCV下计算并绘制直方图的代码如下

图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!
源码中使用的图像下载链接:http://pan.baidu.com/s/1kUJMx1t 密码:r3d3

//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>

#include <iostream>

using namespace cv;
using namespace std;

int main()
{

        Mat img = imread("02.jpg");
        if (img.empty())
        {
                cout << "Error: Could not load image" << endl;
                return 0;
        }

        Mat srcImage;
        cvtColor(img, srcImage, CV_BGR2GRAY);

        imshow("【原图的灰度图】", srcImage);

        //为计算直方图配置变量  
        //首先是需要计算的通道编号,就是需要计算哪个通道的直方图(BGR空间需要确定计算,计算方法见帖子中对相关参数的说明)  
        int channels = 0;
        //然后是定义直方图计算结果的存储空间
        Mat dstHist;
        //接下来是直方图的每一个维度的数目(这个数目用于将每一维度的数值分组)  
        int histSize[] = { 256 }; 
        //最后是确定每个维度的取值范围,就是每一维度的横坐标的取值范围  
        //首先得定义一个数组用来存储单个维度的的取值范围  
        float midRanges[] = { 0, 256 };
        //然后把这个数组再放到一个二维数组中
        const float *ranges[] = { midRanges };

        //准备工作做好后,就可以调用calcHis函数计算直方图数据了
        calcHist(&srcImage, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);

        //calcHist函数调用结束后,dstHist变量中将储存直方图数据 

        //接下来绘制直方图
        //首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像  
        Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);

        //因为图像中的某个灰度值的总个数可能会超出所定义的图像的尺寸,所以要对个数进行归一化处理

        //先用 minMaxLoc函数来得到计算直方图中的最大数据,这个函数的使用方法大家一看函数原型便知
        double g_dHistMaxValue;
        minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);


        //遍历直方图数据,对数据进行归一化和绘图处理
        for (int i = 0; i < 256; i++)
        {
                int value = cvRound(dstHist.at<float>(i) * 256 * 0.9 / g_dHistMaxValue);

                //line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(255, 0, 0));

                line(drawImage, Point(i,0), Point(i, value), Scalar(255, 0, 0));
        }

        //对绘制出的图像作y方向上的翻转处理,以符合我们的看图习惯

        // 输出矩阵定义
        Mat resultImage(drawImage.size(), drawImage.type());
        // X与Y方向矩阵
        Mat xMapImage(drawImage.size(), CV_32FC1);
        Mat yMapImage(drawImage.size(), CV_32FC1);
        int rows = drawImage.rows;
        int cols = drawImage.cols;

        for (int j = 0; j < rows; j++)
        {
                for (int i = 0; i < cols; i++)
                {
                        // y方向上翻转
                        xMapImage.at<float>(j, i) = i;
                        yMapImage.at<float>(j, i) = rows - j;
                }
        }
        // 重映射操作
        remap(drawImage, resultImage, xMapImage, yMapImage,
                CV_INTER_LINEAR, cv::BORDER_CONSTANT,
                cv::Scalar(0, 0, 0));

        imshow("【未翻转前的直方图】", drawImage);
        imshow("【翻转后的直方图】", resultImage);

        waitKey(0);

        return 0;
}

代码说明
代码中用到了line函数来绘制直方图,这里给出它的原型,大家看下原型再结合原型自然就明白了怎么用了。
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,int thickness = 1, int lineType = LINE_8, int shift = 0);
另外,大家要注意,在opencv中,坐标原点在左上角,也就是说向下为y轴正方向,所以代码中为了大家的阅读习惯还对图像进行了一次翻转处理。翻转部分代码的原理请大家参看博文https://blog.csdn.net/lehuoziyuan/article/details/84029770
代码运行结果截图如下

猜你喜欢

转载自blog.csdn.net/lehuoziyuan/article/details/84064822