opencv对直方图的计算和绘制

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

1、直方图的计算

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

函数原型

cpp 复制代码
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

返回值

  • 无返回值,该函数直接修改输出直方图。
cpp 复制代码
#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 函数绘制直方图。
cpp 复制代码
#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)),以便直方图条的高度与直方图值成比例。

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

cpp 复制代码
// 计算彩色图直方图
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 函数显示直方图。

以下是示例代码:

cpp 复制代码
#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 直方图,可以使用以下代码:

cpp 复制代码
// 计算 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();
相关推荐
刘什么洋啊Zz1 小时前
MacOS下使用Ollama本地构建DeepSeek并使用本地Dify构建AI应用
人工智能·macos·ai·ollama·deepseek
奔跑草-2 小时前
【拥抱AI】GPT Researcher 源码试跑成功的心得与总结
人工智能·gpt·ai搜索·deep research·深度检索
禁默3 小时前
【第四届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2025】网络安全,人工智能,数字经济的研究
人工智能·安全·web安全·数字经济·学术论文
AnnyYoung4 小时前
华为云deepseek大模型平台:deepseek满血版
人工智能·ai·华为云
INDEMIND5 小时前
INDEMIND:AI视觉赋能服务机器人,“零”碰撞避障技术实现全天候安全
人工智能·视觉导航·服务机器人·商用机器人
慕容木木5 小时前
【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体的替代品,可本地部署+知识库,注册即可有750w的token使用
人工智能·火山引擎·deepseek·deepseek r1
南 阳5 小时前
百度搜索全面接入DeepSeek-R1满血版:AI与搜索的全新融合
人工智能·chatgpt
企鹅侠客6 小时前
开源免费文档翻译工具 可支持pdf、word、excel、ppt
人工智能·pdf·word·excel·自动翻译
冰淇淋百宝箱6 小时前
AI 安全时代:SDL与大模型结合的“王炸组合”——技术落地与实战指南
人工智能·安全
Elastic 中国社区官方博客7 小时前
Elasticsearch Open Inference API 增加了对 Jina AI 嵌入和 Rerank 模型的支持
大数据·人工智能·elasticsearch·搜索引擎·ai·全文检索·jina