码迷,mamicode.com
首页 > 其他好文 > 详细

利用OpenCV的calcHist绘制灰度直方图、H-S直方图、BGR直方图和自定义直方图的源码及说明

时间:2016-06-12 03:15:36      阅读:4685      评论:0      收藏:0      [点我收藏+]

标签:

要绘制直方图,最重要的三个函数是calcHist、line、和rectangle,下面分别进行介绍

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 );

点此查看calcHist函数的官方解释!

const Mat* images:待计算直方图的图像源的指针,注意是指针,因为有可能包含多幅图

 int nimage:表示待计算图像源中图像的个数,一般情况下都取值为1,就算你要计算多幅,也可以一个个地算啊!如果是多幅,那么说明 images是一个数组撒!

const int* channels:表示要计算哪些通道的指针,注意是指针,因为通道数可能是多个。灰度图为0,HSV的H-S直方图为0和1,BGR为0,1,2(不过BGR图可以使用split分离三个通道,再分别计算,通常也是这样处理)

InputArray mask:掩码阵列,关于这个参数可以参看我写的博文http://blog.csdn.net/wenhao_ir/article/details/51120508

OutputArray hist:存储计算出的直方图数据

int dims:直方图的维度,单通道为1,H-S直方图为2,一维的就是一条线,二维的就是一个平面(即包含x,y两个维度)

const int* histSize:表示直方图横坐标的区间数的指针,注意也是指针,因为对于二维的直方图而言,有两个维度的变量区间

const float** ranges:表示直方图每一维变量的上下界,注意是指针的指针,因为每一维度的区间都是两个边界值,又有可能是多维,如果不明白我说的话,看H-S直方图源码就清楚了

bool uniform=true:表示直方图是否均匀的标志,什么叫是否均匀?我这里就不翻译译官方的文档的注释了。我就说下自己的理解。要理解这个,首先要知道histSize的含义,histSize就明表示咱们这个直方图的横坐标被划分为多少个区间。如果是均匀的,那么从下界到上界之间就被均匀划分为这么多个区间,如果是非均匀,就需要在ranges中给出各个区间的起点和终点,显然histSize个区间需要histSize+1个点。这里我要说明一下在均匀的情况下如果ranges中写了多个区间程序是怎么操作的?比如自定义直方图程序中的histSize[1]={256}; float hranges[6]={0, 60, 120, 160, 220, 255};具体是这样操作的:把256个区间平分5个大区间中,即每个区间51.2个小区间,然后这些每个大区间再分别被划为51.2个小区间。就是这回事!

bool accumulate=false :这个参数表示如果你之前计算过这个直方图,那么这个直方图再次计算时一开始需不需要清零,显然,如果不清零,那么再次计算时是一种更新。

line函数

这个函数就是利用两点确定一条直线的原理绘线,原型如下:

CV_EXPORTS_W void line(CV_IN_OUT Mat& img, Point pt1, Point pt2, const Scalar& color,
                     int thickness=1, int lineType=8, int shift=0);

一看原型就什么都知道了,所以没必要多讲!

rectangle函数

rectangle的绘制过程可以参见博文:

另外有一点我需要特别强调一下 那就是用calcHist计算出来的255级灰度值总是0,关于这个问题,我专门写了篇博文,详见http://blog.csdn.net/wenhao_ir/article/details/51332416 如果以后你的程序中要用到255级灰度值,那么可以自己写一段程序计算255级的灰度值,这个程序实际上很容易完成,可以参考我写的博文http://blog.csdn.net/wenhao_ir/article/details/51332416

好,接下来上源码,明白了以上函数的使用之后,再来看这个源码就很容易了!所以我就不注释什么了~

源码中用到的图片的下载链接:http://pan.baidu.com/s/1kUEDw5x

首先是灰度直方图的源码

//OpenCV版本2.4.9  
//交流QQ2487872782 

#include <opencv2\opencv.hpp>  
int main()
{
    // 图像源获取及判断 
    cv::Mat Image, ImageGray;
    //Image = cv::imread("coins.png"); 
	Image = cv::imread("flower3.jpg"); 
    if(Image.empty()) 
      return -1;
    cv::imshow("Image",Image);
    // 转换为灰度图像
    cv::cvtColor(Image,ImageGray,CV_BGR2GRAY);
    // 定义直方图参数
    const int channels[1]={0};
    const int histSize[1]={256};
    float pranges[2]={0,255};
    const float* ranges[1]={pranges};
    cv::MatND hist;
    // 计算直方图
    cv::calcHist(&ImageGray,1,channels,cv::Mat(),hist,1,
    histSize,ranges);
    // 初始化画布参数
    int hist_w = 500; 
    int hist_h = 500;
    int nHistSize = 255;
    // 区间
    int bin_w = cvRound( (double) hist_w / nHistSize );
    cv::Mat histImage( hist_w, hist_h,
             CV_8UC3,   cv::Scalar( 0,0,0) );
	  // 将直方图归一化到范围 [ 0, histImage.rows ]
	  normalize(hist, hist, 0, histImage.rows, 
               cv::NORM_MINMAX,  -1, cv::Mat() );
	  // 在直方图画布上画出直方图
    for( int i = 1; i < nHistSize; i++ )//注意这里没有绘制255级的灰度值
    {
      cv::line( histImage, cv::Point(bin_w*(i-1),
             hist_h-cvRound(hist.at<float>(i-1)) ) ,
             cv::Point( bin_w*(i), 
             hist_h - cvRound(hist.at<float>(i)) ),
             cv::Scalar( 0, 0, 255), 2, 8, 0  );
    }
	
	int hist_255;
	hist_255=int(hist.at<float>(255));


    // 显示直方图
    cv::imshow("histImage", histImage);
    cv::waitKey();
    return 0;
}

其次是H-S直方图的源码

//OpenCV版本2.4.9  
//交流QQ2487872782 

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream> 
using namespace std;
using namespace cv;
int main()
{
    cv::Mat srcImage, hsvMat;
    srcImage = cv::imread("flower3.jpg");
    if(srcImage.empty()) 
       return -1;
    cv::cvtColor(srcImage, hsvMat, CV_BGR2HSV);
    // 初始化灰度阶参数
    int hbins = 30, sbins = 32;
    int histSize[] = {hbins, sbins};
    // 灰度变化范围设置
    float hranges[] = { 0, 180 };
    // 饱和度变化范围
    float sranges[] = { 0, 256 };
    const float* ranges[] = { hranges, sranges };
    cv::MatND hist;
    // 选取计算直方图通道
    int channels[] = {0, 1};
    // 计算当前通道直方图
    cv::calcHist( &hsvMat, 1, channels, cv::Mat(), 
             hist, 2, histSize, ranges,
             true, false );
    double maxVal=0;
    // 找到直方图的最大值
    cv::minMaxLoc(hist, 0, &maxVal, 0, 0);
    int scale = 10;
    cv::Mat histImg = cv::Mat::zeros(sbins*scale, 
             hbins*10,CV_8UC3);
    // 遍历hs通道
    for( int h = 0; h < hbins; h++ )
    {
        for( int s = 0; s < sbins; s++ )
        {
            float binVal = hist.at<float>(h, s);
            // 根据最大值计算变换范围
            int intensity = cvRound(binVal*255/maxVal);
            // 绘图显示
            cv::rectangle( histImg, 
                             cv::Point(h*scale, s*scale),
                             cv::Point( (h+1)*scale - 1, 
                             (s+1)*scale - 1),
                             cv::Scalar::all(intensity),
                             CV_FILLED );
        }
    }
    cv::imshow( "Source", srcImage);
    cv::imshow( "H-S Histogram", histImg);
    cv::waitKey();
}

再次是BGR直方图

//OpenCV版本2.4.9  
//交流QQ2487872782 

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream> 
using namespace std;
using namespace cv;
int main()
{
  // 图像获取及判断
  cv::Mat srcImage = cv::imread("flower3.jpg");
  if( !srcImage.data ) 
  	 return 1;
  cv::imshow("srcImage",srcImage);  
  // 分离图像的三个通道 B  G R
  std::vector<cv::Mat> bgr_planes;
  split( srcImage, bgr_planes );
  // 初始化直方图计算参数
  int histSize = 256; 
  float range[] = { 0, 256 }; 
  const float* histRange = { range }; 
  bool uniform = true; 
  bool accumulate = false;
  cv::Mat b_hist, g_hist, r_hist;
  // 计算各个通道的直方图
  calcHist( &bgr_planes[0], 1, 0, cv::Mat(), b_hist, 1, 
  	&histSize, &histRange, uniform, accumulate );
  calcHist( &bgr_planes[1], 1, 0, cv::Mat(), g_hist, 1, 
  	&histSize, &histRange, uniform, accumulate );
  calcHist( &bgr_planes[2], 1, 0, cv::Mat(),r_hist, 1, 
  	&histSize, &histRange, uniform, accumulate );
  // 设置直方图绘图参数
  int hist_w = 640; int hist_h = 512;
  int bin_w = cvRound( (double) hist_w/histSize );
    cv::Mat histImage( hist_h, hist_w, 
                      CV_8UC3, cv::Scalar( 0,0,0) );
  // 分别归一化直方图到[ 0, histImage.rows ]
  normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, 
             -1, Mat() );
  normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, 
             -1, Mat() );
  normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, 
             -1, Mat() );
  // 分别对每个通道进行绘图
  for( int i = 1; i < histSize; i++ )
  {
    line( histImage, Point( bin_w*(i-1), 
           hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
           Point( bin_w*(i), hist_h - 
           cvRound(b_hist.at<float>(i)) ),
           Scalar( 255, 0, 0), 2, 8, 0  );
    line( histImage, Point( bin_w*(i-1), hist_h - 
           cvRound(g_hist.at<float>(i-1)) ) ,
           Point( bin_w*(i), hist_h - 
           cvRound(g_hist.at<float>(i)) ),
                   Scalar( 0, 255, 0), 2, 8, 0  );
    line( histImage, Point( bin_w*(i-1), hist_h - 
           cvRound(r_hist.at<float>(i-1)) ) ,
           Point( bin_w*(i), hist_h - 
           cvRound(r_hist.at<float>(i)) ),
           Scalar( 0, 0, 255), 2, 8, 0  );
  }
  imshow("calcHist", histImage );
  waitKey(0);
  return 0;
}

最后是自定义直方图

//OpenCV版本2.4.9  
//交流QQ2487872782 

#include <opencv2/opencv.hpp>
int main()
{
	// 图像获取及判断
    cv::Mat srcImage = cv::imread("flower3.jpg");
    if( !srcImage.data ) 
      return 1;
    cv::imshow("srcImage",srcImage);
    // 灰度转换  
    cv::Mat srcGray;
    cv::cvtColor(srcImage,srcGray,CV_BGR2GRAY);
    // 初始化直方图计算参数
    const int channels[1]={0};
    const int histSize[1]={256};
    // 设定区间[0 60],[61 120],[121 160],[161 220],[221 255]
    float hranges[6]={0, 60, 120, 160, 220, 255};
    const float* ranges[1] = {hranges};
    cv::MatND hist;
    // 计算直方图
    cv::calcHist( &srcGray, 1, 
    	          channels, cv::Mat(),
    	          hist, 1, histSize, 
    	          ranges );
    // 求直方图中最大值
    double maxHist=0;
    cv::minMaxLoc(hist, 0, &maxHist, 0 ,0);
    // 设置直方图绘图参数
    int hist_Size = hist.rows;
    cv::Mat histImg(hist_Size, hist_Size, 
                      CV_8U, cv::Scalar(255));
    // 直方图绘制
    for(int h = 0; h < hist_Size; h++)
    {
        float binVal = hist.at<float>(h);
        //归一化 根据最大值计算变换范围 
        int intensity = static_cast<int>(binVal * 
            hist_Size / maxHist);
        // 绘图直方图信息
        //cv::line(histImg, cv::Point(h, hist_Size), 
        //	     cv::Point(h, hist_Size - intensity),
        //	     cv::Scalar::all(0));

        cv::line(histImg, cv::Point(h, hist_Size), 
        	     cv::Point(h, hist_Size - intensity),
        	     cv::Scalar::all(0));
    }
    cv::imshow("histImg", histImg);
    cv::waitKey(0);
    return 0;
}

运行结果依次如下图所示:

技术分享

技术分享

技术分享

技术分享

-------------------------------------------
欢迎大家加入图像识别技术交流群:271891601,另外,特别欢迎成都从事图像识别工作的朋友交流,我的QQ号2487872782

利用OpenCV的calcHist绘制灰度直方图、H-S直方图、BGR直方图和自定义直方图的源码及说明

标签:

原文地址:http://blog.csdn.net/wenhao_ir/article/details/51580625

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!