【OpenCV • c++】直方图计算 | 绘制 H-S 直方图 | 绘制一维直方图 | 绘制 RGB 三色直方图

news2025/3/1 21:49:13

文章目录

    • 一、什么是直方图
    • 二、直方图的相关函数
      • 1、计算直方图 calcHist()
      • 2、找寻最值 minMaxLoc()
    • 三、程序演示
      • 1、色调 —— 饱和度直方图
      • 2、一维直方图
      • 3、RGB 三色直方图

一、什么是直方图

  直方图广泛应用于很多计算机视觉处理当中。通过标记帧与帧之间显著的边缘和颜色的变化,可以检测视频中的场景变化。在每个兴趣点设置一个有相似特征的直方图所构成的“标签”,可以用来标记各种不同的事情,比如图像的色彩分布,物体边缘梯度模板等等。是计算机视觉中最经典的工具之一。
  简单来说直方图就是对数据进行统计的一种方法,它将统计值组织到一系列事先定义好的bin中。bin中的数值是从数据中计算出的特征的统计量,这些数据可以是梯度、方向、色彩以及其他任何特征。直方图获取的是数据分布的统计图,通常情况下,直方图的维度要低于原始数据。由于原始数据可以表示任何事情,直方图就可以很好的表示图像的特征。

二、直方图的相关函数

1、计算直方图 calcHist()

  函数cv:calcHist()可以计算一个或多个数组的直方图。

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 
	) 	

  其中,第一个参数表示输入的数组或数组集,它们需要相同的深度和相同的尺寸。第二个参数表示输入数组的个数,也就是第一个参数中有几个原数组。第三个参数表示需要统计的通道索引。第四个参数表示可选的操作掩码,如果不为空,那么必须为8位,并且与images[i]有同样大小的尺寸,这里的非零掩码元素用于标记出统计直方图的数组元素数据。第五个参数表示输出的目标直方图,是一个二维数组。第六个参数表示需要计算的直方图维度,必须是正数。第七个参数表示存放每个维度的直方图尺寸的数组。第八个参数表示每一维数值的取值范围,第九个参数表示直方图是否均匀的标识符,默认为true。第十个参数表示累计标识符,有默认值false。若为true,直方图在配置阶段不会被清零。此功能主要是允许从多个阵列中计算单个直方图,或者用于在特定的时间更新直方图。

2、找寻最值 minMaxLoc()

  函数minMaxLoc() 查找最小和最大元素值及其位置。在整个数组中搜索极值,如果掩码不是空数组,则在指定的数组区域中搜索极值。

void cv::minMaxLoc 	( 	InputArray  	src,
		double *  	minVal,
		double *  	maxVal = 0,
		Point *  	minLoc = 0,
		Point *  	maxLoc = 0,
		InputArray  	mask = noArray() 
	) 	

  其中第一个参数表示输入的单通道列阵。第二个参数表示返回最小值的指针,若无须返回则为NULL。第三个参数表示返回的最大值的指针,若无须返回则为NULL。第四个参数表示返回最小位置的指针若无须返回则为NULL。第五个参数表示返回最大位置的指针若无须返回则为NULL。

三、程序演示

1、色调 —— 饱和度直方图

  下面我们来说明一下如何计算彩色图像的色调 —— 饱和度直方图。

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;

int main()
{
	// 读取图像并创建一个Mat对象来存储图像数据
	Mat src, hsv;
	src = imread("C://Users//86173//Desktop//c.png");

	// 检查图像是否成功加载
	if (!src.data)
		return -1;

	// 将图像从BGR颜色空间转换为HSV颜色空间
	cvtColor(src, hsv, COLOR_BGR2HSV);

	// 定义直方图的参数
	int hbins = 30, sbins = 32;
	int histSize[] = { hbins, sbins };
	float hranges[] = { 0, 180 };
	float sranges[] = { 0, 256 };
	const float* ranges[] = { hranges, sranges };

	// 创建一个用于存储直方图的Mat对象
	MatND hist;

	// 指定通道
	int channels[] = { 0, 1 };

	// 计算直方图
	calcHist(&hsv, 1, channels, Mat(), hist, 2, histSize, ranges, true, false);

	// 寻找直方图的最大值
	double maxVal = 0;
	minMaxLoc(hist, 0, &maxVal, 0, 0);

	// 定义绘制直方图的参数
	int scale = 10;
	Mat histImg = Mat::zeros(sbins * scale, hbins * 10, CV_8UC3);

	// 绘制直方图
	for (int h = 0; h < hbins; h++)
	{
		for (int s = 0; s < sbins; s++)
		{
			float binVal = hist.at<float>(h, s);
			int intensity = cvRound(binVal * 255 / maxVal);
			rectangle(histImg, Point(h * scale, s * scale), Point((h + 1) * scale - 1, (s + 1) * scale - 1), Scalar::all(intensity), -1);
		}
	}

	// 创建并显示源图像窗口
	namedWindow("Source", 1);
	imshow("Source", src);

	// 创建并显示H-S直方图窗口
	namedWindow("H-S Histogram", 1);
	imshow("H-S Histogram", histImg);

	waitKey();
}

在这里插入图片描述

2、一维直方图

  下面我们来介绍一下如何计算绘制图像一维直方图。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/utils/logger.hpp>

using namespace cv;
using namespace std;

int main()
{
    // 读取图像
    Mat srcImage = imread("C://Users//86173//Desktop//c.png");
    if (!srcImage.data)
    {
        printf("fail to load image!\n");
        return 0;
    }
    // 显示原始图像
    imshow("【原始图】", srcImage);

    // 计算直方图
    MatND dstHist;
    int dims = 1;
    float hranges[] = { 0, 255 };
    const float* ranges[] = { hranges };
    int size = 256;
    int channels = 0;

    calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges, true, false);

    // 创建用于显示直方图的图像
    int scale = 1;
    Mat dstImage(size * scale, size, CV_8U, Scalar(0));

    // 获取直方图的最小值和最大值
    double minValue = 0;
    double maxValue = 0;
    minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);

    // 绘制直方图
    int hpt = saturate_cast<int>(0.9 * size);
    for (int i = 0; i < 256; i++)
    {
        float binValue = dstHist.at<float>(i);
        int realValue = saturate_cast<int>(binValue * hpt / maxValue);
        rectangle(dstImage, Point(i * scale, size - 1), Point((i + 1) * scale - 1, size - realValue), Scalar(255));
    }
    // 显示一维直方图
    imshow("一维直方图", dstImage);

    waitKey(0);
    return 0;
}

在这里插入图片描述

3、RGB 三色直方图

  下面我们来介绍一下如何绘制图像的 RGB 三色直方图。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/utils/logger.hpp>

using namespace cv;
using namespace std;

int main()
{
    // 读取图像
    Mat srcImage = imread("C://Users//86173//Desktop//c.png");
    if (!srcImage.data)
    {
        printf("fail to load image!\n");
        return 0;
    }
    imshow("【原始图】", srcImage);

    int bins = 256;
    int hist_size[] = { bins };
    float range[] = { 0, 256 };
    const float* ranges[] = { range };
    MatND redHist, grayHist, blueHist;

    // 计算红色分量的直方图
    int channels_r[] = { 0 };
    calcHist(&srcImage, 1, channels_r, Mat(), redHist, 1, hist_size, ranges, true, false);

    // 计算绿色分量的直方图
    int channels_g[] = { 1 };
    calcHist(&srcImage, 1, channels_g, Mat(), grayHist, 1, hist_size, ranges, true, false);

    // 计算蓝色分量的直方图
    int channels_b[] = { 2 };
    calcHist(&srcImage, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges, true, false);

    // 绘制三色直方图
    // 参数准备
    double maxValue_red, maxValue_green, maxValue_blue;
    minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
    minMaxLoc(grayHist, 0, &maxValue_green, 0, 0);
    minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);

    int scale = 1;
    int histHeight = 256;
    Mat histImage = Mat::zeros(histHeight, bins * 3, CV_8UC3);

    // 正式绘制
    for (int i = 0; i < bins; i++)
    {
        // 参数准备
        float binValue_red = redHist.at<float>(i);
        float binValue_green = grayHist.at<float>(i);
        float binValue_blue = blueHist.at<float>(i);
        int intensity_red = cvRound(binValue_red * histHeight / maxValue_red);    // 要绘制的高度
        int intensity_green = cvRound(binValue_green * histHeight / maxValue_green);    // 要绘制的高度
        int intensity_blue = cvRound(binValue_blue * histHeight / maxValue_blue);    // 要绘制的高度

        // 绘制红色分量的直方图
        rectangle(histImage, Point(i * scale, histHeight - 1), Point((i + 1) * scale - 1, histHeight - intensity_red), Scalar(255, 0, 0));
        // 绘制绿色分量的直方图
        rectangle(histImage, Point((i + bins) * scale, histHeight - 1), Point((i + bins + 1) * scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
        // 绘制蓝色分量的直方图
        rectangle(histImage, Point((i + bins * 2) * scale, histHeight - 1), Point((i + bins * 2 + 1) * scale - 1, histHeight - intensity_blue), Scalar(0, 0, 255));
    }
    // 显示直方图
    imshow("图像的RGB直方图", histImage);

    waitKey(0);
    return 0;
}

在这里插入图片描述

  • 🚀 个人简介:CSDN「博客新星」TOP 10 , C/C++ 领域新星创作者
  • 💟 作    者:锡兰_CC ❣️
  • 📝 专    栏:【OpenCV • c++】计算机视觉
  • 🌈 若有帮助,还请关注➕点赞➕收藏,不行的话我再努努力💪💪💪

更多专栏订阅推荐:

  • 👍 【开卷数据结构】
  • 💛 【备战蓝桥,冲击省一】
  • 💕   从零开始的 c++ 之旅
  • 💖 【OpenCV • c++】计算机视觉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/996039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】 二叉搜索树的实现

文章目录 &#x1f340;二叉搜索树的概念&#x1f6ec;二叉搜索树功能实现&#x1f6a9;查找关键字key&#x1f4cc;代码实现&#xff1a; &#x1f6a9;插入关键字key&#x1f4cc;代码实现&#xff1a; &#x1f6a9;删除关键字key&#x1f4cc;代码实现&#xff1a; &#x…

OpenCV(三十四):轮廓外接最大、最小矩形和多边形拟合

目录 1.轮廓外接最大矩形boundingRect() 2.轮廓外接最小矩形minAreaRect() 3.轮廓外接多边形approxPolyDP() 1.轮廓外接最大矩形boundingRect() Rect cv::boundingRect ( InputArray array ) array:输入的灰度图像或者2D点集&#xff0c;数据类型为vector<Point>或者M…

OpenCV实现图像的混合

原理 这其实也是加法&#xff0c;但是不同的是两幅图像的权重不同&#xff0c;这就会给人一种混合或者透明的感觉。 图像混合的计算公式如下: g(x)(1-a)f0(x) af1(x) 通过修改α的值(0→1) &#xff0c;可以实现非常炫酷的混合。 现在我们把两幅图混合在一起。 第一幅图…

C 风格文件输入/输出---无格式输入/输出---(std::fputc,std::putc,std::fputs)

C 标准库的 C I/O 子集实现 C 风格流输入/输出操作。 <cstdio> 头文件提供通用文件支持并提供有窄和多字节字符输入/输出能力的函数&#xff0c;而 <cwchar>头文件提供有宽字符输入/输出能力的函数。 无格式输入/输出 写字符到文件流 std::fputc, std::putc in…

软件测试面试遇到之redis要怎么测试?

软件测试面试遇到&#xff1a;redis要怎么测试&#xff1f; 首先我们需要知道&#xff0c;redis是什么&#xff1f;它能做什么&#xff1f; redis是一个 key-value 类型的高速存储数据库。redis常被用做&#xff1a;缓存、队列、发布订阅等。 所以&#xff0c;“redis要怎么…

第18章_瑞萨MCU零基础入门系列教程之GPT

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

基于SSM的学生管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

日志平台搭建第一章:Linux 安装elasticsearch-7.5.1

相关链接 官⽹&#xff1a; https://www.elastic.co/cn/downloads/elasticsearch 下载&#xff1a; wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.5.1-linux-x86_64.tar.gz 分词器&#xff1a; https://github.com/medcl/elasticsearch-an…

来看看Sublime Text运行Python程序(包含下载和安装)

py Sublime Text 是一款流行的文本编辑器&#xff0c;它体积小、运行速度快、文本功能强大、可以运行在 Windows、Linux 和 Mac OS X 平台上。 在程序员眼里&#xff0c;Sublime Text 还是一款非常好用的代码编辑器&#xff0c;它支持运行 C/C、Python、Java 等多种语言编写的程…

PyCharm集成开发环境安装、启动与设置

作为非开发工程师职业,大家多多少少都会对编程有抵触,其实没有必要对Python有太大的“戒心" ,把Python当做你的一个工具就可以了。——扎克伯格 一、Python的定义&#xff1a; Python是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。Python的设计具有…

21.添加websocket模块

这里默认读者了解websocket协议&#xff0c;若是还不了解可以看下这篇文章wesocket协议。 websocket主要有三个步骤&#xff0c;1通过HTTP进行握手连接&#xff0c;2进行双向通信&#xff0c;3.协商断开连接 第一步的握手连接需要HTTP&#xff0c;所以还需要使用到上一节讲解…

《C++ primer plus》精炼(OOP部分)——对象和类(2)

“学习是人类成长的喷泉。” - 亚里士多德 文章目录 内联函数对象的方法和属性构造函数和析构函数构造函数的种类使用构造函数析构函数列表初始化 const成员函数this指针对象数组类作用域作用域为类的常量类作用域内的枚举 内联函数 定义位于类声明中的函数自动成为内联函数。…

代码随想录第46天|139.单词拆分,了解多重背包,背包总结

139.单词拆分 动规五部曲 1.确定valid数组以及下标的含义 valid[i] : 字符串长度为i的话&#xff0c;valid[i]为true&#xff0c;表示可以拆分为一个或多个在字典中出现的单词。 2.valid初始化 valid[0]一定要为true&#xff0c;否则递推下去后面都都是false了 3.递推公式…

TDesign WXS语法

目录 一、输出函数返回值如何获取&#xff1f; 二、WXS语法 三、WXS案例 一、输出函数返回值如何获取&#xff1f; 写在js的方法中 wxml中{{方法名()}}输出&#xff1a; 发现不显示&#xff1f;&#xff1f; 所以不能使用这种方式&#xff01;&#xff01; 二、WXS语法 1.…

idea启动缓慢解决办法

idea启动缓慢解决办法 文章目录 idea启动缓慢解决办法前言一、修改内存大小二、虚拟机运行大小三、插件禁用1、安卓相关2、构建工具3、Code Coverage 代码覆盖率4、数据库5、部署工具6、html和xml7、ide settings8、JavaScript框架和工具9、jvm框架10、Keymap快捷键映射11、kot…

c语言练习43:深入理解strcmp

深入理解strcmp strcmp的主要功能是用来比较两个字符串 模拟实现strcmp 比较两个字符串对应位置上的大小 按字典序进行比较 例如&#xff1a; 输入&#xff1a;abc abc 输出&#xff1a;0 输入&#xff1a;abc ab 输出&#xff1a;>0的数 输入&#xff1a;ab abc …

BUUCTF ciscn_2019_n_1 1

分析 使用file命令查看文件信息 使用IDA64打开文件 进入func函数 如果 v2 等于 11.28125 就可以拿到flag 可以看到v1有栈溢出&#xff0c;并且v1在v2的上面&#xff0c;可以通过溢出v2来覆盖v1的值从而获取flag 首先v1是浮点数 11.28125 的二进制是 0x413480 exp from…

【FPGA零基础学习之旅#13】串口发送模块设计与验证

&#x1f389;欢迎来到FPGA专栏~串口发送模块 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望大家能指正&…

Redis 十大核心数据类型解析

一、Redis 简述 redis是一个开源的使用C语言编写的一个kv存储系统&#xff0c;是一个速度非常快的非关系远程内存数据库。它支持包括String、List、Set、Zset、hash五种数据结构。 除此之外&#xff0c;通过复制、持久化和客户端分片等特性&#xff0c;用户可以很方便地将red…

基于Yolov8的NEU-DET钢材表面缺陷检测,优化组合新颖程度较高:CVPR2023 PConv和BiLevelRoutingAttention,涨点明显

1.钢铁缺陷数据集介绍 NEU-DET钢材表面缺陷共有六大类,分别为:crazing,inclusion,patches,pitted_surface,rolled-in_scale,scratches 每个类别分布为: 2.基于yolov8的训练 原始网络如下: map@0.5为0.733