opencv2—(7)计算图像的直方图

一个图像有不同的像素值构成,像素值在图像中的分布情况是这幅图片的一重要特征。直方图可以描述图像内容、检测图像中的特定对象或纹理,你将学习如何计算直方图来修改图像外观。opencv提供了 cv::calcHist这个函数,可以计算任意类型的多通道图像。下面我们先定义一个类 class Histogram1D,成员变量
private:
       float m_hranges[2];//像素的最小及最大值 0.0 255.0

       int m_histSize[1];//项的数目 256
       const float*m_ranges[1];//像素的最大最小数组指针
       int channels[1];//仅用到一个通道 通道0

然后在构造函数中初始化:
public:
       Histogram1D()
       {
              //准备1D 直方图的参数
              m_hranges[0] = 0.0;
              m_hranges[1] = 255.0;
             
              m_histSize[0] = 256;
              m_ranges[0] = m_hranges;
              channels[0] = 0;
       };

然后计算直方图:
//计算1D直方图
       cv:: MatND getHistogram(const cv::Mat &image)
       {
              cv::MatND hist;
              //计算直方图
               cv::calcHist(&image, //图片
                     1,               //计算单张图片的直方图
                     channels,        //通道数量
                     cv::Mat(),       //不使用图像作为掩码
                     hist,            //返回的直方图
                     1,               //这是1D的直方图
                     m_histSize,      //项的数量
                     m_ranges         //像素值的范围
              );
              return hist;
       };
    

接着你可以遍历 hist 的256个条目,它是一个一维数组
for (int i = 0; i < 256; i++)
              //遍历这256个值对应的像素点个数
              cout << "value" << i << "=" << histo.at<float>(i) << endl;

为了更直观的把数值显示出来,更方便的方式是将直方图可视化,我们在类  class Histogram1D 添加 getHistogramImage() 方法,计算1D的直方图,并返回柱状图。
//计算1D直方图,并返回一张图像
       cv::Mat getHistogramImage(const cv::Mat & image)
       {
              //首先计算直方图
              cv::MatND hist = getHistogram(image);
              //获取最大值和最小值
              double maxVal = 0;
              double minVal = 0;
              cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);

              cv::Mat histImg(m_histSize[0], m_histSize[0], CV_8U, cv::Scalar(255));
              int hpt = static_cast<int>(0.9*m_histSize[0]);
              //每个条目都绘制一条垂直线
              for (int h = 0; h < m_histSize[0]; h++)
              {
                     float binVal = hist.at<float>(h);
                     int intensity = static_cast<int>(binVal*hpt / maxVal);
                     //两点之间绘制一条直线
                     cv::line(histImg, cv::Point(h, m_histSize[0]), //底部点
                           cv::Point(h, m_histSize[0] - intensity),//顶部点
                           cv::Scalar::all(0));//黑色
              }
              return histImg;
       };


相似的,我们可以定义一个类来计算彩色的 BGR 图像的直方图:
class Colorhistogram
{
private :
        int m_histSize[3]; //项的数目
        float m_hranges[2]; //像素的最小及最大值
        const float *m_ranges[3];
        int m_channels[3];
public :
       Colorhistogram()
       {
              m_histSize[0] = m_histSize[1] = m_histSize[2] = 256;
              m_hranges[0] = 0.0;
              m_hranges[1] = 255.0;
              m_ranges[0] = m_hranges;
              m_ranges[1] = m_hranges;
              m_ranges[2] = m_hranges;
              m_channels[0] = 0;
              m_channels[1] = 0;
              m_channels[2] = 0;
       };
       cv:: MatND getHistogram( const cv:: Mat & image )
       {
              cv:: MatND hist;
               // BGR color histogram
              m_hranges[0] = 0.0;    // BRG range
              m_hranges[1] = 255.0;
              m_channels[0] = 0;          // the three channels
              m_channels[1] = 1;
              m_channels[2] = 2;
               // Compute histogram
              cv::calcHist(& image ,
                     1,                    // histogram of 1 image only
                     m_channels,    // the channel used
                     cv:: Mat (),     // no mask is used
                     hist,          // the resulting histogram
                     3,                    // it is a 3D histogram
                     m_histSize,    // number of bins
                     m_ranges              // pixel value range
              );
               return hist;
       }
        // Computes the histogram.
       cv:: SparseMat getSparseHistogram( const cv:: Mat & image ) {
              cv:: SparseMat hist(3, m_histSize, CV_32F );
               // BGR color histogram
              m_hranges[0] = 0.0;    // BRG range
              m_hranges[1] = 255.0;
              m_channels[0] = 0;          // the three channels
              m_channels[1] = 1;
              m_channels[2] = 2;
               // Compute histogram
              cv::calcHist(& image ,
                     1,                    // histogram of 1 image only
                     m_channels,    // the channel used
                     cv:: Mat (),     // no mask is used
                     hist,          // the resulting histogram
                     3,                    // it is a 3D histogram
                     m_histSize,    // number of bins
                     m_ranges              // pixel value range
              );
               return hist;
       }
        // Computes the 2D ab histogram.
        // BGR source image is converted to Lab
       cv:: MatND getabHistogram( const cv:: Mat & image ) {
              cv:: MatND hist;
               // Convert to Lab color space
              cv:: Mat lab;
              cv::cvtColor( image , lab, CV_BGR2Lab );
               // Prepare arguments for a 2D color histogram
              m_hranges[0] = -128.0;
              m_hranges[1] = 127.0;
              m_channels[0] = 1; // the two channels used are ab
              m_channels[1] = 2;
               // Compute histogram
               return hist;
       }
        // Computes the 1D Hue histogram with a mask.
        // BGR source image is converted to HSV
       cv:: MatND getHueHistogram( const cv:: Mat & image ) {
              cv:: MatND hist;
               // Convert to Lab color space
              cv:: Mat hue;
              cv::cvtColor( image , hue, CV_BGR2HSV );
               // Prepare arguments for a 1D hue histogram
              m_hranges[0] = 0.0;
              m_hranges[1] = 180.0;
              m_channels[0] = 0; // the hue channel
                                          // Compute histogram
              cv::calcHist(&hue,
                     1,                    // histogram of 1 image only
                     m_channels,    // the channel used
                     cv:: Mat (),     // no mask is used
                     hist,          // the resulting histogram
                     1,                    // it is a 1D histogram
                     m_histSize,    // number of bins
                     m_ranges              // pixel value range
              );
               return hist;
       }
       cv:: Mat colorReduce( const cv:: Mat & image , int div = 64) {
               int n = static_cast < int >(log( static_cast < double >( div )) / log(2.0));
               // mask used to round the pixel value
               uchar mask = 0xFF << n; // e.g. for div=16, mask= 0xF0
              cv:: Mat_ <cv:: Vec3b >:: const_iterator it = image .begin<cv:: Vec3b >();
              cv:: Mat_ <cv:: Vec3b >:: const_iterator itend = image .end<cv:: Vec3b >();
               // Set output image (always 1-channel)
              cv:: Mat result( image .rows, image .cols, image .type());
              cv:: Mat_ <cv:: Vec3b >:: iterator itr = result.begin<cv:: Vec3b >();
               for (; it != itend; ++ it, ++ itr) {
                     ( * itr) [ 0 ] = (( * it) [ 0 ] & mask) + div / 2;
                     ( * itr) [ 1 ] = (( * it) [ 1 ] & mask) + div / 2;
                     ( * itr) [ 2 ] = (( * it) [ 2 ] & mask) + div / 2;
              }
               return result;
       }
};

猜你喜欢

转载自blog.csdn.net/sinat_27614619/article/details/56667234