列表内容
在读取直方图前,要了解一下图像的直方图是什么?其实图像直方图就是对一副图像每个像素的像素值的统计。比如一副灰度图像,每个像素只有一个通道,所以每个像素的值就是一个uchar的值,uchar的范围就是0~~255。也就是说,每个像素点只有256种可能,它就是0~255里的一个数值。直方图就是统计一副图像的每一个像素值的个数,(比如:像素值是0 的像素有20个,像素值是1是像素有30个,……像素值是254的像素有50个,像素值是255的像素有45个)。其实在实际应用是不会直接这样用直方图,想一想,一副图像有很多像素,如果我们想画出一副图像的直方图那像素值的个数是成千上万的,是很难画出来的。于是我们一般会把直方图归一化,归一化就是用每个像素值的个数除以图像的像素总数,这样的话,每一个像素值的个数就会变成一个小数,而所有像素值的个数加起来就是1;这样直方图的值域就限定在0到1啦,但是他们的比例不变。这样好像是可以了,但是我们用计算机画直方图是需要的是整数。于是我们又可以用要的直方图图像的高乘以归一化的直方图,这样有把直方图的值域换到可以接受的范围,又不会太大。
下面是定义了一个类用来画出一副彩色图像的HSV三个通道的直方图:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstring>
using namespace cv;
using namespace std;
/*
* 功能:计算图形SHV的直方图和灰度图像直方图
*
*
**/
class HistogramND
{
private:
Mat src ;//源图像
Mat hsv ;//转化后的SHV图像
Mat rgb_hist[3] ,gray; //
int histSize ,hist_w ,hist_h;//定义直方图图像的大小,宽和高
float range[2]; //直方图定义域的范围值
const float *ranges ;
vector<Mat> rgb_plances ;
MatND r_hist , g_hist , b_hist ; //用来放直方图的一维向量
public:
HistogramND(){ //初始化
histSize = 256 ;
range[0] = 0.0 ;
range[1] = 255.0 ;
ranges = &range[0] ;
}
~HistogramND(){};
//设置原图像
void setImage(Mat &image){
image.copyTo(src) ;
}
//导入原图像
void importImage(string iamge){
src = cv::imread(iamge);
}
//把图像从RGB转换到HSV
void RGB2HSV(){
if(src.channels() == 3){
cvtColor(src, hsv, COLOR_BGR2HSV);
}
}
//把SHV的三个通道分解
void HSVsplic(){
if(src.channels() == 3){
split(hsv ,rgb_plances);
}
}
//直方图处理程序
//如果是彩色图像通道为3,灰度图像通道为1
void ProcHist(){ if(src.channels()== 3){
//获取直方图
calcHist(&rgb_plances[2] ,1 , 0 ,Mat(),r_hist ,1,&histSize ,&ranges ,true ,false);
calcHist(&rgb_plances[1] ,1, 0 ,Mat() ,g_hist,1 ,&histSize ,&ranges ,true ,false);
calcHist(&rgb_plances[0] ,1, 0 ,Mat() , b_hist ,1, &histSize ,&ranges ,true ,false);
//在控制台输出直方图的值
for (int i = 0 ; i < 255;i++)
{
cout<<"Red Value"<<i<<"= "<<r_hist.at<float>(i)<<endl ;
cout<<"Green Value"<<i<<"= "<<g_hist.at<float>(i)<<endl;
cout<<"Blue Value"<<i<<"= "<<b_hist.at<float>(i) << endl ;
} } else{//处理灰度图像的直方图
calcHist(&src , 1 , 0 ,Mat() , r_hist , 1 ,&histSize ,&ranges ,true ,false) ;
}
}
Mat getSrc(){
return src;
}
void Dspgr(){//显示灰度图像直方图
hist_w = 400 ;
hist_h = 600 ;
gray = Mat(hist_h ,hist_w , CV_8UC3 ,Scalar::all(0));
normalize(r_hist ,r_hist,0 ,hist_w-10 ,NORM_MINMAX);//规定化直方图
for (int i = 0 ; i < 256 ; i++)
{
int val = saturate_cast<int>(r_hist.at<float>(i));
rectangle(gray ,Point(i*2+10 ,gray.rows ), Point((i+1)*2+10, gray.rows-val),Scalar(0,0,255),1,8) ;
}
imshow("灰度直方图",gray) ;
}
void DisplayHist(){//显示彩色图像直方图
hist_w = 400 ;
hist_h = 600 ;
for (int i = 0 ; i < 3 ; i++)
{
rgb_hist[i] = Mat(hist_w , hist_h ,CV_8UC3 ,Scalar::all(0));
}
normalize(r_hist, r_hist, 0, hist_w-10, NORM_MINMAX);
normalize(g_hist, g_hist, 0, hist_w-10, NORM_MINMAX);
normalize(b_hist, b_hist, 0, hist_w-10, NORM_MINMAX);
for (int i = 0 ; i < 256 ; i++)
{
int val = saturate_cast<int>(r_hist.at<float>(i));
rectangle(rgb_hist[0] ,Point(i*2+10 ,rgb_hist[0].rows ), Point((i+1)*2+10, rgb_hist[0].rows-val),Scalar(0,0,255),1,8) ;
val = saturate_cast<int>(g_hist.at<float>(i));
rectangle(rgb_hist[1] ,Point(i*2+10 ,rgb_hist[1].rows ), Point((i+1)*2+10, rgb_hist[1].rows-val),Scalar(0,255,0),1,8) ;
val = saturate_cast<int>(b_hist.at<float>(i));
rectangle(rgb_hist[2] ,Point(i*2+10 ,rgb_hist[2].rows ), Point((i+1)*2+10, rgb_hist[2].rows-val),Scalar(255,0,0),1,8) ;
}
cv::imshow("H" , rgb_hist[2]);
imshow("S" , rgb_hist[1]);
imshow("V" , rgb_hist[0]);
imshow("image" , src);
}
};
接下来可以在main函数调用上述函数;测试结果:
原图
HSV直方图
H:
S:
V:
灰度图像
灰度图像直方图:
控制塔输出结果: