OpenCV直方图计算

 返回: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 exclusiveconst 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 exclusiveconst 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.mzph.cn/bicheng/4156.shtml

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

相关文章

网络安全实训Day24(End)

写在前面 并没有完整上完四个星期&#xff0c;老师已经趁着清明节假期的东风跑掉了。可以很明显地看出这次持续了“四个星期”实训的知识体系并不完整&#xff0c;内容也只能算是一次基础的“复习”。更多的内容还是靠自己继续自学吧。 网络空间安全实训-渗透测试 文件包含攻击…

用 C 语言进行大模型推理:探索 llama2.c 仓库(一)

文章目录 前提有关huggingface社区chinese-baby-llama2llama2.cexport.py读取模型信息重建模型对重建出的模型初始化权重导出run.c要求的.bin文件 tokenizer.py 一些思考参考链接 前提 最近发现了一个只用c语言就可以推理大模型的仓库llama2.c&#xff0c;作者是openAI的员工。…

把私有数据接入 LLMs:应用程序轻松集成 | 开源日报 No.236

run-llama/llama_index Stars: 29.9k License: MIT llama_index 是用于 LLM 应用程序的数据框架。 该项目解决了如何最佳地利用私有数据增强 LLMs&#xff0c;并提供以下工具&#xff1a; 提供数据连接器&#xff0c;以摄取现有的数据源和各种格式&#xff08;API、PDF、文档…

vite加密打包插件(vite-plugin-javascript-obfuscator)选项(option)详解

本文主要介绍vite加密打包插件(vite-plugin-javascript-obfuscator)选项(option)。 目录 一、选项(option)1. compact2. config3. controlFlowFlattening4. controlFlowFlatteningThreshold5. deadCodeInjection6. deadCodeInjectionThreshold7. debugProtection8.debugProtect…

【每日刷题】Day23

【每日刷题】Day23 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 138. 随机链表的复制 - 力扣&#xff08;LeetCode&#xff09; 2. 链表的回文结构_牛客题霸_牛客网 …

MySQL从入门到高级 --- 2.DDL基本操作

文章目录 第二章&#xff1a;2.基本操作 - DDL2.1 数据库的常用操作创建数据库选择要操作的数据库删除数据库修改数据库编码 2.2 表结构的常用操作创建表格式查看当前数据库的所有表名称查看指定某个表的创建语句查看表结构删除表 2.3 修改表结构添加列修改列名和类型删除列修改…

python之excel加工处理小案例一则

一、工具用途 工作中&#xff0c;需要对各类excel进行加工处理&#xff0c;当表和字段比较多时&#xff0c;关联条件又有多个&#xff0c;每次通过execl的vlookup之类的关联公式手工可以解决工作需求&#xff0c;但一般耗时较长&#xff0c;且人工统计匹配也存在出错的情况。 …

cnpm安装

npm install -g cnpm --registryhttps://registry.npmmirror.com # 注册模块镜像 npm set registry https://registry.npmmirror.com // node-gyp 编译依赖的 node 源码镜像 npm set disturl https://npmmirror.com/dist // 清空缓存 npm cache clean --force // 安装c…

深入理解操作系统与计算机体系结构

文章目录 操作系统(Operator System)为什么要有操作系统操作系统是如何进行管理的为什么说操作系统是安全&#xff0c;稳定&#xff0c;高效的理解系统调用和库函数 操作系统(Operator System) 概念&#xff1a; 操作系统&#xff08;Operating System&#xff0c;简称OS&…

一文整理完MySQL关系型数据库相关知识

MySQL关系型数据库 1. 介绍1.1 MySQL 2. 安装3. SQL语句4. SQL分类5. DDL5.1 库的DDL5.2 表、列的DDL 6. DML6.1 添加数据6.2 修改数据6.3 删除数据 7. DQL7.1 基础查询7.2 条件查询7.3 排序查询7.4 聚合函数7.5 分组查询7.6 分页查询 8. 约束8.1 约束分类 9. 多表查询9.1 内连…

Vue阶段练习:tab栏、进度条、购物车

阶段练习旨在学习完Vue 指令、计算属性、侦听器-CSDN博客后&#xff0c;进行自我检测&#xff0c;每个练习分为效果显示、需求分析、静态代码、完整代码、总结 四个部分&#xff0c;效果显示和准备代码已给出&#xff0c;我们需要完成“完整代码”部分。 目录 练习1&#xff1…

【经验分享】MySQL集群部署一:主从模式

目录 前言一、基本介绍1.1、概念1.2、执行流程 二、部署2.1、通用配置2.2、主节点配置2.3、从节点配置2.4、主从测试2.5、谈一谈主节点历史数据同步问题 前言 MySQL的部署模式常见的包括以下几种&#xff1a; 独立服务器部署主从复制部署高可用性集群&#xff08;HA&#xff…

(mac)Promethues监控之mysqld_exporter(MySQL监控)

搭建Mysqld_exporterPrometheusGrafana监控系统 普罗米修斯是后端数据监控平台&#xff0c;通过Mysqld_exporter收集mysql数据&#xff0c;Grafana将数据用图形的方式展示出来 前提&#xff1a;已安装grafana和promethues 1.下载安装Mysql &#xff08;1&#xff09;启动MySQL…

基于51单片机的电梯仿真系统

基于51单片机的电梯设计 &#xff08;仿真&#xff0b;程序PPT&#xff09; 功能介绍 具体功能&#xff1a; 1.一共4层&#xff0c;数码管显示当前楼层&#xff1b; 2.六个按键模拟电梯外按键&#xff08;1上、2上、2下、3上、3下、4下&#xff09;&#xff0c;每当按下时有…

循环单链表的介绍与操作

定义 区别 链表合并 整合代码 typedef struct node{int data;node* next;; }lnode,*linklist; lnode* n; linklist l;//定义 void init(linklist &l){lnode lnew lnode;l->nextl;lnode *rl; } //单循环链表的合并 linklist merge(linklist &a,linklist b){//存头结…

debian配置distcc分布式编译

前言 distcc 是一个用于在网络上的多台机器上分发 C、C、Objective C 或 Objective C 代码构建的程序。 distcc 应始终生成与本地构建相同的结果&#xff0c;易于安装和使用&#xff0c;并且通常比本地编译快得多。 distcc 不要求所有机器共享文件系统、同步时钟或安装相同的…

数据结构 - 队列 [动画+代码注释超详解],萌新轻松上手!!!

一. 队列的概念 队列是一种特殊的线性表&#xff0c;用于存储元素&#xff0c;并且按照先进先出(First In First Out)的顺序进行管理&#xff0c;这意味着最先加入队列的元素将会是最先从队列中被移除的元素 队列的原型&#xff1a;只允许在一端进行插入数据的操作&#xff0c…

HTTP、模块化

HTTP协议 包括请求行、请求头、请求体 http常见请求方法&#xff1a; url统一资源请求符&#xff0c;其本身也是一个字符串 响应体的内容格式是非常灵活的,常见的响应体格式有: 1.HTML 2.CSS 3. JavaScript 4.图片 5.视频 6.JSON 响应状态码&#xff1a; IP本身是一个数字…

20240427纳米多孔石墨烯力学性能的调控

文献来源&#xff1a;Tuning the mechanical properties of nanoporous graphene: a molecular dynamics study DOI&#xff1a;https://orcid.org/0000-0003-3598-5439 结论&#xff1a;在这项工作中&#xff0c;使用经典MD模拟分析了扶手椅和锯齿形的NPG&#xff08;纳米多…

Ubuntu2004 CMake 使用基础

一、环境安装 win10安装wsl ubuntu2004 #windows c盘工程目录建立软链 ln -s /mnt/c /home/vrviu/ 安装cmake、c编译工具 apt install -y cmake g 二、CMakeLists.txt讲解 准备工作 首先&#xff0c;在/home/vrviu 目录建立一个 cmake 目录 以后我们所有的 cmake 练习都会放…