OpenCV-绘制图像的像素直方图-Histogram

来源:互联网 发布:jquery each 数组 编辑:程序博客网 时间:2024/06/02 12:10

随手翻了翻之前推荐的那本OpenCV2的教程,突然发现了之前看图像处理中的像素直方图的实现教程,原本就打算找时间自己实现的,没想到opencv是有这个功能的

而且这个功能可以辅助很多的图像处理和识别的算法过程,是值得看一看的

OpenCV对于像素直方图的统计有这么一个函数:

void calcHist(const Mat* arrays, 
             int narrays, 
             const int* channels, 
             InputArray mask, 
             OutputArray hist, 
             int dims, 
             const int* histSize, 
             const float** ranges, 
             bool uniform=true, 
             bool accumulate=false )

下面贴出官方的参数解释,我觉得很好明白的

Parameters
        arrays
– Source arrays. They all should have the same depth, CV_8U or CV_32F , and the
                        same size. Each of them can have an arbitrary number of channels.
        narrays – Number of source arrays.
        channels – List of the dims channels used to compute the histogram. The first ar-
                             ray channels are numerated from 0 to arrays[0].channels()-1 , the second ar-
                             ray channels are counted from arrays[0].channels() to arrays[0].channels() +
                             arrays[1].channels()-1, and so on.
       mask – Optional mask. If the matrix is not empty, it must be an 8-bit array of the same
                     size as arrays[i] . The non-zero mask elements mark the array elements counted in the
                     histogram.
      hist – Output histogram, which is a dense or sparse dims -dimensional array.
      dims – Histogram dimensionality that must be positive and not greater than CV_MAX_DIMS
                   (equal to 32 in the current OpenCV version).
      histSize – Array of histogram sizes in each dimension.
      ranges – Array of the dims arrays of the histogram bin boundaries in each dimension.
                       When the histogram is uniform ( uniform =true), then for each dimension i it is enough to
                      specify the lower (inclusive) boundary L0 of the 0-th histogram bin and the upper (exclusive)
                      boundary UhistSize[i]−1 for the last histogram bin histSize[i]-1 . That is, in case of a
                      uniform histogram each of ranges[i] is an array of 2 elements. When the histogram is not
                      uniform ( uniform=false ), then each of ranges[i] contains histSize[i]+1 elements:
                      L0 , U0 = L1 , U1 = L2 , ..., UhistSize[i]−2 = LhistSize[i]−1 , UhistSize[i]−1 . The array
                      elements, that are not between L0 and UhistSize[i]−1 , are not counted in the histogram.
       uniform – Flag indicatinfg whether the histogram is uniform or not (see above).
       accumulate – Accumulation flag. If it is set, the histogram is not cleared in the beginning
                                when it is allocated. This feature enables you to compute a single histogram from several
                                sets of arrays, or to update the histogram in time.

代码:

#include <opencv2/opencv.hpp>#include <iostream>using namespace std;class Histogram{        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        public:                Histogram()                {                        //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                }                cv::MatND getHistogram(const cv::Mat &image)                {                        cv::MatND hist;                        //Compute histogram                        cv::calcHist(&image,                                        1,                                        channels,                                        cv::Mat(),                                        hist,                                        1,                                        histSize,                                        ranges                                        );                     return hist;                }                //Compute the 1D histogram and returns an image of it                cv::Mat 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);                        //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 draw 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;                }};int main(){        //Read input image        cv::Mat image = cv::imread("1.png",0);//open in b&w        //the histogram object        Histogram h;        //Compute the histogram        /*cv::MatND histo = h.getHistogram(image);        for(int i = 0;i<256;i++)        {                cout<<"Value "<<i<<"="<<histo.at<float>(i) <<endl;        }*/        cv::namedWindow("Histogram");        cv::imshow("Histogram",h.getHistogramImage(image));        cv::waitKey(0);        return 0;}

需要注意的是imread这个函数后面的那个参数,不清楚的可以查阅官方的手册~

截图:



上面的代码只是读取的灰度图像反馈的1D的直方图,那么如果我是3通道的RGB/BGR图像呢?只需要做相应的修改然后函数便会返回3*256的一个Mat值

        private:                int histSize[3];//number of bins                float hranges[2];//min and max pixel value                const float* ranges[3];                int channels[3];//only 1 channel used here        public:                Histogram()                {                        //Prepare arguments for 1D histogram                        histSize[0] = 256;histSize[1] = 256;histSize[2] = 256;                        hranges[0] = 0.0;                        hranges[1] = 255.0;                        ranges[0] = hranges;ranges[1] =hranges;                        ranges[2] =hranges;                        channels[0] = 0;channels[1] = 1;channels[2] = 2;                }                cv::MatND getHistogram(const cv::Mat &image)                {                        cv::MatND hist;                        //Compute histogram                        cv::calcHist(&image,                                        1,                                        channels,                                        cv::Mat(),                                        hist,                                        3,                                        histSize,                                        ranges                                        );                     return hist;                }

但是在3通道的直方图计算过程中,有可能会觉得计算量过大了,同样可以使用稀疏矩阵(sparse matrix),calcHist同样支持

cv::SparseMat getSparseHistogram(const cv::Mat &image)                {                        cv::SparseMat hist(3,histSize,CV_32F);                        //Compute histogram                        cv::calcHist(&image,                                        1,                                        channels,                                        cv::Mat(),                                        hist,                                        3,                                        histSize,                                        ranges                                        );                     return hist;                }

接下来一段时间,就要回归水鱼的比赛了,OpenCV就要放一放

打算晚上写一下北大提供的PoseToPose函数的分析指导,由于自己的学识有限,很难分析全面,真的希望有人可以来指正我的错误~

                                                                                                                                             张巍骞

2012-4-10

原创粉丝点击