OpenCV 直方图概念,直方图均衡化原理详解

文章目录

  • 直方图相关概念
    • 颜色灰度级
    • 作用
    • 应用场景
  • C++ 使用OpenCV绘制直方图
    • 单通道直方图
      • 关键代码分析:
        • `calcHist`函数分析
        • 使用OpenCV API来绘制直方图
      • 效果图:
    • 彩色三通道直方图
      • 效果图:
  • 直方图均衡化概念
    • 均衡化作用
    • 均衡化效果
    • 均衡化数学原理
      • 步骤
      • 数学公式
      • 示例
    • OpenCV 直方图均衡化 API

直方图相关概念

直方图(Histogram)是一种图表,用于显示数据集的分布情况。它通过将数据范围划分为若干个连续的区间(称为“桶”或“箱”—bins),然后统计每个区间内的数据点数量,以条形图的形式展示这些数量。横轴表示数据的取值范围,纵轴表示每个区间内数据点的数量或频率。例如下图(转载自025 - 二维直方图_哔哩哔哩_bilibili)

在这里插入图片描述

颜色灰度级

  • 灰度级:在灰度图像中,每个像素的亮度值,可以是0到255之间的整数,其中0表示黑色,255表示白色,中间的值表示不同程度的灰色。
  • 直方图:一种柱状图,用于表示每个灰度级在图像中出现的频率。

作用

  1. 图像分析:直方图可以帮助分析图像的整体亮度分布,了解图像是过暗、过亮还是对比度适中。
  2. 图像增强:通过直方图均衡化等技术,可以增强图像的对比度,使图像细节更加清晰。
  3. 图像分割:在图像处理和计算机视觉中,可以利用直方图来确定图像的阈值,进行目标和背景的分割。
  4. 图像对比度调整:根据直方图调整图像对比度,使图像更符合视觉需求。

应用场景

  1. 医学影像处理:在医学图像(如X射线、CT、MRI)中,通过直方图分析可以增强图像,帮助医生更好地诊断。
  2. 摄影和图像编辑:摄影师和图像编辑软件利用直方图调整图像的曝光、对比度和颜色分布,以达到理想的视觉效果。
  3. 监控系统:在监控图像中,直方图可以帮助调整图像质量,使得图像在不同光照条件下保持较好的可见性。
  4. 计算机视觉:在目标检测、识别和跟踪中,直方图作为特征描述子之一,可以用于比较和匹配图像。

C++ 使用OpenCV绘制直方图

单通道直方图

顾名思义,就是分析单通道图像的亮度分布情况,一般用于灰度图像,下方代码,则是展示了分析三通道图像的其中一个通道的直方图

void show_hist_demo(Mat &image){Mat hist;vector<Mat> bgr_channels;split(image,bgr_channels);int histSize = 256; // 从 0 到 255float range[] = { 0, 256 }; // 强度范围 灰度等级const float* histRange = { range };  // calcHist支持分析多张图片,这里只提供一张图片,因此,只传入一个范围数组。分析多张图片,往后添加范围数组即可calcHist(&bgr_channels[0], 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);// 绘制直方图int hist_w = 512, hist_h = 400;int bin_w = cvRound((double) hist_w / histSize);Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(0, 0, 0));  // 空白图像 用来显示结果normalize(hist, 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(hist.at<float>(i - 1))),Point(bin_w * i, hist_h - cvRound(hist.at<float>(i))),Scalar(255), 2, 8, 0);}imshow("Source image", image);imshow("Histogram", histImage);waitKey(0);
}

关键代码分析:

vector<Mat> bgr_channels;
split(image,bgr_channels);

将一张彩色三通道图像分离成三个通道 B G R Mat对象。便于下文分析单个通道的分析。

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);

参数介绍

const Mat* images:

  • 这是指向图像数组的指针,可以处理单张或多张图像。在单通道或者多通道图像的处理中,这个数组将包含所有需要计算直方图的图像。

int nimages:

  • 这个参数指定了 images 数组中图像的数量。例如,如果你只处理一张图像,这个值就应该是 1。

const int* channels:

  • 这是一个包含了需要计算直方图的通道索引的数组。例如,对于 BGR 图像,如果你只想计算蓝色通道的直方图,你可以传递 0。

InputArray mask:

  • 这是一个可选参数,用于定义一个掩码。如果掩码非空,函数将只计算掩码内像素的直方图。这可以用于计算图像特定区域的直方图。

OutputArray hist:

  • 这是一个输出参数,用来存储计算得到的直方图。通常,这是一个多维数组,其中每个维度对应于一个通道或一个特定的直方图轴。

int dims:

  • 这指定了直方图的维度数量。对于简单的灰度图像直方图,这个值是 1。对于包含多个通道的图像,这个值可以更高。

const int* histSize:

  • 这是一个数组,指定了每个维度的 bin 数量。例如,如果你在每个颜色通道上想有 256 个 bins,你可以传递 {256, 256, 256}

const float\** ranges:

  • 这是一个指向数组的指针,数组中每个元素定义了直方图的值范围。对于标准的 8 位图像,这通常是 {0, 256}

bool uniform:

  • 这个布尔值指定直方图是否均匀。如果为 true,表示所有的 bin 的宽度都是相同的。这通常可以提高计算的效率。

bool accumulate:

  • 如果这个值被设为 true,则直方图在调用时不会被清空。这允许从多个数组中累积直方图,或者用于时间上连续的直方图更新。

举个栗子

 calcHist(&bgr_channels[0], 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);

这行代码则是 只计算通道B(蓝色)像素值分布,只计算一张图片,第一个通道,不需要使用掩码,输出到hist,数量为1维,范围为0-255的灰度等级,使所有的bin的宽度相同,调用完毕之后清空直方图,不进行累计。

使用OpenCV API来绘制直方图

上述代码已经得到了结果,存放在hist 中, 接下来需要创建一个空的图像,将结果绘制上去。

1.首先进行归一化,目的确保 条目的数量不超过空白图像的高度 ,因此将条目的数量 归一到0到最高点的范围之内。

 normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

2.遍历 0-255 每个条目数量,使用 OpenCV line API 绘制到图像中。使用 line 函数绘制直方图时,通过 Point 类创建线的起点和终点。这段代码是用来将计算出的直方图的数据可视化为一个图像。每一次循环中的 line 函数调用都会在直方图图像上绘制一条小线段,这些线段合起来形成了完整的直方图。

bin_w * (i - 1):这计算了当前 bin 的起始水平位置

hist_h - cvRound(hist.at<float>(i - 1)):这计算了线段起点的垂直位置。hist_h 是直方图图像的总高度,hist.at<float>(i - 1) 从直方图数据中获取当前 bin (i-1) 的值(这个值表示该强度值的像素数量),使用 cvRound 将其四舍五入到最近的整数。从 hist_h 中减去这个值将坐标翻转,因为在图像坐标中,y 轴是向下增长的。

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

效果图:

在这里插入图片描述

彩色三通道直方图

可以直接调用calcHist函数输出三个通道的直方图,也可以分三次调用单通道直方图代码,本文采用了后者

void show_dims_hist_demo(Mat &image){// 计算直方图vector<Mat> bgr_channels;split(image,bgr_channels);int histSize = 256; // 从 0 到 255float range[] = { 0, 256 }; // 强度范围 灰度等级const float* histRange = { range };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));  // 使用彩色图像以显示三个通道vector<Scalar> colors = {Scalar(255, 0, 0), Scalar(0, 255, 0), Scalar(0, 0, 255)};  // 蓝、绿、红for (int c = 0; c < 3; c++) {Mat hist;calcHist(&bgr_channels[c], 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);normalize(hist, 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(hist.at<float>(i - 1))),Point(bin_w * i, hist_h - cvRound(hist.at<float>(i))),colors[c], 2, 8, 0);}}imshow("Histogram", histImage);waitKey(0);
}

与单通道唯一不同的是,调用了for循环,绘制了三条曲线代表 B G R 三个通道

效果图:

在这里插入图片描述

直方图均衡化概念

直方图均衡化(Histogram Equalization)是一种图像处理技术,用于增强图像的对比度。其目的是通过调整灰度级分布,使得图像的灰度级在直方图上的分布更加均匀,从而提升图像的视觉效果

均衡化作用

  1. 增强图像对比度:通过均衡化,原本对比度较低的图像可以变得更加清晰,细节更加明显。
  2. 改善图像质量:直方图均衡化可以使图像在视觉上更加均衡和舒适,特别是在光照条件不佳的情况下。
  3. 提高图像处理算法的效果:许多图像处理和计算机视觉算法在对比度较高的图像上表现更好,直方图均衡化可以作为预处理步骤提高这些算法的性能。

均衡化效果

左边为原始图像,右边为均衡化之后的图像

在这里插入图片描述

均衡化数学原理

直方图均衡化的数学原理涉及图像的累积分布函数(CDF)和灰度级映射。以下是其具体步骤和公式:

步骤

  1. 计算图像的直方图
    设原始图像有 (N) 个像素,每个像素的灰度级范围为 (0) 到 (L-1),计算每个灰度级 (i) 的像素数量 (n_i),并得到图像的概率密度函数(PDF):
    p ( i ) = n i N , i = 0 , 1 , 2 , … , L − 1 p(i) = \frac{n_i}{N}, \quad i = 0, 1, 2, \ldots, L-1 p(i)=Nni,i=0,1,2,,L1

  2. 计算累积分布函数(CDF)
    累积分布函数 (c(i)) 是概率密度函数 (p(i)) 的累加和:
    c ( i ) = ∑ j = 0 i p ( j ) , i = 0 , 1 , 2 , … , L − 1 c(i) = \sum_{j=0}^{i} p(j), \quad i = 0, 1, 2, \ldots, L-1 c(i)=j=0ip(j),i=0,1,2,,L1

  3. 映射旧灰度级到新灰度级
    利用累积分布函数将旧的灰度级 (i) 映射到新的灰度级 (i’),映射关系为:
    i ′ = ⌊ ( L − 1 ) ⋅ c ( i ) ⌋ i' = \left\lfloor (L-1) \cdot c(i) \right\rfloor i=(L1)c(i)
    向下取整

  4. 生成均衡化后的图像
    使用上述映射关系,将原始图像中的每个像素灰度级 (i) 映射为新的灰度级 (i’),得到均衡化后的图像。

数学公式

设原始图像的灰度级为 (X),均衡化后的灰度级为 (Y),其关系可以表示为:
Y = T ( X ) Y = T(X) Y=T(X)
其中 T(X) 是映射函数,定义为:
T ( X ) = ( L − 1 ) ⋅ ∫ 0 X p ( x ) d x T(X) = (L-1) \cdot \int_{0}^{X} p(x) \, dx T(X)=(L1)0Xp(x)dx

对于离散情况,映射关系可以写为:

Y i = ( L − 1 ) ⋅ ∑ j = 0 i p ( j ) Y_i = (L-1) \cdot \sum_{j=0}^{i} p(j) Yi=(L1)j=0ip(j)

示例

假设一个简单的8位灰度图像,其灰度级范围为 (0) 到 (255)。原始图像的灰度直方图如下:

灰度级 (i)像素数量 (n_i)概率密度函数 (p(i))累积分布函数 (c(i))新灰度级 (i’)
05000.050.0512
110000.100.1538
215000.150.3076
320000.200.50127
415000.150.65165
510000.100.75191
65000.050.80204
75000.050.85217
85000.050.90229
95000.050.95242
105000.051.00255

根据上述表格,新灰度级的映射关系已经确定,可以用于生成均衡化后的图像。

直方图均衡化通过这种方式重新分配灰度级,使得图像的整体对比度得到增强,从而使图像细节更加清晰。

OpenCV 直方图均衡化 API

OpenCV 提供了用于直方图均衡化的函数 equalizeHist。这个函数可以对单通道(通常是灰度图像)进行直方图均衡化

使用示例

int main()
{string imagePath = "C:\\Users\\Marxist\\Pictures\\coco\\raw_lenna.jpg";string video_path = "C:\\Users\\Marxist\\Videos\\Captures\\gtr.mp4";Mat image = imread(imagePath,IMREAD_GRAYSCALE);if(image.empty()){cout<<"file not exist!"<<endl;return -1;}Mat dst;equalizeHist(image,dst);imshow("raw image",image);imshow("equalizeHist image",dst);waitKey(0);return 0;
}

注: equalizeHist 只能用于单通道。可以对彩色图像的每个通道分别进行直方图均衡化,或更常见的是将彩色图像转换到 YCrCb 或 HSV 色彩空间,在亮度通道上应用直方图均衡化,然后再转换回 RGB 色彩空间。

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

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

相关文章

Linux中进程间通信--匿名管道和命名管道

本篇将会进入 Linux 进程中进程间通信&#xff0c;本篇简要的介绍了 Linux 中进程为什么需要通信&#xff0c;进程间通信的常用方式。然后详细的介绍了 Linux 进程间的管道通信方式&#xff0c;管道通信分为匿名管道和命名管道&#xff0c;本篇分别介绍了其实现的原理&#xff…

基于VMware(虚拟机) 创建 Ubunton24.04

目录 1.设置 root 密码 2. 防火墙设置 2.1 安装防火墙 2.2 开启和关闭防火墙 2.3 开放端口和服务规则 2.4 关闭端口和删除服务规则 2.5 查看防火墙状态 3. 换源 3.1 源文件位置 3.2 更新软件包 1. 设置网络 1. 在安装ubuntu时设置网络 2.在配置文件中修改 2.设置 r…

17_高级进程间通信 UNIX域套接字1

非命名的UNIX域套接字 第1个参数domain&#xff0c;表示协议族&#xff0c;只能为AF_LOCAL或者AF_UNIX&#xff1b; 第2个参数type&#xff0c;表示类型&#xff0c;只能为0。 第3个参数protocol&#xff0c;表示协议&#xff0c;可以是SOCK_STREAM或者SOCK_DGRAM。用SOCK_STR…

HTTP 缓存

缓存 web缓存是可以自动保存常见的文档副本的HTTP设备&#xff0c;当web请求抵达缓存时&#xff0c;如果本地有已经缓存的副本&#xff0c;就可以从本地存储设备而不是从原始服务器中提取这个文档。使用缓存有如下的优先。 缓存减少了冗余的数据传输缓存环节了网络瓶颈的问题…

MySQL学习之InnoDB引擎,索引

Mysql中的引擎 我们先来看一下MySql提供的有哪些引擎 mysql> show engines; 从上图我们可以查看出 MySQL 当前默认的存储引擎是InnoDB,并且在5.7版本所有的存储引擎中只有 InnoDB 是事务性存储引擎&#xff0c;也就是说只有 InnoDB 支持事务。 查看MySQL当前默认的存储引…

算法力扣刷题记录 五十一【654.最大二叉树】

前言 二叉树篇&#xff0c;继续。 记录 五十一【654.最大二叉树】 一、题目阅读 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。…

套接字编程一(简单的UDP网络程序)

文章目录 一、 理解源IP地址和目的IP地址二、 认识端口号1. 理解 "端口号" 和 "进程ID"2. 理解源端口号和目的端口号 三、 认识协议1. 认识TCP协议2. 认识UDP协议 四、 网络字节序五、 socket编程接口1. socket 常见API2. sockaddr结构&#xff08;1&#…

WebGIS的Web服务概述

WebGIS是互联网技术应用于GIS开发的产物&#xff0c;是现代GIS技术的重要组成部分&#xff0c;其中的Web服务是现代WebGIS的核心技术和重要标志&#xff0c;它集GIS、程序组件和互联网的优点于一身&#xff0c;深刻改变了GIS开发和应用的方式&#xff0c;绕过了本地数据转换和本…

Unity 批处理详讲(含URP)

咱们在项目中&#xff0c;优化性能最重要的一个环节就是合批处理&#xff0c;&#xff0c;在早期Unity中&#xff0c;对于合批的处理手段主要有三种&#xff1a; Static Batching Dynamic Batching GPU Instancing 如今Unity 为了提升合批范围与效率&#xff0c;提供了…

ICT测试原理

目录&#xff1a; 一、什么是ICT 二、ICT在哪使用 三、ICT如何测试 1、隔离(Guarding)原理 2、电容器测试原理 3、电感器测试原理 4、普通二极管测试方法(MODE D) 5、晶体管的测量原理 (三端点)(MODE TR) 6、短/开路的测试原理 1&#xff09;学习短路表 2&#xff…

基于chrome插件的企业应用

一、chrome插件技术介绍 1、chrome插件组件介绍 名称 职责 访问权限 DOM访问情况 popup 弹窗页面。即打开形式是通过点击在浏览器右上方的icon&#xff0c;一个弹窗的形式。 注: 展示维度 browser_action:所有页面 page_action:指定页面 可访问绝大部分api 不可以 bac…

【数据结构】排序算法——Lessen1

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

【动态专修】2024年五菱维修手册和电路图资料更新

经过整理&#xff0c;2017-2024年五菱汽车全系列已经更新至汽修帮手资料库内&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表…

人、智能、机器人……

在遥远的未来之城&#xff0c;智能时代如同晨曦般照亮了每一个角落&#xff0c;万物互联&#xff0c;机器智能与人类智慧交织成一幅前所未有的图景。这座城市&#xff0c;既是科技的盛宴&#xff0c;也是人性与情感深刻反思的舞台。 寓言&#xff1a;《智光与心影》 在智能之…

Python自动化DevOps任务入门

目录 Python自动化DevOps任务入门 一、环境和工具配置 1. 系统环境与Python版本 2. 虚拟环境搭建 3. 必要的库安装 二、自动化部署 1. 使用Fabric进行流式部署 2. 使用Ansible编写部署剧本 三、持续集成和测试 1. 配置CI/CD工具 选择工具 配置工具 构建和测试自动…

【SLAM】最最最简单的直线拟合情形下的多种求解方法

本文我们讨论一个最最最简单情况下的拟合的情形&#xff0c;并尝试使用不同的方法来进行求解。 假如有一组数 x 1 , x 2 , x 3 , . . . , x n x_1,x_2,x_3,...,x_n x1​,x2​,x3​,...,xn​&#xff0c;对应的值为 y 1 , y 2 , y 3 , . . . , y n y_1,y_2,y_3,...,y_n y1​,y2…

10.11和10.8那个大(各种ai的回答)

问题&#xff1a;10.11和10.8两个数哪个大 腾讯混元 ✔️ chatGPT ❎ 通义千问 ❎ 文心一言 ✔️ 智谱清言 ❎ 讯飞星火 ✔️ C知道 ❎ 豆包 ✔️

TCP粘包问题详解和解决方案【C语言】

1.什么是TCP粘包 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输协议&#xff0c;它保证了数据的可靠性和顺序性。然而&#xff0c;由于TCP是基于字节流而不是消息的&#xff0c;因此在传输过…

【接口自动化_08课_Pytest+Yaml+Allure框架】

上节课一些内容 的补充 1、openxl这个方法&#xff0c;第一个元素是从1开始的&#xff0c;不是从0开始 回写的列在程序里写的是11&#xff0c;是因为是固定值 一、1. Yaml入门及应用 1、什么是yaml YAML&#xff08;/ˈjməl/&#xff0c;尾音类似camel骆驼&#xff09;是一…

Finding columns with a useful data type 找到合适的数据列的类型

Finding columns with a useful data type 在确定了原始查询的数据列数之后&#xff0c;接下来就是要确定合适的数据列的数据类型。可以用 SELECT a 的方式判断对应的数据列方式&#xff0c;有时候可以通过错误信息判断数据列的类型。如果服务器的响应没有报错&#xff0c;而…