赞
踩
常言道“温故而知新”,写此文章就是对自己目前学习内容的小小的总结与记录。
本文力求用最简洁的语言,详细的代码将此部分内容讲解清楚,但由于博主同样是刚刚接触OpenCV,或许表达上有些瑕疵,还望读者能够指教探讨,大家共同进步。
博主机器配置为:VS2013+opencv2.4.13+Win-64bit。
若本文能给读者带来一点点启示与帮助,我就很开心了。
====================分割线====================
本节以HSV空间的H-S的二维联合直方图为例。需要说明的是,二维直方图并不是一个通道一个通道的分别独立平行计算,而是将两个通道的数据整合起来计算出的二维直方图。
前言:
直方图的定义
直方图(Histogram)又称柱状图、质量分布图,是一种统计报告图。直方图由一系列高度不等的纵向条纹或线段表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布情况。在图像处理上,直方图是图像信息统计的有力工具。其实也就是统计一幅图某个亮度像素数量。
第一个就是当我们面对图像的时候,我们面对的是抽象的矩阵,如下图,下面是0-255的灰度图像的表示,密密麻麻的。
那么我们做的直方图,其实就是对这些像素值的统计。例如:首先,我们需要把0-255分成 17 个 区域(bin),如下图所示:
我们对每个范围中的灰度值进行统计排序,做出如下的表格:
我们是以图像的灰度为例子说明这个直方图,当然直方图不仅仅用于灰度特种统计排序,还可以用于图像的梯度、方向等特征。
灰度直方图是灰度级的函数,描述图像中该灰度级的像素个数(或该灰度级像素出现的频率):其横坐标是灰度级,纵坐标表示图像中该灰度级出现的个数(频率)。
在以上的过程中,我们使用到一些重要的参数,理解这些参数帮助我们更好的使用API函数。
一维直方图的结构表示为:
再结合上面画的示意图,应该就很好理解了。
基本的概念其实很简答,想的时候要不要想复杂了,那么基本概念就到这里了。
===============分割线===============
================分割线==============
当然了,首先介绍的是计算直方图的函数了。
直方图计算: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 );
参数解释:
=====================间隔线======================
寻找最值:minMaxLoc()函数
功能:查找全局最小和最大数组元素并返回它们的值和它们的位置。
void minMaxLoc(InputArray src, CV_OUT double* minVal,
CV_OUT double* maxVal=0, CV_OUT Point* minLoc=0,
CV_OUT Point* maxLoc=0, InputArray mask=noArray());
参数解释
=====================间隔线======================
绘图方法详情请看官方文档: 基本绘图
=====================分割线=====================
//--------------------------------------------------------------
//功能:绘制H-S直方图(二维)
//--------------------------------------------------------------
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
//------------【1】读取源图像并转化为HSV颜色模型------------
Mat srcImage, hsvImage;
srcImage = imread("D:/OutPutResult/ImageTest/jianzhu6.jpg");
if (!srcImage.data)
{
cout << "读取图片错误,请重新输入正确路径!\n";
system("pause");
return -1;
}
cvtColor(srcImage, hsvImage, COLOR_BGR2HSV); //RGB颜色空间转换为HSV颜色空间
//------------【2】参数准备------------------------------------
//将灰度量化为30个等级,将饱和度量化为32个等级
int hueBinNum = 30; //灰度色调的直方图直条数量
int saturationBinNum = 32; //饱和度的直方图直条数量
int histSize[] = { hueBinNum, saturationBinNum };
//定义灰度的变化范围为0到179
float hueRanges[] = { 0, 180 };
//定义饱和度的变化范围为0(黑,白,灰)到255(纯光谱颜色)
float saturationRanges[] = { 0, 256 };
const float* ranges[] = { hueRanges, saturationRanges };
MatND dstHist;
//选取计算直方图通道。calcHist函数中将计算第0通道和第1通道的直方图
int channels[] = { 0, 1 };
//------------【3】正式calcHist,进行直方图计算------------
calcHist(&hsvImage, //输入的数组
1, //数组个数为1
channels, //通道索引
Mat(), //不使用掩膜
dstHist, //输出的目标直方图
2, //需要计算的直方图的维度为2
histSize, //存放每个维度的直方图尺寸的数组
ranges, //每一维数值的取值范围数组
true, //指示直方图是否均匀的标识符,true表示均匀的直方图
false); //累计标识符,false表示直方图在配置阶段会被清零
//------------【4】为绘制直方图准备参数------------------------------------
double maxValue = 0;
minMaxLoc(dstHist, 0, &maxValue, 0, 0); //查找到直方图的最大值
int scale = 10;
Mat histImg = Mat::zeros(saturationBinNum*scale, hueBinNum * 10, CV_8UC3);
//------------【5】双层循环,进行直方图绘制。遍历H、S通道------------
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(histImg, Point(hue*scale, saturation*scale), Point((hue + 1)*scale - 1,
(saturation + 1)*scale - 1), Scalar::all(intensity), CV_FILLED);
}
}
//------------【6】显示效果图------------------------
imshow("【源图像-RGB颜色空间】", srcImage);
imshow("【源图像转HSV颜色空间】", hsvImage);
imshow("H-S直方图", histImg);
waitKey(0);
return 0;
}
=========================分割线===================
====================分割线=================
注意 :色调(Hue),饱和度(Saturation)。 所以“H-S直方图”就是“色调-饱和度直方图” 。
参考文献:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。