当前位置: 首页 > 编程日记 > 正文

灰度图像直方图均衡化公式及实现

图像的直方图:直方图是图像中像素强度分布的图形表达方式。它统计了每一个强度值所具有的像素个数

直方图均衡化:是通过拉伸像素强度分布范围来增强图像对比度的一种方法。是图像处理领域中利用图像直方图对对比度进行调整的方法。

均衡化指的是把一个分布(给定的直方图)映射到另一个分布(一个更宽更统一的强度值分布),所以强度值分布会在整个范围内展开。映射函数应该是一个累积分布函数(cumulative distribution function(cdf))。

直方图均衡化是通过调整图像的灰阶分布,使得在0~255灰阶上的分布更加均衡,提高了图像的对比度,达到改善图像主观视觉效果的目的。对比度较低的图像适合使用直方图均衡化方法来增强图像细节。

这种方法通常用来增加许多图像的全局对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景噪声的对比度并且降低有用信号的对比度。

灰度直方图均衡化算法实现步骤:

(1)、统计原始图像各灰度级的像素数目ni,0≤i<L, L是图像中所有的灰度数(通常为256);

(2)、图像中灰度为i的像素的出现概率是:px(i)=p(x=i)=ni/n,n是图像中所有的像素数,px(i)实际上是像素值为i的图像的直方图,归一化到[0, 1];

(3)、px的累积分布函数,是图像的累计归一化直方图:


(4)、直方图均衡化计算公式, cdfmin为累积分布函数最小值,M和N分别代表了图像的长宽像素个数,而L则是灰度级数(如图像为8位深度,则灰度级别共有2^8=256级数,这也是最常见的灰度级数),v为原始图像中为v的像素值:


彩色图像直方图均衡化:上面描述了灰度图像上使用直方图均衡化的方法,但是通过将这种方法分别用于图像RGB颜色值的红色、绿色和蓝色分量,从而也可以对彩色图像进行处理。实际上,对彩色分量rgb分别做均衡化,会产生奇异的点,图像不和谐。一般采用的是用yuv空间进行亮度的均衡即可。

以上内容主要参考:维基百科

以下是分别采用C++和OpenCV实现的code,从执行结果可知,C++和OpenCV的结果完全一致:

histogram_equalization.cpp:

#include "funset.hpp"
#include <chrono>
#include <vector>
#include <algorithm>
#include "common.hpp"int histogram_equalization_cpu(const unsigned char* src, int width, int height, unsigned char* dst, float* elapsed_time)
{//TIME_START_CPUconst int hist_sz{ 256 };std::vector<int> hist(hist_sz, 0), lut(hist_sz, 0);for (int y = 0; y < height; ++y) {for (int x = 0; x < width; ++x) {++hist[src[y * width + x]];}}int i{ 0 };while (!hist[i]) ++i;int total{ width * height };if (hist[i] == total) {unsigned char* p = dst;std::for_each(p, p + total, [i](unsigned char& value) { value = i; });return 0;}float scale = (hist_sz - 1.f) / (total - hist[i]);int sum = 0;for (lut[i++] = 0; i < hist_sz; ++i) {sum += hist[i];lut[i] = static_cast<unsigned char>(sum * scale + 0.5f);}for (int y = 0; y < height; ++y) {for (int x = 0; x < width; ++x) {dst[y * width + x] = static_cast<unsigned char>(lut[src[y * width + x]]);}}//TIME_END_CPUreturn 0;
}
main.cpp:

#include "funset.hpp"
#include <random>
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <algorithm>
#include "common.hpp"int test_image_process_histogram_equalization()
{const std::string image_name{ "E:/GitCode/CUDA_Test/test_data/images/lena.png" };cv::Mat mat = cv::imread(image_name, 0);CHECK(mat.data);const int width{ mat.cols/*1513*/ }, height{ mat.rows/*1473*/ };cv::resize(mat, mat, cv::Size(width, height));std::unique_ptr<unsigned char[]> data1(new unsigned char[width * height]), data2(new unsigned char[width * height]);float elapsed_time1{ 0.f }, elapsed_time2{ 0.f }; // millisecondsCHECK(histogram_equalization_cpu(mat.data, width, height, data1.get(), &elapsed_time1) == 0);//CHECK(histogram_equalization_gpu(mat.data, width, height, data2.get(), &elapsed_time2) == 0);//fprintf(stdout, "image histogram equalization: cpu run time: %f ms, gpu run time: %f ms\n", elapsed_time1, elapsed_time2);cv::Mat dst;cv::equalizeHist(mat, dst);cv::imwrite("E:/GitCode/CUDA_Test/test_data/images/histogram_equalization.png", dst);CHECK(compare_result(data1.get(), dst.data, width*height) == 0);//CHECK(compare_result(data1.get(), data2.get(), width*height) == 0);save_image(mat, dst, width, height/2, "E:/GitCode/CUDA_Test/test_data/images/histogram_equalization_result.png");return 0;
}
执行结果:




GitHub: https://github.com/fengbingchun/CUDA_Test

相关文章:

超越最新无监督域自适应方法,研究人员提轻量CNN新架构OSNet

作者 | Kaiyang Zhou, Xiatian Zhu, Yongxin Yang, Andrea Cavallaro, and Tao Xiang 译者 | TroyChang 编辑 | Jane 出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; CNN新架构OSNet 【导读】今天推荐论文《Learning Generalisable Omni-Scale Repre…

在一台机器上搭建多个redis实例

2019独角兽企业重金招聘Python工程师标准>>> 默认Redis程序安装在/usr/local/redis目录下&#xff1b; 配置文件&#xff1a;/usr/local/redis/redis.conf&#xff0c;该配置文件中配置的端口为默认端口&#xff1a;6379&#xff1b; Redis的启动命令路径&#xff1…

使用kaptcha生成验证码

2019独角兽企业重金招聘Python工程师标准>>> kaptcha是一个简单好用的验证码生成工具&#xff0c;通过配置&#xff0c;可以自己定义验证码大小、颜色、显示的字符等等。下面就来讲一下如何使用kaptcha生成验证码以及在服务器端取出验证码进行校验。 一、搭建测试环…

主成分分析(PCA) C++ 实现

主成分分析(Principal Components Analysis, PCA)简介可以参考&#xff1a; http://blog.csdn.net/fengbingchun/article/details/78977202以下是PCA的C实现&#xff0c;参考OpenCV 3.3中的cv::PCA类。使用ORL Faces Database作为测试图像。关于ORL Faces Database的介绍可以参…

为何Google、微软、华为将亿级源代码放一个仓库?从全球最大代码管理库说起...

作者 | 夕颜编辑 | Just出品 | AI 科技大本营&#xff08;ID:rgznai100&#xff09;【导读】2017 年&#xff0c;在当时微软的一篇官方博客中&#xff0c;时任微软云开发服务副总裁的 Brian Harry 表示微软内部代码开始向 Git 迁移&#xff0c;宣布推出针对大规模 repo 的“Git…

jquery mobie导致超链接不可用

在a标签中添加rel"external"即可转载于:https://blog.51cto.com/here2142/1435434

编译器GCC与Clang的异同

GCC&#xff1a;GNU(Gnus Not Unix)编译器套装(GNU Compiler Collection&#xff0c;GCC)&#xff0c;指一套编程语言编译器&#xff0c;以GPL及LGPL许可证所发行的自由软件&#xff0c;也是GNU项目的关键部分&#xff0c;也是GNU工具链的主要组成部分之一。GCC(特别是其中的C语…

如何正确选择聚类算法? | CSDN博文精选

作者 | Josh Thompson翻译 | 张睿毅校对 | 王雨桐来源 | 数据派THU&#xff08;ID:DatapiTHU&#xff09;本文将介绍四种基本的聚类算法—层次聚类、基于质心的聚类、最大期望算法和基于密度的聚类算法&#xff0c;并讨论不同算法的优缺点。聚类算法十分容易上手&#xff0c;但…

Python工具 | 9个用来爬取网络站点的 Python 库

1️⃣Scrapy 一个开源和协作框架&#xff0c;用于从网站中提取所需的数据。 以快速&#xff0c;简单&#xff0c;可扩展的方式。 官网2️⃣cola 一个分布式爬虫框架。 GitHub3️⃣Demiurge 基于 PyQuery 的爬虫微型框架。 官网4️⃣feedparser 通用 feed 解析器。 官网5️⃣Gra…

Python并发编程实例教程

有关Python中的并发编程实例,主要是对Threading模块的应用,文中自定义了一个Threading类库。 一、简介  我们将一个正在运行的程序称为进程。每个进程都有它自己的系统状态&#xff0c;包含内存状态、打开文件列表、追踪指令执行情况的程序指针以及一个保存局部变量的调用栈。…

Nginx负载均衡之TCP端口高可用(二)

在前面我们实现了基本的HTTP反向代理&#xff0c;从互联网过来的请求已经可以分发到后端多台网站服务器上&#xff0c;但不是所有的业务都是网络类型的&#xff0c;此篇文章我们主要讨论的是TCP 端口的负载均衡做法&#xff0c;昨天也有小伙伴提到了&#xff0c;在HTTP反向代理…

语音识别大牛Daniel Povey为何加入小米?“手机+AIoT”强大生态,开源战略是关键...

整理 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;10 月 17 日&#xff0c;语音识别开源工具 Kaldi 创始人&#xff0c;语音和 AI 领域大牛 Daniel Povey 在10 月 19 日&#xff0c;小米集团副总裁、集团技术委员会主席崔宝秋发布微博&#xff0c;欢迎 Dani…

Python运维项目中用到的redis经验及数据类型

先感叹下&#xff0c;学东西一定要活学活用&#xff01; 我用redis也有几年的历史了&#xff0c;今个才想到把集合可以当python list用。 最近做了几个项目都掺杂了redis&#xff0c; 遇到了一些个问题和开发中提高性能的方法&#xff0c;这都分享出来&#xff0c;共同学习。…

图像边缘检测之拉普拉斯(Laplacian)C++实现

拉普拉斯算子(Laplacian)可应用到图像边缘检测中。在OpenCV中当kernel大小为3*3时&#xff0c;支持两种kernel算子&#xff0c;分别为&#xff1a;在OpenCV中默认的计算方式如下&#xff0c;假设有一个5*5的小图像&#xff0c;原始值依次为1,2,…25,如下图红色部分&#xff0c;…

从0到1,Airbnb的深度学习实践经验总结

作者 | Haldar译者 | 陆离出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;此前&#xff0c;AI科技大本营发布了关于希望通过介绍的研究成果为读者提供一些有用的帮助和指引。模型中的生态系统本文要讨论的机器学习现实应用&#xff0c;是关于根据用户预约的可能性来…

高并发大流量专题---8、动态语言的并发处理

高并发大流量专题---8、动态语言的并发处理 一、总结 一句话总结&#xff1a; 和本科毕业论文连起来了&#xff1a;基于消息中间件Rocket MQ的研究&#xff1b;用于并发处理的消息队列 1、什么是进程、线程、协程&#xff1f; 进程&#xff08;Process&#xff09;是计算机中的…

1. 文件系统——磁盘分区、各目录功能、硬盘

一、磁盘分区及文件访问入口在前文中介绍过&#xff0c;Linux的整个文件系统像一棵倒置的数&#xff0c;最顶层的是根文件系统&#xff0c;其下有很多一级子目录&#xff0c;一级子目录下面是二级子目录&#xff0c;依此类推&#xff1a;/&#xff1a;根目录/bin&#xff0c;/s…

吴恩达老师深度学习视频课笔记:逻辑回归公式推导及C++实现

逻辑回归(Logistic Regression)是一个二分分类算法。逻辑回归的目标是最小化其预测与训练数据之间的误差。为了训练逻辑回归模型中的参数w和b&#xff0c;需要定义一个成本函数(cost function)。成本函数(cost function)&#xff1a;它是针对整个训练集的。衡量参数w和b在整个训…

网络运行时间提高100倍,Google使用的AI视频理解架构有多强?

译者 | 刘畅出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;视频理解是一个很有挑战性的问题。由于视频包含时空数据&#xff0c;因此图像的特征表示需要同时提取图像和运动信息。这不仅对自动理解视频语义内容有重要性&#xff0c;还对机器人的感知和学习也至关重要…

iOS学习笔记(十三)——获取手机信息(UIDevice、NSBundle、NSLocale)

2019独角兽企业重金招聘Python工程师标准>>> iOS的APP的应用开发的过程中&#xff0c;有时为了bug跟踪或者获取用反馈的需要自动收集用户设备、系统信息、应用信息等等&#xff0c;这些信息方便开发者诊断问题&#xff0c;当然这些信息是用户的非隐私信息&#xff0…

吴恩达老师深度学习视频课笔记:单隐含层神经网络公式推导及C++实现(二分类)

关于逻辑回归的公式推导和实现可以参考&#xff1a; http://blog.csdn.net/fengbingchun/article/details/79346691 下面是在逻辑回归的基础上&#xff0c;对单隐含层的神经网络进行公式推导&#xff1a;选择激活函数时的一些经验&#xff1a;不同层的激活函数可以不一样。如果…

「2019中国大数据技术大会」超值学生票来啦!

大会官网&#xff1a;https://t.csdnimg.cn/U1wA经过11年的沉淀与发展&#xff0c;中国大数据技术大会见证了大数据技术生态在中国的建立、发展和成熟&#xff0c;已经成为国内大数据行业极具影响力的盛会&#xff0c;也是大数据人非常期待的年度深度分享盛会。在新的时代背景下…

校验正确获取对象或者数组的属性方法(babel-plugin-idx/_.get)

背景&#xff1a; 开发中经常遇到取值属性的时候&#xff0c;需要校验数值的有效性。 例如&#xff1a; 获取props对象里面的friends属性 props.user && props.user.friends && props.user.friends[0] && props.user.friends[0].friends 对于深层的对…

Ring Tone Manager on Windows Mobile

2019独角兽企业重金招聘Python工程师标准>>> 手机铃声经常能够体现一个人的个性&#xff0c;有些哥们儿在自习室不把手机设置成震动&#xff0c;一来电就#$^%^&^%#$&$*&#xff0c;声音还很大&#xff0c;唯恐别人听不到。 Windows Mobile设备上如何来设置手…

OpenCV3.3中K-Means聚类接口简介及使用

OpenCV3.3中给出了K-均值聚类(K-Means)的实现&#xff0c;即接口cv::kmeans&#xff0c;接口的声明在include/opencv2/core.hpp文件中&#xff0c;实现在modules/core/src/kmeans.cpp文件中,其中&#xff1a;下面对此接口中的参数作个简单说明&#xff1a;(1)、data&#xff1a…

一文读懂对抗机器学习Universal adversarial perturbations | CSDN博文精选

作者 | Icoding_F2014来源 | CSDN博客本文提出一种 universal 对抗扰动&#xff0c;universal 是指同一个扰动加入到不同的图片中&#xff0c;能够使图片被分类模型误分类&#xff0c;而不管图片到底是什么。示意图&#xff1a;形式化的定义&#xff1a;对于d维数据分布 μ&…

Reactor模式与Proactor模式

博主一脚刚踏进分布式的大门&#xff08;看《分布式Java应用》&#xff0c;如果大家有啥推荐的书欢迎留言~&#xff09;&#xff0c;发现书中对NIO采用的Reactor模式、AIO采用的Proactor模式一笔带过&#xff0c;好奇心趋势我找了一下文章&#xff0c;发现两篇挺不错的文章&…

linux下使profile和.bash_profile立即生效的方法

使profile生效的方法1.source /etc/profile使用.bash_profile生效的方法1 . .bash_profile2 source .bash_profile3 exec bash --login转载于:https://blog.51cto.com/shine20/1436473

吴恩达老师深度学习视频课笔记:多隐含层神经网络公式推导(二分类)

多隐含层神经网络的推导步骤非常类似于单隐含层神经网络的步骤&#xff0c;只不过是多重复几遍。关于单隐含层神经网络公式的推导可以参考&#xff1a; http://blog.csdn.net/fengbingchun/article/details/79370310 逻辑回归是一个浅层模型(shadow model)&#xff0c;或称单层…

Python中的元编程:一个关于修饰器和元类的简单教程

作者 | Saurabh Kukade译者 | 刘畅出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;最近&#xff0c;作者遇到一个非常有趣的概念&#xff0c;它就是用 Python 进行元编程。我想在本文中分享我对该主题的见解。作者希望它可以帮助解决这个问题&#xff0c;因为很多人说…