OpenCV直方图计算

news2025/2/21 3:41:43
 返回:OpenCV系列文章目录(持续更新中......)
上一篇:OpenCV实现直方图均衡
下一篇 :OpenCV系列文章目录(持续更新中......)

在本教程中,您将学习如何:

  • 使用 OpenCV 函数 cv::split 将图像划分为其对应平面。
  • 使用 OpenCV 函数计算图像数组的直方图 cv::calcHist
  • 使用函数 cv::normalize 规范化数组

注意

在上一个教程(直方图均衡)中,我们讨论了一种特殊的直方图,称为图像直方图。现在我们将从更一般的概念中考虑它。请继续阅读!

什么是直方图?

  • 直方图是组织到一组预定义箱中的数据计数集合
  • 当我们说数据时,我们并没有将其限制为强度值(正如我们在上一教程直方图均衡中看到的那样)。收集的数据可以是您认为对描述图像有用的任何特征。
  • 让我们看一个例子。想象一下,矩阵包含图像的信息即强度在(0-255)范围内:

  • 如果我们想以有组织的方式计算这些数据,会发生什么?由于我们知道这种情况的信息值范围是 256 个值,因此我们可以将范围分割成子部分(称为),例如:

[0,255]=[0,15]∪[16,31]∪....∪[240,255]�����=���1∪���2∪....∪����=15

我们可以计算每个 \(bin_{i}\) 范围内的像素数。将其应用于上面的示例,我们得到下面的图像(轴 x 表示箱,轴 y 表示每个箱中的像素数)。

  • 这只是直方图如何工作以及为什么它有用的简单示例。直方图不仅可以计算颜色强度,还可以计算我们想要测量的任何图像特征(即渐变、方向等)。
  • 让我们确定直方图的某些部分:
    1. dims:要收集数据的参数数。在我们的示例中,dims = 1,因为我们只计算每个像素的强度值(在灰度图像中)。
    2. bins:是每个 dim 中的细分数量。在我们的示例中,bins = 16
    3. range:要测量的值的限值。在本例中:范围 = [0,255]
  • 如果要计算两个功能怎么办?在这种情况下,生成的直方图将是一个 3D 图(其中 x 和 y 将是每个特征的 \(bin_{x}\) 和 \(bin_{y}\),z 将是 \((bin_{x}, bin_{y})\) 的每个组合的计数数)。这同样适用于更多功能(当然它会变得更棘手)。

OpenCV 为您提供什么

为了简单起见,OpenCV 实现了函数 cv::calcHist ,它计算一组数组(通常是图像或图像平面)的直方图。它最多可以操作 32 个尺寸。我们将在下面的代码中看到它!

C++代码
 

  • 这个程序是做什么的?
    • 加载图像
    • 使用函数 cv::split 将图像拆分为 R、G 和 B 平面
    • 通过调用函数 cv::calcHist 计算每个 1 通道平面的直方图
    • 在窗口中绘制三个直方图
  • 可下载代码: 点击这里
  • 代码一览
  • :
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/imgproc.hpp"
    #include <iostream>
     
    using namespace std;
    using namespace cv;
     
    int main(int argc, char** argv)
    {
     CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
     Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
     if( src.empty() )
     {
     return EXIT_FAILURE;
     }
     
     vector<Mat> bgr_planes;
     split( src, bgr_planes );
     
     int histSize = 256;
     
     float range[] = { 0, 256 }; //the upper boundary is exclusive
     const float* histRange[] = { range };
     
     bool uniform = true, accumulate = false;
     
     Mat b_hist, g_hist, r_hist;
     calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, histRange, uniform, accumulate );
     calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, histRange, uniform, accumulate );
     calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, histRange, uniform, accumulate );
     
     int hist_w = 512, hist_h = 400;
     int bin_w = cvRound( (double) hist_w/histSize );
     
     Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
     
     normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
     normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
     normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
     
     for( int i = 1; i < histSize; i++ )
     {
     line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ),
     Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
     Scalar( 255, 0, 0), 2, 8, 0 );
     line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ),
     Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
     Scalar( 0, 255, 0), 2, 8, 0 );
     line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ),
     Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
     Scalar( 0, 0, 255), 2, 8, 0 );
     }
     
     imshow("Source image", src );
     imshow("calcHist Demo", histImage );
     waitKey();
     
     return EXIT_SUCCESS;
    }

解释
 

加载源图像

 CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
 Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
 if( src.empty() )
 {
 return EXIT_FAILURE;
 }

将源图像分隔到三个 R、G 和 B 平面中。为此,我们使用 OpenCV 函数cv::split :

 vector<Mat> bgr_planes;
 split( src, bgr_planes );
  • 我们的输入是要分割的图像(在这种情况下有三个通道),输出是 Mat 的向量)

  • 现在,我们已准备好开始配置每个平面的直方图。由于我们正在使用 B、G 和 R 平面,因此我们知道我们的值将在区间内范围内[0,255]
  • 确定箱数 (5, 10...):

 int histSize = 256;

设置值范围(正如我们所说,介于 0 和 255 之间)

 float range[] = { 0, 256 }; //the upper boundary is exclusive
 const float* histRange[] = { range };

我们希望我们的箱具有相同的大小(均匀),并在开始时清除直方图,因此:

 bool uniform = true, accumulate = false;

我们继续使用 OpenCV 函数 cv::calcHist 计算直方图:

 Mat b_hist, g_hist, r_hist;
 calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, histRange, uniform, accumulate );
 calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, histRange, uniform, accumulate );
 calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, histRange, uniform, accumulate );
  • 其中参数为 (C++ 代码):
    • &bgr_planes[0]:源数组
    • 1:源数组的数量(在本例中我们使用 1.我们也可以在这里输入数组列表:)
    • 0:要测量的通道(暗淡)。在这种情况下,它只是强度(每个数组都是单通道的),所以我们只写 0。
    • Mat():要在源数组上使用的掩码(零表示要忽略的像素)。如果未定义,则不使用
    • b_hist:将存储直方图的 Mat 对象
    • 1:直方图维数。
    • histSize:每个使用维度的箱数
    • histRange:每个维度要测量的值范围
    • 均匀累积:箱大小相同,直方图在开始时被清除。
  • 创建图像以显示直方图:

 int hist_w = 512, hist_h = 400;
 int bin_w = cvRound( (double) hist_w/histSize );
 
 Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

请注意,在绘制之前,我们首先对直方图进行 cv::规范化,使其值落在输入的参数指示的范围内:

 normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
 normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
 normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
  • 此函数接收以下参数(C++ 代码):
    • b_hist:输入数组
    • b_hist:输出规范化数组(可以相同)
    • 0 和 histImage.rows:在此示例中,它们是规范化 r_hist 值的下限和上限
    • NORM_MINMAX:指示规范化类型的参数(如上所述,它调整之前设置的两个限制之间的值)
    • -1:表示输出规范化数组的类型将与输入相同
    • 垫():可选面罩
  • 要访问箱(在本例中为此 1D 直方图),请注意:

 for( int i = 1; i < histSize; i++ )
 {
 line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ),
 Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
 Scalar( 255, 0, 0), 2, 8, 0 );
 line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ),
 Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
 Scalar( 0, 255, 0), 2, 8, 0 );
 line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ),
 Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
 Scalar( 0, 0, 255), 2, 8, 0 );
 }

我们使用表达式(C++代码):

b_hist.at<float>(i)

其中表示尺寸。如果它是 2D 直方图,我们会使用如下内容:最后,我们显示直方图并等待用户退出:

 imshow("Source image", src );
 imshow("calcHist Demo", histImage );
 waitKey();

结果

  1. 使用如下所示的图像作为输入参数:

  1. 生成以下直方图:


参考文献:

1、《Histogram Calculation》-----Ana Huamán

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

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

相关文章

Kubernetes中文件挂载的四种方式

一. Kubernetes入门 1.1 Kubernetes创建POD过程 1.2. Kubernetes基本操作 命令说明用法create创建kubectl create -f xx.yamledit编辑kubectl edit svc [POD的service名称]get获取kubectl get pod --namespaceXXXpatch更新kubectl patch -f xx.yamldelete删除kubectl delete …

[SWPUCTF-2022-新生赛]ez_sql

title:[SWPUCTF 2022 新生赛]ez_sql 审题 根据提示&#xff0c;POST传参 得到假的flag 判断类型 字符型注入 判断列数 发现空格和’or’被过滤 重新构造 nss-1/**/oorrder/**/by/**/4#发现为3个字段 采用联合注入union 爆库 发现union被过滤&#xff0c;双写union绕过 发…

sheng的学习笔记-AI-支持向量机(SVM)

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 目录 什么是向量机 SVM算法原理 SVM基本模型 SVM对偶问题 什么是对偶问题&#xff1a; 为什么使用对偶问题 拉格朗日定理 拉格朗日乘子法 对偶问题算法 非线性SVM算法原理 核函数 常用核函数 软间隔与正则化 软…

PMBOK® 第六版 项目是什么

目录 读后感—PMBOK第六版 目录 项目定义 定义&#xff1a;项目是为创造独特的产品、服务或成果而进行的临时性工作。 项目的特征具备以下三点&#xff1a; 独特性&#xff1a;独一无二&#xff0c;无法简单重复过去的做法。 临时性&#xff1a;项目有明确的起点和终点&…

腾讯云邮件推送如何设置?群发邮件的技巧?

腾讯云邮件推送功能有哪些&#xff1f;怎么有效使用邮件推送&#xff1f; 腾讯云邮件推送以其稳定、高效的特点&#xff0c;受到了众多企业的青睐。那么&#xff0c;腾讯云邮件推送如何设置呢&#xff1f;又有哪些群发邮件的技巧呢&#xff1f;下面AokSend就来详细探讨一下。 …

AI预测体彩排列3第2套算法实战化测试第5弹2024年4月27日第5次测试

今天继续进行新算法的测试&#xff0c;今天是第5次测试。好了&#xff0c;废话不多说了&#xff0c;直接上图上结果。 2024年4月27日体彩排3预测结果 6码定位方案如下&#xff1a; 百位&#xff1a;6、2、1、7、8、9 十位&#xff1a;8、9、4、3、1、0 个位&#xff1a;3、7、8…

Python 数组控件的使用

当一个UI窗口界面内有多个相同类型的控件&#xff0c;且这多个控件的功能都类似时&#xff0c;使用数组控件是一个非常不错的选择&#xff0c;可以大大减少代码的编写 且 代码易读性强&#xff0c;可惜的是Python好象是没有数组控件这个东东。 我们来看看以下一个界面&#xff…

生成完美口型同步的 AI 代言人视频(及其实现原理详解)

目录 什么是Heygen? Heygen注册 Video Translation&#xff08;视频翻译 完美口型同步&#xff09; 实现原理详解 视频翻译部分 完美口型同步部分 什么是Heygen? Heygen是一款在线工具&#xff0c;可帮助您生成具有完美口型同步的 AI 代言人视频。 Heygen注册 https:…

SpringBoot 缓存

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 目录 一、缓存的作用二、SpringBoot启用缓存三…

循迹/跟随/摇头避障小车

循迹小车 智能小车2-循迹小车-CSDN博客 接线 B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10 循迹模块(左) -- PB3 循迹模块(右) -- PB4 CubeMx 在CubeMx配置,并重定义,在main.h会自动生成 #define B_1A_Pin GPIO_PIN_0 #define B_1A_GPIO_Port GPIOB #defi…

【开发问题记录】启动某个服务时请求失败(docker-componse创建容器时IP参数不正确)

问题记录 一、问题描述1.1 产生原因1.2 产生问题 二、问题解决2.1 找到自己的docker-compose.yml文件2.2 重新编辑docker-compose.yml文件2.3 通过docker-componse重新运行docker-compose.yml文件2.4 重新启动docker容器2.5 查看seata信息 一、问题描述 1.1 产生原因 因为我是…

【国标语音对讲】EasyCVR视频汇聚平台海康/大华/宇视摄像头GB28181语音对讲配置

一、背景分析 近年来&#xff0c;国内视频监控应用发展迅猛&#xff0c;系统接入规模不断扩大&#xff0c;涌现了大量平台提供商&#xff0c;平台提供商的接入协议各不相同&#xff0c;终端制造商需要给每款终端维护提供各种不同平台的软件版本&#xff0c;造成了极大的资源浪…

嵌入式学习58-ARM7(字符设备驱动框架led)

知识零碎&#xff1a; kernel 内核 printk 内核打印 cat /proc/devices insmod …

LINUX系统编程:软硬链接,动静态连接

1.硬连接 什么是硬连接?,我们或许可以用操作清楚的认识什么是硬连接。 在我们学习文件的时候这个数字好像完全没有被提到过&#xff0c;这个代表什么意思呢&#xff1f; 这个代表该文件的inode编号与文件映射的次数&#xff0c;现在该文件的inode只与test.c这个文件名映射&a…

使用grasshopper修改梁的起始点方向

一般北方向朝上的情况&#xff0c;梁的方向从南向北&#xff0c;从西向东。 现在使用grasshopper来判断起始点坐标&#xff0c;分辨是否错误。 交换起始点这个&#xff0c;我实在不会用电池操作&#xff0c;只好敲python代码实现了。代码如下&#xff1a; 如果会敲代码的同学…

Git | 远程操作

Git | 远程操作 文章目录 Git | 远程操作0、分布式版本控制系统概念1、创建远程仓库2、克隆远程仓库https方式ssh方式 3、推送至远程仓库4、本地拉取远程仓库5、配置Git忽略特殊文件给命令配置别名 6、标签管理创建标签操作标签 0、分布式版本控制系统概念 Git是一个分布式版本…

【小迪安全2023】第58天:服务攻防-应用协议设备KibanaZabbix远控向日葵VNCTV

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

RPA机器人怎么操作知乎好物推荐自动点击【添加】商品按钮?

先看需要实现的效果&#xff08;启动机器人-点击收益&#xff08;打开商品卡片列表&#xff09;-点击添加&#xff08;自动添加商品卡片到文章&#xff09;&#xff09;&#xff1a; 学员提问&#xff1a; 知乎上点击好物推荐【添加】商品按钮&#xff0c;iframe的元素是动态的…

力扣每日一题-查询网格图中每一列的宽度-2024.4.27

力扣题目&#xff1a;查询网格图中每一列的宽度 题目链接: 2639.查询网格图中每一列的宽度 题目描述 代码思路 双层for循环遍历整个矩阵容易想到&#xff0c;只要能想到使用整数转字符串的技巧&#xff08;“” 字符串&#xff09;&#xff0c;即可完成题目 代码纯享版 c…

基于SpringBoot + Vue实现的家政服务管理系统设计与实现+毕业论文+答辩PPT+指导搭建视频(包运行成功)

目录 项目介绍 论文展示 资源获取 项目介绍 家政服务管理平台是一个管理信息系统&#xff0c;为了宣传的需要&#xff0c;为了给用户提供方便快捷的服务&#xff0c;从而设计了家政服务管理平台。管理员可以通过这个系统把家政服务信息发布出去&#xff0c;可以方便用户快…