OpenCV之直⽅图绘制(calcHist函数详解)
⽬录
1.直⽅图的定义
要理解直⽅图,绕不开“亮度”这个概念。⼈们把亮度分为0到255共256个数值,数值越⼤,代表的亮度越⾼。其中0代表纯⿊⾊的最暗区域,255表⽰最亮的纯⽩⾊,⽽中间的数字就是不同亮度的灰⾊。⼈们还进⼀步把这些亮度分为了5个区域,分别是⿊⾊,阴影,中间调,⾼光和⽩⾊。
在图像处理上,直⽅图是图像信息统计的有⼒⼯具。其实也就是统计⼀幅图某个亮度像素数量。
最近看的小说2.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=fal);
参数解释:
· images:输⼊的图像的指针;
· nimages:输⼊图像个数;
· channels:需要统计直⽅图的第⼏通道;
别时容易见时难· mask:掩模,mask必须是⼀个8位(CV_8U)的数组并且和images的数组⼤⼩相同;
·
hist:直⽅图计算的输出值;
· dims:输出直⽅图的维度(由channels指定);
· histSize:直⽅图中每个dims维度需要分成多少个区间(如果把直⽅图看作⼀个⼀个竖条的话,就是竖条的个数);
· ranges:统计像素值的区间;
· uniform=true:是否对得到的直⽅图数组进⾏归⼀化处理;
· accumulate=fal:在多个图像时,是否累积计算像素值的个数;
【注】:在计算图像直⽅图的时候⼀般配合minMaxLoc()和normalize()函数⼀起使⽤。
3.绘制直⽅图
只看函数说明肯定看不明⽩,下⾯来对函数进⾏代码演⽰。绘制直⽅图主要有三步:
3.1 读取原图像并检查图像是否读取成功
相关代码如下:
Mat src, gray;
src =imread("D:/Desktop/16.png");
if(!src.data)
{
cout <<"读取图⽚错误,请重新输⼊正确路径!\n";
system("pau");
return-1;
}
热爱的名言
cvtColor(src, gray, CV_BGR2GRAY);//转换为灰度图像
imshow("【灰度图】", gray);
当然,如果觉得⿇烦,可以直接⽤以下代码代替:
Mat src, gray;
grayImage =imread("D:/Desktop/16.png",0);
imshow("【灰度图】", gray);
3.2 定义直⽅图参数并计算直⽅图
//需要计算的图像的通道,灰度图像为0,BGR图像需要指定B,G,R
const int channels[]={0};
Mat hist;//定义输出Mat类型
int dims =1;//设置直⽅图维度
const int histSize[]={256};//直⽅图每⼀个维度划分的柱条的数⽬
//每⼀个维度取值范围
float pranges[]={0,255};//取值区间
const float* ranges[]={ pranges };
calcHist(&gray,1, channels,Mat(), hist, dims, histSize, ranges,true,fal);//计算直⽅图
3.3 绘制直⽅图
⽅法⼀:
int scale =2;
int hist_height =256;
Mat hist_img = Mat::zeros(hist_height,256* scale, CV_8UC3);//创建⼀个⿊底的8位的3通道图像,⾼256,宽256*2
double max_val;
minMaxLoc(hist,0,&max_val,0,0);//计算直⽅图的最⼤像素值
//将像素的个数整合到图像的最⼤范围内
//遍历直⽅图得到的数据
for(int i =0; i <256; i++)
向孩子学习
吃什么补脑神经{
float bin_val = hist.at<float>(i);//遍历hist元素(注意hist中是float类型)
int intensity =cvRound(bin_val*hist_height / max_val);//绘制⾼度
rectangle(hist_img,Point(i*scale, hist_height -1),Point((i +1)*scale -1, hist_height - intensity),Scalar(255,255,255));//绘制直⽅图}
⽅法⼆:
int hist_w =500;
int hist_h =300;
int nHistSize =256;
int bin_w =cvRound((double)hist_w / nHistSize);//区间
Mat histImage(hist_h, hist_w, CV_8UC3,Scalar(0,0,0));//创建⼀个⿊底的8位的3通道图像,⾼300,宽500
normalize(hist, hist,0, ws, NORM_MINMAX,-1,Mat());//将直⽅图归⼀化到[ws]
for(int i =1; i < nHistSize; i++)
{
统一思想认识line(histImage,Point(bin_w*(i -1), hist_h -cvRound(hist.at<float>(i -1))),Point(bin_w*(i), hist_h -cvRou
nd(hist.at<float>(i))),Scalar(255,0,0));
}
4.关于BGR直⽅图的绘制
上⾯介绍了灰度直⽅图的绘制,下⾯介绍⼀下BGR彩⾊直⽅图的绘制过程。
关于为什么叫BGR⽽不叫RGB,⽹上有许多误导性的博客,相信⼤家⼀定也有所了解,这⾥就不过多介绍了。
4.1 读取原图像并检查图像是否读取成功
同上
4.2 分通道显⽰
利⽤split函数进⾏分通道显⽰:
vector<Mat>bgr_planes;
split(src, bgr_planes);
4.3 分B,G,R计算直⽅图
int histSize =256;
float range[]={0,255};
const float*Ranges ={ range };
Mat b_hist, g_hist, r_hist;
calcHist(&bgr_planes[0],1,0,Mat(), b_hist,1,&histSize,&Ranges,true,fal);
calcHist(&bgr_planes[1],1,0,Mat(), g_hist,1,&histSize,&Ranges,true,fal);
calcHist(&bgr_planes[2],1,0,Mat(), r_hist,1,&histSize,&Ranges,true,fal);
【注意】:这⾥说明⼀下,第⼀⾏有两种写法,如果按照3.2所写:const int histSize[] = { 256 }; ,则后⾯计算直⽅图时直接写histSize 即可,如果按照4.3所写:int histSize = 256;,那么下⾯调⽤计算直⽅图的calcHist()函数的时候,该变量需要写 &histSize
选择⼀种⾃⼰喜欢的⽅法即可,切记不要⽤混了!
4.4 绘制直⽅图
int hist_w =500;//直⽅图的图像的宽
int hist_h =300;//直⽅图的图像的⾼
int nHistSize =256;
int bin_w =cvRound((double)hist_w / nHistSize);//区间
疫情复工图片
Mat histImage(hist_h, hist_w, CV_8UC3,Scalar(0,0,0));//绘制直⽅图显⽰的图像normalize(b_hist, b_hist,0, ws, NORM_MINMAX,-1,Mat());//归⼀化normalize(g_hist, g_hist,0, ws, NORM_MINMAX,-1,Mat()); normalize(r_hist, r_hist,0, ws, NORM_MINMAX,-1,Mat());
for(int i =1; i < nHistSize; 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);
羸弱的读音//绘制绿⾊分量直⽅图
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);
//绘制红⾊分量直⽅图
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);
}
输出结果: