opencv对直方图的计算和绘制

embedded/2025/1/19 23:01:03/

【欢迎关注编码小哥,学习更多实用的编程方法和技巧】

1、直方图的计算

cv::calcHist 是 OpenCV 中用于计算图像直方图的函数。它可以处理多通道图像,并通过指定图像、通道、掩膜、直方图大小和范围等参数来生成直方图。

函数原型

void cv::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 = false)

参数

  • images: 要计算的原图,类型为 const Mat*,表示一个图像数组。
  • nimages: 图像数组的大小,类型为 int
  • channels: 指定计算的通道,类型为 const int*,表示一个通道数组。每个通道对应一个图像。
  • mask: 用于计算特定区域的掩膜,类型为 InputArray,表示一个图像或矩形区域。
  • hist: 输出的直方图,类型为 OutputArray,表示一个多维数组。
  • dims: 直方图的维度,类型为 int,表示直方图的维度。
  • histSize: 直方图的大小,类型为 const int*,表示一个大小数组,每个大小对应一个维度。
  • ranges: 像素值范围,类型为 const float**,表示一个范围数组,每个范围对应一个维度。
  • uniform: 是否使用均匀的直方图,类型为 bool,默认为 true
  • accumulate: 是否累积计算结果,类型为 bool,默认为 false

返回值

  • 无返回值,该函数直接修改输出直方图。
  • #include <opencv2/opencv.hpp>int main() {// 读取图像cv::Mat img = cv::imread("image.jpg");// 计算灰度图直方图cv::Mat gray;cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);int histSize = 256;float range[] = {0, 256};cv::Mat hist;cv::calcHist(&gray, 1, &0, cv::Mat(), hist, 1, &histSize, &range);// 计算彩色图直方图int channels[] = {0, 1, 2};cv::Mat hist_b, hist_g, hist_r;cv::calcHist(&img, 1, channels, cv::Mat(), hist_b, 1, &histSize, &range);cv::calcHist(&img, 1, channels + 1, cv::Mat(), hist_g, 1, &histSize, &range);cv::calcHist(&img, 1, channels + 2, cv::Mat(), hist_r, 1, &histSize, &range);// 绘制直方图cv::Mat hist_img(256, 256, CV_8UC3);cv::normalize(hist, hist, 0, hist_img.rows, cv::NORM_MINMAX);for (int i = 0; i < histSize; i++) {cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist.at<float>(i))), cv::Scalar(255, 0, 0));}cv::imshow("Histogram", hist_img);cv::waitKey(0);cv::destroyAllWindows();return 0;
    }

  • cv::calcHist 函数可以处理多通道图像,但必须指定计算的通道。
  • cv::calcHist 函数可以计算多个直方图,但必须具有相同的尺寸和类型。
  • cv::calcHist 函数可以累积计算结果,但必须指定输出直方图。

2、一维直方图的绘制

一维直方图是一种常见的数据可视化方法,用于显示数据的分布情况。在 OpenCV 中,可以使用以下步骤绘制一维直方图:

  1. 计算直方图:使用 cv::calcHist 函数计算图像的直方图。
  2. 归一化直方图:使用 cv::normalize 函数将直方图归一化到指定的范围。
  3. 绘制直方图:使用 cv::line 函数绘制直方图。
#include <opencv2/opencv.hpp>int main() {// 读取图像cv::Mat img = cv::imread("image.jpg");// 计算灰度图直方图cv::Mat gray;cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);int histSize = 256;float range[] = {0, 256};cv::Mat hist;cv::calcHist(&gray, 1, &0, cv::Mat(), hist, 1, &histSize, &range);// 归一化直方图cv::Mat hist_norm;cv::normalize(hist, hist_norm, 0, 256, cv::NORM_MINMAX);// 绘制直方图cv::Mat hist_img(256, 256, CV_8UC3);for (int i = 0; i < histSize; i++) {cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_norm.at<float>(i))), cv::Scalar(255, 0, 0));}// 显示直方图cv::imshow("Histogram", hist_img);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

 在这个示例中,我们首先读取一张图像,然后计算其灰度图直方图。接着,我们将直方图归一化到 0-256 的范围,然后绘制直方图。最后,我们显示直方图。

注意:在绘制直方图时,我们使用 cv::line 函数绘制每个直方图条。我们将直方图条的高度设置为 hist_img.rows - cvRound(hist_norm.at<float>(i)),以便直方图条的高度与直方图值成比例。

如果想绘制彩色图直方图,可以使用以下代码:

// 计算彩色图直方图
int channels[] = {0, 1, 2};
cv::Mat hist_b, hist_g, hist_r;
cv::calcHist(&img, 1, channels, cv::Mat(), hist_b, 1, &histSize, &range);
cv::calcHist(&img, 1, channels + 1, cv::Mat(), hist_g, 1, &histSize, &range);
cv::calcHist(&img, 1, channels + 2, cv::Mat(), hist_r, 1, &histSize, &range);// 归一化直方图
cv::Mat hist_b_norm, hist_g_norm, hist_r_norm;
cv::normalize(hist_b, hist_b_norm, 0, 256, cv::NORM_MINMAX);
cv::normalize(hist_g, hist_g_norm, 0, 256, cv::NORM_MINMAX);
cv::normalize(hist_r, hist_r_norm, 0, 256, cv::NORM_MINMAX);// 绘制直方图
cv::Mat hist_img(256, 256, CV_8UC3);
for (int i = 0; i < histSize; i++) {cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_b_norm.at<float>(i))), cv::Scalar(255, 0, 0));cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_g_norm.at<float>(i))), cv::Scalar(0, 255, 0));cv::line(hist_img, cv::Point(i, hist_img.rows), cv::Point(i, hist_img.rows - cvRound(hist_r_norm.at<float>(i))), cv::Scalar(0, 0, 255));
}

在这个示例中,我们计算彩色图的直方图,然后归一化直方图。接着,我们绘制直方图,每个通道使用不同的颜色。

3、多维直方图的绘制 

2D直方图是一种用于表示两个变量之间关系的数据可视化方法。在 OpenCV 中,可以使用以下步骤绘制 2D 直方图:

  1. 计算直方图:使用 cv::calcHist 函数计算图像的直方图。
  2. 归一化直方图:使用 cv::normalize 函数将直方图归一化到指定的范围。
  3. 绘制直方图:使用 cv::imshow 函数显示直方图。

以下是示例代码:

#include <opencv2/opencv.hpp>int main() {// 读取图像cv::Mat img = cv::imread("image.jpg");// 计算 2D 直方图int channels[] = {0, 1};int histSize[] = {256, 256};float range[] = {0, 256, 0, 256};cv::Mat hist;cv::calcHist(&img, 1, channels, cv::Mat(), hist, 2, histSize, range);// 归一化 2D 直方图cv::Mat hist_norm;cv::normalize(hist, hist_norm, 0, 256, cv::NORM_MINMAX);// 绘制 2D 直方图cv::Mat hist_img(256, 256, CV_8UC3);for (int i = 0; i < 256; i++) {for (int j = 0; j < 256; j++) {int index = i * 256 + j;cv::Vec3b color = cv::Vec3b(i, j, 0);hist_img.at<cv::Vec3b>(i, j) = color * (hist_norm.at<float>(index) / 256.0f);}}// 显示 2D 直方图cv::imshow("2D Histogram", hist_img);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

 在这个示例中,我们计算 2D 直方图,然后归一化 2D 直方图。接着,我们绘制 2D 直方图,每个像素的颜色根据 2D 直方图值计算。

注意:在绘制 2D 直方图时,我们使用 cv::Vec3b 类型表示颜色,每个颜色通道的值根据 2D 直方图值计算。

如果想绘制 3D 直方图,可以使用以下代码:

// 计算 3D 直方图
int channels[] = {0, 1, 2};
int histSize[] = {256, 256, 256};
float range[] = {0, 256, 0, 256, 0, 256};
cv::Mat hist;
cv::calcHist(&img, 1, channels, cv::Mat(), hist, 3, histSize, range);// 归一化 3D 直方图
cv::Mat hist_norm;
cv::normalize(hist, hist_norm, 0, 256, cv::NORM_MINMAX);// 绘制 3D 直方图
cv::Mat hist_img(256, 256, CV_8UC3);
for (int i = 0; i < 256; i++) {for (int j = 0; j < 256; j++) {for (int k = 0; k < 256; k++) {int index = i * 256 * 256 + j * 256 + k;cv::Vec3b color = cv::Vec3b(i, j, k);hist_img.at<cv::Vec3b>(i, j) = color * (hist_norm.at<float>(index) / 256.0f);}}
}// 显示 3D 直方图
cv::imshow("3D Histogram", hist_img);
cv::waitKey(0);
cv::destroyAllWindows();


http://www.ppmy.cn/embedded/155325.html

相关文章

Android系统开发(一):AOSP 架构全解析:开源拥抱安卓未来

引言 当我们手握智能手机&#xff0c;流畅地滑动屏幕、切换应用、欣赏动画时&#xff0c;背后其实藏着一套庞大且精密的开源系统——Android AOSP&#xff08;Android Open Source Project&#xff09;。这套系统不仅是所有安卓设备的根基&#xff0c;也是系统开发者的终极 pl…

大模型赋能医疗项目,深兰科技与武汉协和医院达成合作

2025年1月15日&#xff0c;以“科技创新&#xff0c;转化赋能&#xff0c;医企向未来”为主题的武汉市首届“卫生健康科技创新大赛优秀成果展示暨颁奖典礼”在光谷科技会展中心隆重举行&#xff0c;活动中&#xff0c;深兰科技武汉公司与华中科技大学同济医学院附属协和医院就构…

MongoDB深度解析与实践案例

MongoDB深度解析与实践案例 在当今大数据与云计算盛行的时代,NoSQL数据库以其灵活的数据模型、水平扩展能力和高性能,成为处理海量数据的重要工具之一。MongoDB,作为NoSQL数据库的杰出代表,凭借其面向文档的存储结构、强大的查询语言以及丰富的生态系统,赢得了众多开发者…

knife4j 文档解析 application/x-www-form-urlencoded表单解析成post json

环境 <spring.boot.version>2.7.18</spring.boot.version> <springdoc.version>1.8.0</springdoc.version> <knife4j.version>4.5.0</knife4j.version> 原因 解决方法 github 上发现有开发者创建了一个 fork&#xff0c;并将这个修复到…

远程桌面使用是TCP还是UDP?

什么是TCP和UDP&#xff1f; “远程桌面是使用TCP还是UDP协议&#xff1f;我通常在Windows Server 2012 R2服务器上使用远程桌面协议&#xff08;RDP&#xff09;进行连接&#xff0c;最近有些好奇&#xff0c;RDP到底是通过UDP 3389端口还是TCP 3389端口来建立远程会话的&…

机器学习-交叉验证

交叉验证 (Cross-Validation) 是一种评估模型性能和选择模型参数的统计学方法&#xff0c;特别是在数据量有限的情况下。它比简单地将数据分成训练集和测试集更加可靠&#xff0c;因为它利用了所有的数据进行训练和测试。 什么是交叉验证&#xff1f; 交叉验证的基本思想是将…

打家劫舍 打家劫舍II 打家劫舍III

打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房屋…

MySQL第三次实验

一、建库建表 1、创建数据库mydb11_stu并使用数据库 mysql> create database mydb11_stu; Query OK, 1 row affected (0.01 sec)mysql> show databases; -------------------- | Database | -------------------- | information_schema | | mydb10_city …