【C++的OpenCV】第十一课-OpenCV图像常用操作(八):直方图计算(cv.calc())

欢迎各位来到小白 p i a o 的学习空间! \color{red}{欢迎各位来到小白piao的学习空间!} 欢迎各位来到小白piao的学习空间!
持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!
目前已经为大家更新了: \color{green}{目前已经为大家更新了:} 目前已经为大家更新了:

  1. Python基础、中级、高级;
  2. C++数据结构和算法;
  3. OpenCV相关内容等重点内容

我的主页: \color{purple}{我的主页:} 我的主页:我的主页

目录

  • 前言
  • 一、图像直方图的计算
    • 1.1 cv.calcHist()函数
    • 1.2 实例代码
    • 1.3 结果

前言

        上一章内容中,为大家简单介绍了图像直方图,和直方图均衡化的目的和相关的案例源码,本章节我们将继续深化这部分内容,因为这部分内容也是一个比较有意思的内容。本章内容主要围绕cv.calcHist()的使用方法展开,为大家详细介绍它的用法,注重实际使用!请认真看看哈。


前文链接:【C++的OpenCV】第十课-OpenCV图像常用操作(七):直方图和直方图同等化(直方图均衡化)


一、图像直方图的计算

1.1 cv.calcHist()函数

  • 函数原型:原文链接
  • 原型一:
void cv::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_16U或CV_32F以及相同的大
	小。它们中的每一个都可以具有任意数量的通道。
nimages:这个图像阵列中,图像的个数
channels:用于计算直方图中的每个维度的每个通道的列表,需要统计的图像的通道集合(是一个整型数组,且数组值不可变)。
mask:掩膜,如果掩膜非空,
	那么这个掩膜必须是和源图像阵列中的图像同样大小的8位图像数组。
hist:存放经过直方图计算后的图像
dims:直方图的维度,直方图维度必须为正且不大于CV_MAX_DIMS(在当前OpenCV版本中等于32)
histSize:每个维度上直方图的尺寸大小
ranges:每个维度上直方图二进制边界的维度数组的数组,是一个二位数组。当直方图是均匀的(uniform=true)时,对于每个维度,只需指定第0个直方图的下(含)边界和最后一个直方图的上(不含)边界即可,即,在均匀直方图的情况下,每个范围是2个元素的阵列。当直方图不一致(uniform=false)时,则每个范围i中包含histSize[i]+1个元素:L0,U0=L1,U1=L2,....... ,UhistSize[i]−2=LhistSize[i]−1,UhistSize[i]−1。不在L0和UhistSize[i]−1之间的数组元素不计入直方图中。
uniform:直方图是否进行归一化处理,true为是,false为否
accumulate:累计,是否累计,如果已设置,则分配直方图时不会在开始时清除直方图。此功能使您能够从多组数组中计算单个直方图,或及时更新直方图。
*/

  • 原型二:

void cv::calcHist	(	
						const Mat * 	images,
						int 	nimages,
						const int * 	channels,
						InputArray 	mask,
						SparseMat & 	hist,
						int 	dims,
						const int * 	histSize,
						const float ** 	ranges,
						bool 	uniform = true,
						bool 	accumulate = false 
					)	
/*
参数解释:
hist : 只有这个参数的类型与第一种原型不同,故解释一下:只是说以SparseMat类型的图像作为直方图输出的结果。
*/

  • 原型三:

void cv::calcHist	(	
						InputArrayOfArrays 	images,
						const std::vector< int > & 	channels,
						InputArray 	mask,
						OutputArray 	hist,
						const std::vector< int > & 	histSize,
						const std::vector< float > & 	ranges,
						bool 	accumulate = false 
					)	
/*
参数解释:
这个里边的 channels、histSize、ranges都存放在了vector容器当中而已。
但是需要注意的是,这个函数仅仅可以被用于归一化处理的直方图的计算。
range参数要么是空向量,要么是histSize.size()*2个元素(histSize.shize()元素对)的展平向量。每对的第一和第二元素指定下边界和上边界。
*/

1.2 实例代码

//实例一:
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include 

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
  Mat src, dst;
  String imageName( "/home/aelx-chen/demo.jpg" ); //指定一个图片路径
  src = imread( imageName ); // 读取这个路径下的图片放在这个src容器当中
  if( src.empty() ) //图片判空
    { return -1; }
  vector<Mat> bgr_planes; // 创建装源图像的图像容器vector
  split( src, bgr_planes );//将这个图像在RGB三个通道分别分离出来。记得到三个通道的三张图片存放在bgr_planes中
  int histSize = 256; //设置直方图大小
  float range[] = { 0, 256 } ; // 指定饱和度范围在0~255中。
  const float* histRange = { range };
  bool uniform = true; bool accumulate = false;
  Mat b_hist, g_hist, r_hist;
  calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
  calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
  calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate ); 
  //上边是计算三个通道三张图片的直方图。
  //下边是画出这三条折线图(过点划线),当然你也可以使用rectangle去绘制条形图。当然如果是Python,则可以借助三方库matlab中的方法直接完成绘图。
  int hist_w = 512; int hist_h = 400; //直方图宽和高
  int bin_w = cvRound( (double) hist_w/histSize );//得到二进制边界为直方图宽度除以直方图大小之后的结果转换为双精度浮点数之后再取最近的整数得到额结果。
  Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) ); 
//利用Mat的重写的构造函数构造一个histImage图像对象
//用于存储均质化(规范化一个数组的标准范围或者数组中元素值的范围)的结果。
//这个图像的大小和直方图一样大。
  //标准化处理:
  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  );
  }
  namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
  imshow("calcHist Demo", histImage );
  imshow("src", src);
  waitKey(0);
  return 0;

1.3 结果

【C++的OpenCV】第十一课-OpenCV图像常用操作(八):直方图计算(cv.calc())_第1张图片


你可能感兴趣的:(openCV,opencv,c++,计算机视觉)