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

要绘制直方图,最重要的三个函数是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

时间: 2024-11-12 16:39:22

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

如何利用openCV做灰度图片

将彩色图片变成灰度图片的两种方式: 1.使用openCV 2.使用IOS系统自带的开发库实现 3.实现架构布局(设计模式:策略模式) 第一:使用openCV 1.下载openCV框架:http://opencv.org/ 2.导入项目 3.创建渲染灰度图片类: #import "ImageUtils.h" //第一步导入OpenCV 头文件 #import <opencv2/opencv.hpp> #import <opencv2/imgcodecs/ios.h>

【数字图像处理】四.MFC对话框绘制灰度直方图

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行回忆讲解,主要通过MFC单文档视图实现点击弹出对话框绘制BMP图片的灰度直方图,再获取平均灰度.中指灰度和标准差等值.文章比较详细基础,希望该篇文章对你有所帮助~ [数字图像处理]一.MFC详解显示BMP格式图片 [数字图像处理]二.MFC单文档分割窗口显示图片 [数字图像处理]三.MFC实现图像灰度.采样和量化功能详解 免费资源下载地址: http://download.csdn.ne

利用opencv中的级联分类器进行人脸检测-opencv学习(1)

OpenCV支持的目标检测的方法是利用样本的Haar特征进行的分类器训练,得到的级联boosted分类器(Cascade Classification).注意,新版本的C++接口除了Haar特征以外也可以使用LBP特征. 先介绍一下相关的结构,级联分类器的计算特征值的基础类FeatureEvaluator,功能包括读操作read.复制clone.获得特征类型getFeatureType,分配图片分配窗口的操作setImage.setWindow,计算有序特征calcOrd,计算绝对特征calcC

数字图像处理作业使用OpenCV - 自定义直方图

第二次作业需要打印出来灰度直方图,当然不能使用ocv的自带calcHist函数来得到Mat对象了……结果上网搜索怎么用自己的数据创建直方图,搜到的都是直接用函数的_(:з」∠)_ 结果这个地方拖了好久呵呵呵呵呵呵呵.最后还是努力耐下性子来对照网上绘制灰度直方图的代码来看到底内藏什么玄机,结果发现其实真的,没什么,大不了(笑)(哭). 基本思路: 建立一个Mat对象作为直方图的画布,将256个灰度级的数值的直方用rectangle或者line一个一个画出来. ……简直简单到我无法想象_(:з」∠)

利用opencv源代码和vs编程序训练分类器haartraining.cpp

如需转载请注明本博网址:http://blog.csdn.net/ding977921830/article/details/47733363. 一  训练框架 训练人脸检測分类器须要三个步骤: (1) 准备正负样本集,分别放到两个目录里. 我使用的是麻省理工的那个人脸库.大家能够网上搜一下. (2)把正样本集生成正样本描写叙述文件(*.vec),把负样本集生成负样本集合文件.详细怎么操作请參考我博客中的另外两篇文章,各自是http://blog.csdn.net/ding977921830/a

DirectX学习笔记(四):利用D3DX网格数据结构绘制可旋转茶壶

前言: 在上篇文章(DirectX学习笔记三)中,我详细的说明了如何利用线框模式绘制可旋转的正方体.链接:点击打开链接.但是应该看到的是,如果我们通过创建三角形单元来创建3D物体是十分繁琐的事情.幸运的是,在D3DX库中提供了一些用于生成简单3D物体的网格数据方法. 如:利用网格数据创建一个茶壶: 1. 我们需要使用ID3DXMesh网格数据结构接口来创建我们的茶壶网格数据,这时我们需要使用此函数: HRESULT D3DXCreateTeapot(LPDIRECT3DDEVICE9 pDevi

根据MATLAB的histeq函数改写的运行在OpenCV下的直方图规定化C源码!

据说,图像的直方图规定化比直方图均衡化用得更多,但是很奇怪的是OpenCV居然没有图像直方图规定化的源码!所以,我就有必要在OpenCV下写一个图像直方图规定化处理的函数,以方便将来使用. 我在网上找了几个直方图均稀化的源码,并基于OpenCV来改写这些源码,效果都不如MATLAB的histeq函数,这其中改写的艰辛与繁琐就不细说了.最后,没办法,只好学习MATALB的histeq函数源码,并对其进行基于OpenCV的改写. 虽然我最终改写成功了,但是对算法还是不太理解,只能按照MATLAB的帮

利用OpenCV霍夫变换检测出圆

利用OpenCV进行霍夫变换检测出圆形,并提取圆心坐标和半径. 程序很简单,看看就懂了. #include <opencv2/opencv.hpp> using namespace cv; using namespace std; const int kvalue = 15;//双边滤波邻域大小 int main() { Mat src_color = imread("1.png");//读取原彩色图 imshow("原图-彩色", src_color)

#利用openCV裁脸

#利用openCV裁脸 import cv2 def draw_rects(img, rects): for x, y, w, h in rects: cv2.rectangle(img, (x, y), (x+w, y+h), (255, 255, 00), 2) cv2.circle(img, (x, y), 1, (0, 0, 255), 10) print(img.shape) imgs = img[y :y + h , x :x + w ] print(imgs.shape) cv2.