定义
直方图是数学中的一种表达工具,在统计学中应用颇多,直方图是一个二维的图标,如果放在坐标系中就是横轴和纵轴,分别表示不同的参数,在图像中就是图像样本的整体与图像单个的属性之间的统计关系。通俗的理解就是在横轴参数的不同区间内,某一特征或属性的数量或频率是多少。分类有灰度直方图,图像直方图,还有归一化和均衡化以及利用直方图的相关应用。
直方图的绘制
OpenCV提供了相关的API,如下所示。OpenCV提供了两个重载的calcHist函数,它可以计算一系列阵列的直方图,这些系列通常是图像或像平面。它最多可以同时处理32个维度。
C++: void calcHist(
const Mat* images, //要处理的图像,类型为CV_8U或 CV_32F
int nimages, //要处理图像的数量
const int* channels, //图像的通道序列
InputArray mask, //可自定义,与image尺寸相同的矩阵,默认Mat()输出的直方图
OutputArray hist, //输出直方图
int dims, //输出直方图的维度,最大为32
const int* histSize, //数组,存储不同维度的取样数量
const float** ranges, //二维数组与uniform和accumulate有关
bool uniform=true, //默认true,是否归一化
bool accumulate = false //默认false)
//下面同上,区别在于参数定义类型
C++: void 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 )
完整代码如下
#include<opencv2/opencv.hpp>
#include"iostream"
using namespace cv;
void main()
{
Mat dst, dst1;
Mat img = imread("ck567.jpg");
if (!img.data)
{
printf("fail to load jpg!\n");
}
else
{
imshow("original image", img);
//通道分离
vector<Mat>bgr_channel;
split(img,bgr_channel);
//计算直方图
int histsize = 256;//0~255共256个灰度级
float range[] = { 0,256 };//区间范围
const float*histRanges = { range };
Mat b_hist, g_hist, r_hist;
calcHist(&bgr_channel[0], 1, 0, Mat(), b_hist, 1, &histsize, &histRanges, true, false);
calcHist(&bgr_channel[1], 1, 0, Mat(), g_hist, 1, &histsize, &histRanges, true, false);
calcHist(&bgr_channel[2], 1, 0, Mat(), r_hist, 1, &histsize, &histRanges, true, false);
//归一化
int hist_h = 325;//直方图的图像的行数
int hist_w = 580;//直方图的图像的列数
double bin_w = hist_w / histsize;//每一个灰度级区间的宽度
Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));//绘制直方图显示的图像
normalize(b_hist, b_hist, 0, hist_h*0.8, NORM_MINMAX, -1, Mat());//归一化
normalize(g_hist, g_hist, 0, hist_h*0.8, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h*0.8, NORM_MINMAX, -1, Mat());
//绘制直方图
for (int i = 1; i < histsize; i++)
{
//绘制蓝色分量直方图
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, CV_AA);
//绘制绿色分量直方图
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, CV_AA);
//绘制红色分量直方图
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, CV_AA);
}
imshow("histogram iamge", histImage);
waitKey(0);
destroyAllWindows();
}
}
效果如下
上面是直方图的简单绘制,只能够粗略的看出某一范围内的RGB多少,并没有提供数据价值,因此如果能够在坐标系中显示直方图,并配有坐标,也是一大改进。
代码如下
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include "math.h"
#include"iostream"
using namespace cv;
void main()
{
int histSize = 50;
Mat img = imread("ck567.jpg",0);
imshow( "orignal jpg",img);
Mat hist;//计算得到的直方图结果
char string[10];
float ranges[2] = {0,256};
const float *histRanges[1] = {ranges};
Mat histimg(512,256*4,CV_8UC3,Scalar(0,0,0));
//计算图像的直方图
calcHist(&img,1,0,Mat(),hist,1,&histSize,histRanges,true,false);
double maxVal = 0;
Point maxLoc;
minMaxLoc(hist, NULL, &maxVal, NULL, &maxLoc);//寻找最大值及其位置
double bin_w =(double) histimg.cols / histSize; // histSize: 条的个数,则 bin_w 为条的宽度
double bin_h = (double)histimg.rows/ maxVal; // maxVal: 最高条的像素个数,则 bin_u 为单个像素的高度
// 画直方图
for(int i=0;i<histSize;i++)
{
Point p0=Point(i*bin_w,histimg.rows);
float binValue = hist.at<float>(i);
Point p1=Point((i+1)*bin_w,histimg.rows-binValue*bin_h);
rectangle(histimg,p0,p1,Scalar(255,0,0),2,8,0);
}
//画纵坐标刻度(像素个数)
int k=0;
for(int i=1;k<maxVal;i++)
{
k=i*maxVal/10;
sprintf(string,"%d",k);
putText(histimg, string , Point(0,histimg.rows-k*bin_h),FONT_HERSHEY_SIMPLEX,0.5,Scalar(255,255,0),1);
line( histimg,Point(0,histimg.rows-k*bin_h),Point(histimg.cols-1,histimg.rows-k*bin_h),Scalar(0,255,0));
}
//画横坐标刻度(像素灰度值)
k=0;
for(int i=1;k<256;i++)
{
k=i*30;
sprintf(string,"%d",k);
putText(histimg, string , Point(k*(histimg.cols / 256),histimg.rows), FONT_HERSHEY_SIMPLEX,0.5,Scalar(255,255,0),1);
}
imshow( "Hist", histimg );
waitKey(0);
destroyAllWindows();
}
效果如下
扫描二维码关注公众号,回复:
12457152 查看本文章

以上是直方图的绘制,重点如何在图像上进行定标画图。
直方图均衡化
直方图均衡化是直方图在图像处理中的一个应用。用于提高对比度,增强细节,便于观察。OpenCV提供的API如下所示。
C++ void equalizeHist(InputArray src, OutputArray dst)
灰度图均衡化代码如下
#include<opencv2/opencv.hpp>
#include "math.h"
#include"iostream"
using namespace cv;
void main()
{
Mat img = imread("1.jpg",0);
imshow("orignal jpg",img);
equalizeHist(img,img);
imshow("Hist",img);
waitKey(0);
destroyAllWindows();
}
效果如下
彩色图均衡化代码如下
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include"iostream"
using namespace cv;
void main()
{
Mat img = imread("1.jpg");
imshow("orignal jpg",img);
vector<Mat>channel;
split(img,channel);
Mat B = channel.at(0);
Mat G = channel.at(1);
Mat R = channel.at(2);
equalizeHist(B, B);
equalizeHist(G, G);
equalizeHist(R, R);
merge(channel, img);
imshow("hist",img);
waitKey(0);
destroyAllWindows();
}
效果如下