需求说明
在对图像进行处理时,经常会有这类需求:想要观察图像的直方图分布,例如灰度图中0-255区间数值的分布情况,从而可以进行后续的操作,如阈值分割二值化、直方图均衡化等等。本文设计了一个能绘制简易直方图的简单函数DrawHistImg,可以帮助大家快速掌握绘制的原理,可以根据自己的创意对其进行改善和补充。
下面介绍具体实现流程。
具体流程
1)取图像的灰度图,并遍历统计0-255各个灰度值所出现的次数。
- cv::Mat src = imread("test.jpg", 0);
- cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
- for (int i = 0; i < src.rows; ++i)
- {
- for (int j = 0; j < src.cols; ++j)
- {
- hist.at<float>(0, src.at <uchar>(i, j))++;
- }
- }
2)定义直方图图像histImage,并初始化一些参数。其中bins是数值最大值,即255;scale为每个灰度值所对应的直方图宽度;histHeight为直方图高度最大值,也是直方图图像的宽。
- cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
- const int bins = 255;
- int scale = 4;
- int histHeight = 540;
3)利用minMaxLoc函数得出哪个灰度值的出现次数最高,为归一化做准备。
- double maxValue;
- cv::Point2i maxLoc;
- cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
4)遍历hist中每个灰度值,并根据其出现次数绘制直方图,height是归一化后的高度。
- for (int i = 0; i < bins; i++)
- {
- float binValue = (hist.at<float>(i));
- int height = cvRound(binValue * histHeight / maxValue);
- cv::rectangle(histImage, cv::Point(i * scale, histHeight),
- cv::Point((i + 1) * scale - 1, histHeight - height), cv::Scalar(255), -1);
-
- }
5)函数执行完毕。?
功能函数
- // 绘制简易直方图
- cv::Mat DrawHistImg(cv::Mat &src)
- {
- cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
- for (int i = 0; i < src.rows; ++i)
- {
- for (int j = 0; j < src.cols; ++j)
- {
- hist.at<float>(0, src.at <uchar>(i, j))++;
- }
- }
- cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
- const int bins = 255;
- double maxValue;
- cv::Point2i maxLoc;
- cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
- int scale = 4;
- int histHeight = 540;
-
- for (int i = 0; i < bins; i++)
- {
- float binValue = (hist.at<float>(i));
- int height = cvRound(binValue * histHeight / maxValue);
- cv::rectangle(histImage, cv::Point(i * scale, histHeight),
- cv::Point((i + 1) * scale - 1, histHeight - height), cv::Scalar(255), -1);
-
- }
- return histImage;
- }
C++测试代码
- #include <iostream>
- #include <time.h>
- #include <opencv2/opencv.hpp>
-
- using namespace std;
- using namespace cv;
-
- cv::Mat DrawHistImg(cv::Mat &hist);
-
- int main()
- {
- cv::Mat src = imread("test.jpg", 0);
-
- // 绘制均衡化后直方图
- cv::Mat hrI = DrawHistImg(src);
-
- imshow("original", src);
- imshow("hist", hrI);
- waitKey(0);
-
- return 0;
- }
-
-
- // 绘制简易直方图
- cv::Mat DrawHistImg(cv::Mat &src)
- {
- cv::Mat hist = cv::Mat::zeros(1, 256, CV_32FC1);
- for (int i = 0; i < src.rows; ++i)
- {
- for (int j = 0; j < src.cols; ++j)
- {
- hist.at<float>(0, src.at <uchar>(i, j))++;
- }
- }
- cv::Mat histImage = cv::Mat::zeros(540, 1020, CV_8UC1);
- const int bins = 255;
- double maxValue;
- cv::Point2i maxLoc;
- cv::minMaxLoc(hist, 0, &maxValue, 0, &maxLoc);
- int scale = 4;
- int histHeight = 540;
-
- for (int i = 0; i < bins; i++)
- {
- float binValue = (hist.at<float>(i));
- int height = cvRound(binValue * histHeight / maxValue);
- cv::rectangle(histImage, cv::Point(i * scale, histHeight),
- cv::Point((i + 1) * scale - 1, histHeight - height), cv::Scalar(255), -1);
-
- }
- return histImage;
- }
测试效果

图1 原图

图2 灰度图

图3 直方图
如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~?
以上就是C++ OpenCV绘制简易直方图DrawHistImg的详细内容,更多关于C++ OpenCV绘制直方图的资料请关注w3xue其它相关文章!