用opencv写了一个灰度直方图显示工具,与其他灰度直方图显示没有本质差别,只是根据个人喜好添加了坐标参数显示功能.
具体实现实现原理请看代码注释
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage = imread("C:\\Users\\Alliance\\Desktop\\2.jpg",0);//只读取灰度图
if (!srcImage.data)
{
cout << "fail to load image" << endl;
return 0;
}
imshow("原图", srcImage);
MatND dstHist;//得到的直方图
int dims = 1;//得到的直方图的维数 灰度图的维数为1
float hranges[2] = { 1, 255 }; //直方图统计的灰度值范围
const float *ranges[1] = { hranges }; // 这里需要为const类型,二维数组用来指出每个区间的范围
int bin = 255;//直方图横坐标的区间数 即横坐标被分成多少份
int channels = 0;//图像得通道 灰度图的通道数为0
/* 计算图像的直方图 */
calcHist(&srcImage, 1/*输入图像个数*/, &channels, Mat()/*掩码*/, dstHist, dims, &bin, ranges);
int height = 150; //直方图高度
int scale = 3; //垂直缩放比
int horvizon_scale = 3; //水平缩放比
//获取最大值和最小值
double minValue = 0;
double maxValue = 0;
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0); //找到直方图中的最大值和最小值
int shift_vertical = 13; //直方图偏移值,偏移用于显示水平坐标
int shift_horvizon = 30; //直方图偏移值,偏移用于显示垂直坐标
//绘制出直方图
Mat dstImage(height*scale, bin*horvizon_scale + shift_horvizon, CV_8UC3, Scalar(0, 0, 0)); //创建一个彩色三通道矩阵,大小a*b,填充0
int hpt = saturate_cast<int>((dstImage.rows - shift_vertical)*0.95); //最大值对应的Y坐标,防止溢出
for (int i = 0; i < bin; i++)
{
float binValue = dstHist.at<float>(i);
int realValue = saturate_cast<int>(binValue * hpt / maxValue);
rectangle(dstImage, Point(i*horvizon_scale + shift_horvizon, dstImage.rows - 1 - shift_vertical), Point((i + 1)*horvizon_scale + shift_horvizon - 1, dstImage.rows - realValue - shift_vertical), Scalar(255, 255, 255), 1, 8, 0);
}
//绘制垂直刻度
char string[100];
CvFont font;
double font_size = 1;//字体大小
cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1, 1, 0, 1, 8);//字体结构初始化
Size text_size;
for (int i = hpt; i>=0; )
{
_itoa(maxValue*i/hpt, string, 10);//把一个整数转换为字符串
//在图像中显示文本字符串
text_size = getTextSize(string, CV_FONT_HERSHEY_PLAIN, font_size, 1, NULL); //获得字体大小
putText(dstImage, string, cvPoint(0, dstImage.rows - i - shift_vertical + text_size.height/2), cv::FONT_HERSHEY_PLAIN, font_size, Scalar(0, 255, 0), 1, 8, 0);
i -= hpt / 10; //只显示10个刻度
}
//刻画水平刻度
for (int i = bin; i >= 0;)
{
_itoa(i, string, 10);//把一个整数转换为字符串
//在图像中显示文本字符串
text_size = getTextSize(string, CV_FONT_HERSHEY_PLAIN, font_size, 1, NULL); //获得字体大小
putText(dstImage, string, cvPoint(i*horvizon_scale + shift_horvizon - text_size.width/2, dstImage.rows), cv::FONT_HERSHEY_PLAIN, font_size, Scalar(0, 0, 255), 1, 8, 0);
i -= bin / 20; //只显示20个刻度
}
//显示统计信息
sprintf(string, "bin=%d Ranges from %d to %d", bin, (int)hranges[0], (int)hranges[1]);
putText(dstImage, string, cvPoint(dstImage.cols/5, 30), cv::FONT_HERSHEY_PLAIN, (double)1.3, Scalar(255, 0, 0), 1, 8, 0);
imshow("一维直方图", dstImage);
waitKey(0);
return 0;
}
效果图:
参考链接:
<1> http://blog.csdn.net/qq_20823641/article/details/51932798
<2> http://blog.csdn.net/guduruyu/article/details/68491211
<3> https://docs.opencv.org/2.4.9/index.html