《OpenCV3编程入门》学习笔记9 直方图与匹配(一&二) 图像直方图概述&直方图的计算与绘制

第9章 直方图与匹配

9.1 图像直方图(Histogram)概述

1.作用:
  在每个兴趣点设置一个有相近特征的直方图所构成的标签,通过标记帧与帧之间显著的边缘、颜色、角度等特征的统计变化,来检测视频中场景的变化。
2.概念:
  图像直方图是图像中像素强度分布的图形表达方式,统计了每一个强度值所具有的像素个数,并将统计结果分布于一系列预定义的bins中。直方图中,横坐标的左侧为纯黑较暗区域,右侧为纯白较亮区域。
3.术语:
(1)dims:需要统计的特征数目
(2)bins:每个特征空间子区段的数目,称为“直条”或“组距”
(3)Range:每个特征空间的取值范围
4.例如:
  假设一个矩阵包含一张图像的信息(灰度值0-255),已知数字范围包含256个值,将范围分成子区域(bins),然后统计每个bin的像素数目,如:
                在这里插入图片描述

9.2 直方图的计算与绘制

9.2.1 计算直方图:calcHist()函数

1.作用:
  计算一个或多个阵列的直方图
2.函数原型:

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

3.参数说明:
(1)输入数组(集)
(2)输入数组个数
(3)需要统计的通道(dim)索引,第一个数组通道从0到images[0].channels()-1,第二个数组通道从images[0].channels()计算到images[0].channels()+images[1].channels()-1。
(4)可选的操作掩码,为空或与images[i]同样大小的8位数组,非零掩码元素用于标记出统计直方图的数组元素数据。
(5)输出的目标直方图,二维数组
(6)需要计算的直方图维度,必须是正数且不大于CV_MAX_DIMS
(7)存放每个维度的直方图尺寸的数组
(8)表示每一个维度数组的每一维的边界阵列,即每一位数组的取值范围
(9)指示直方图是否均匀的标识符,默认true
(10)累计标识符,默认值false,为true时直方图在配置阶段不会被清零,主要是允许从多个阵列中计算单个直方图,或用于在特定时间更新直方图。

9.2.2 寻找最值:minMaxLoc()函数

1.作用:
  在数组中找到全局最小/大值
2.函数原型:

void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())

3.参数说明:
(1)输入的单通道阵列
(2)返回最小值的指针,若无需返回则置为NULL
(3)返回最大值的指针,若无需返回则置为NULL
(4)返回最小位置的指针,若无需返回则置为NULL
(5)返回最大位置的指针,若无需返回则置为NULL
(6)用于选择子阵列的可选掩模

9.2.3 示例程序

1.绘制H-S二维直方图

/*
程序说明:计算彩色图像的色调(Hue)-饱和度(Saturation)二维直方图
*/
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;

int main()
{
	//【1】载入原图,转化为HSV颜色模型
	Mat srcImage, hsvImage;
	srcImage = imread("1.jpg");
	cvtColor(srcImage, hsvImage, COLOR_RGB2HSV);
	
	//【2】参数准备
	//定义存储直方图的数据结构(单通道阵列)
	MatND dstHist;
	//将色调量化为30个等级,将饱和度量化为32个等级
	int hueBinNum = 30;//色调直方图直条数量
	int saturationBinNum = 32;//饱和度直方图直条数量
	int histSize[] = { hueBinNum,saturationBinNum };
	//定义变化范围
	float hueRanges[] = { 0,180 };//定义色调的变化范围为0-179
	float saturationRanges[] = { 0,256 };//定义饱和度的变化范围为0-255
	const float* ranges[] = { hueRanges,saturationRanges };
	//calcHist函数中将计算第0通道和第1通道的直方图
	int channels[] = { 0,1 };

	//【3】正式调用calcHist,进行直方图计算
	//输入数组,数组个数为1,通道索引,不使用掩模,输出目标直方图,需要计算的直方图维度为2,存放每个维度的直方图尺寸的数组,每一维数组的取值范围数组,指示直方图均匀,直方图在配置阶段会被清零
	calcHist(&hsvImage, 1, channels, Mat(), dstHist, 2, histSize, ranges, true, false);

	//【4】绘制直方图准备参数
	double maxValue = 0;//最大值
	minMaxLoc(dstHist, 0, &maxValue, 0, 0);//查找数组和子数组的全局最大值存入maxValue中
	int scale = 10;
	Mat histImage = Mat::zeros(saturationBinNum*scale, hueBinNum * 10, CV_8UC3);

	//【5】双层循环,进行直方图绘制
	for (int hue = 0; hue < hueBinNum; hue++)
	{
		for (int saturation = 0; saturation < saturationBinNum; saturation++)
		{
			float binValue = dstHist.at<float>(hue, saturation);//直方图直条的值
			int intensity = cvRound(binValue * 255 / maxValue);//强度
			//正式绘制
			rectangle(histImage, Point(hue*scale, saturation*scale), Point((hue + 1)*scale - 1, (saturation+1)*scale - 1), Scalar::all(intensity), FILLED);
		}	
	}
	//【6】显示效果图
	imshow("素材图", srcImage);
	imshow("H-S直方图", histImage);

	waitKey(0);
	return 0;
}

运行效果:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

2.计算并绘制图像一维直方图

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;

int main()
{
	//【1】载入原灰度图并显示
	Mat srcImage = imread("1.jpg", 0);
	if (!srcImage.data)
	{
		printf("载入原图失败~!\n");
		return  false;
	}
	imshow("【原始图】", srcImage);

	//【2】定义变量
	MatND dstHist;
	int dims = 1;
	float hranges[] = { 0,255 };
	const float *ranges[] = { hranges };
	int size = 256;
	int channels = 0;

	//【3】计算图像的直方图
	calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges, true, false);
	int scale = 1;
	Mat dstImage(size*scale, size, CV_8U, Scalar(0));

	//【4】获取最大值和最小值
	double minValue = 0;
	double maxValue = 0;
	minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);

	//【5】绘制出直方图
	int hpt = saturate_cast<int>(0.9*size);
	for (int i = 0; i < 256; i++)
	{
		float binValue = dstHist.at<float>(i);
		int realValue = saturate_cast<int>(binValue*hpt / maxValue);
		rectangle(dstImage, Point(i*scale, size - 1), Point((i + 1)*scale - 1, size - realValue), Scalar(255));
	}
	imshow("一维直方图", dstImage);

	waitKey(0);
	return 0;
}

运行效果:
在这里插入图片描述在这里插入图片描述

3.绘制RGB三色直方图

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;

int main()
{
	//【1】载入原图并显示
	Mat srcImage = imread("love.jpg");
	imshow("【原始图】", srcImage);
	//【2】初始化直方图计算参数
	int bins = 256;
	int hist_size[] = { bins };
	float range[] = { 0,256 };
	const float* ranges[] = { range };
	MatND redHist, grayHist, blueHist;
	
	//【3】进行直方图计算(红色分量部分)
	int channels_r[] = { 0 };
	calcHist(&srcImage, 1, channels_r, Mat(), redHist, 1, hist_size, ranges, true, false);

	//【4】进行直方图计算(绿色分量部分)
	int channels_g[] = { 1 };
	calcHist(&srcImage, 1, channels_g, Mat(), grayHist, 1, hist_size, ranges, true, false);

	//【5】进行直方图计算(蓝色分量部分)
	int channels_b[] = { 2 };
	calcHist(&srcImage, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges, true, false);

	//绘制三色直方图
	//参数准备
	double maxValue_red, maxValue_green, maxValue_blue;
	minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
	minMaxLoc(grayHist, 0, &maxValue_green, 0, 0);
	minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
	
	int scale = 1;
	int histHeight = 256;
	Mat histImage = Mat::zeros(histHeight, bins * 3, CV_8UC3);

	//正式绘制
	for (int i = 0; i < bins; i++)
	{
		//参数准备
		float binValue_red = redHist.at<float>(i);
		float binValue_green = grayHist.at<float>(i);
		float binValue_blue = blueHist.at<float>(i);
		int intensity_red = cvRound(binValue_red*histHeight / maxValue_red);//要绘制的高度
		int intensity_green = cvRound(binValue_green*histHeight / maxValue_green);//要绘制的高度
		int intensity_blue = cvRound(binValue_blue*histHeight / maxValue_blue);//要绘制的高度
		
		//绘制红色分量的直方图
		rectangle(histImage, Point(i*scale, histHeight - 1), Point((i + 1)*scale - 1, histHeight - intensity_red), Scalar(255, 0, 0));
		//绘制绿色分量的直方图
		rectangle(histImage, Point((i + bins)*scale, histHeight - 1), Point((i + bins + 1)*scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
		//绘制蓝色分量的直方图
		rectangle(histImage, Point((i + bins * 2)*scale, histHeight - 1), Point((i + bins * 2 + 1)*scale - 1, histHeight - intensity_blue), Scalar(0, 0, 255));
	}
	//显示直方图
	imshow("图像的RGB直方图", histImage);

	waitKey(0);
	return 0;
}

运行效果:
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ccchenxi/article/details/85871666