直方图均衡化

概念

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

原理

  • 均衡化指的是把一个分布 (给定的直方图) 映射 到另一个分布 (一个更宽更统一的强度值分布),从而令强度值分布会在整个范围内展开。

  • 要想实现均衡化的效果,映射函数应该是一个 累积分布函数 ( cumulative distribution function, cdf ) 。对于直方图 H ( i ) H(i) H(i),它的累积分布函数 H ′ ( i ) H^{'}(i) H(i)

    H ′ ( i ) = ∑ j = 0 i H ( j ) H^{'}(i) = \sum_{j=0}^i H(j) H(i)=j=0iH(j)

    要使用其作为映射函数,我们必须对最大值为255 (或者用图像的最大强度值) 的累积分布 H ′ ( i ) H^{'}(i) H(i) 进行归一化。

  • 最后,我们使用一个简单的映射过程来获得均衡化后像素的强度值,假设原图为 I ( x , y ) I(x,y) I(x,y),均衡化后像素强度值 I ′ ( x , y ) I^{'}(x,y) I(x,y)

    I ′ ( x , y ) = H ′ ( I ( x , y ) ) I^{'}(x,y) = H^{'}(I(x,y)) I(x,y)=H(I(x,y))

代码实现

以 OpenCV 为例,其直方图均衡化函数为 equalizeHist(),代码实现如下:

/** @brief Equalizes the histogram of a grayscale image.

The function equalizes the histogram of the input image using the following algorithm:

- Calculate the histogram \f$H\f$ for src .
- Normalize the histogram so that the sum of histogram bins is 255.
- Compute the integral of the histogram:
\f[H'_i =  \sum _{0  \le j < i} H(j)\f]
- Transform the image using \f$H'\f$ as a look-up table: \f$\texttt{dst}(x,y) = H'(\texttt{src}(x,y))\f$

The algorithm normalizes the brightness and increases the contrast of the image.

@param src Source 8-bit single channel image.
@param dst Destination image of the same size and type as src .
 */
CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );

void cv::equalizeHist( InputArray _src, OutputArray _dst )
{
    CV_INSTRUMENT_REGION();

    CV_Assert( _src.type() == CV_8UC1 );

    if (_src.empty())
        return;

    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
               ocl_equalizeHist(_src, _dst))

    Mat src = _src.getMat();
    _dst.create( src.size(), src.type() );
    Mat dst = _dst.getMat();

    CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_EQUALIZE_HISTOGRAM>(src.cols, src.rows),
               openvx_equalize_hist(src, dst))

    CALL_HAL(equalizeHist, cv_hal_equalize_hist, src.data, src.step, dst.data, dst.step, src.cols, src.rows);

    Mutex histogramLockInstance;

    const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;
    int hist[hist_sz] = {0,};
    int lut[hist_sz];

    EqualizeHistCalcHist_Invoker calcBody(src, hist, &histogramLockInstance);
    EqualizeHistLut_Invoker      lutBody(src, dst, lut);
    cv::Range heightRange(0, src.rows);

    if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))
        parallel_for_(heightRange, calcBody);
    else
        calcBody(heightRange);

    int i = 0;
    while (!hist[i]) ++i;

    int total = (int)src.total();
    if (hist[i] == total)
    {
        dst.setTo(i);
        return;
    }

    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] = saturate_cast<uchar>(sum * scale);
    }

    if(EqualizeHistLut_Invoker::isWorthParallel(src))
        parallel_for_(heightRange, lutBody);
    else
        lutBody(heightRange);
}

应用举例

C++ 代码如下:

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>

using namespace cv;
using std::cout;
using std::endl;

int main(int argc, char** argv)
{
    CommandLineParser parser(argc, argv, "{@input | wukong.png | input image}");
    Mat src = imread(samples::findFile(parser.get<String>("@input")), IMREAD_COLOR);
    if (src.empty())
    {
        cout << "Could not open or find the image!\n" << endl;
        cout << "Usage: " << argv[0] << " <Input image>" << endl;
        return EXIT_FAILURE;
    }

    // 转换为灰度图像
    cvtColor(src, src, COLOR_BGR2GRAY);

    Mat dst;
    // 直方图均衡化
    equalizeHist(src, dst);

    imshow("Source image", src);
    imshow("Equalized Image", dst);

    waitKey();

    return EXIT_SUCCESS;

}

Python 代码如下:

import cv2
import matplotlib.pyplot as plt

# 读取图像
img = cv2.imread('../data/wukong.png', cv2.IMREAD_COLOR)
# 转换为灰度图
src = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 直方图均衡化
dst = cv2.equalizeHist(src)
# 显示原图和均衡化后的图
fig, axes = plt.subplots(2, 2, figsize=(18, 9))
axes[0, 0].imshow(src, cmap='gray')
axes[1, 0].imshow(dst, cmap='gray')
axes[0, 1].hist(src.ravel(), 256, [0, 256], color='#fc8403')
axes[1, 1].hist(dst.ravel(), 256, [0, 256], color='#fc8403')
# 显示直方图网格
axes[0, 1].grid(axis='y', linestyle='-.', alpha=0.5)
axes[1, 1].grid(axis='y', linestyle='-.', alpha=0.5)
# 设置标题
axes[0, 0].set_title('Original Image')
axes[1, 0].set_title('Equalized Image')
axes[0, 1].set_title('Histogram of Original Image')
axes[1, 1].set_title('Histogram of Equalized Image')
# 显示图表
plt.show()

直方图均衡化效果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS知识点详解:div盒子模型

盒子模型&#xff1a; 边框&#xff1a; border-color&#xff1a;边框颜色 border-width&#xff1a;边框粗细 1.thin 2.medium 3.thick 4.像素值 border-width:5px ; border-width:20px 2px; border-width:5px 1px 6px; border-width:1px 3px 5px 2px; 这个简写属性…

Java二十三种设计模式-责任链模式(17/23)

责任链模式&#xff1a;实现请求处理的灵活流转 引言 在这篇博客中&#xff0c;我们深入探讨了责任链模式的精髓&#xff0c;从其定义和用途到实现方法&#xff0c;再到使用场景、优缺点、与其他模式的比较&#xff0c;以及最佳实践和替代方案&#xff0c;旨在指导开发者如何…

基于springboot框架的电影订票系统_wqc3k

TOC springboot611基于springboot框架的电影订票系统_wqc3k--论文 绪 论 1.1研究背景和意义 随着科学技术的不断发展&#xff0c;计算机现在已经成为了社会的必需品&#xff0c;人们通过网络可以获得海量的信息&#xff0c;这些信息可以和各行各业进行关联&#xff0c;电影…

Selenium + Python 自动化测试22(PO+数据驱动)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了PO模式和unittest框架结合起来使用。 本篇文章我们综合一下之前学习的内容&#xff0c;如先将PO模式、数据驱动思想和我们生成HTML报告融合起来&#xff0c;综…

如何应对突发技术故障和危机:开发团队的应急策略

开发团队如何应对突发的技术故障和危机&#xff1f; 在数字化时代&#xff0c;软件服务的稳定性对于企业至关重要。然而&#xff0c;即使是大型平台&#xff0c;如网易云音乐&#xff0c;也可能遇到突发的技术故障。网页端出现502 Bad Gateway 报错&#xff0c;且App也无法正常…

如何生成随机数(通过rand函数,srand函数,time函数深入讲解)

目录 1. 随机数的生成 2. srand函数 3. time函数 4. 设置随机数的范围 1. 随机数的生成 既然是猜数字游戏&#xff0c;那么最终的数字答案肯定是重要的&#xff0c;我们要如何实现这个随机数的生成呢&#xff1f; 在这个功能上&#xff0c;C语言提供了一个函数叫rand&…

数据库多表设计:深入理解一对多、一对一、多对多关系 【后端 12】

数据库多表设计&#xff1a;深入理解一对多、一对一、多对多关系 在数据库设计中&#xff0c;表之间的关系决定了如何组织和存储数据。常见的表关系包括一对多、一对一和多对多。在不同的业务场景下&#xff0c;我们会选择不同的关系模式进行数据库设计。本文将通过具体案例介绍…

Excel技巧(一)

快捷键技巧 原文链接 选取某一行的数据直到最后一行&#xff1a;【CTRL SHIFT ↓ 】或者选取一行后按住SHIFT键&#xff0c;双击下边线就可以快速选取区域。 如果表格中有多行空行&#xff0c;可以先按CTRL SHIFT END&#xff0c;再按CTRL SHIFT 上下键调整&#xff0c;…

网络安全之xss靶场练习

目录 一、xss靶场练习 1、Ma Spaghet! 2、Jefff 第一个方法 第二个方法 3、Ugandan Knuckles 4、Ricardo Milos 5、Ah Thats Hawt 6、Ligma 7、Mafia​编辑 8、Ok, Boomer 一、xss靶场练习 靶场地址 https://xss.pwnfunction.com/ 页面显示如下 1、Ma Spaghet! 分析…

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——6.vector

1.杨辉三角 . - 力扣&#xff08;LeetCode&#xff09; 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>> arr;int i 0;int j 0;for (i…

CSS“叠叠乐”——WEB开发系列16

在现代前端开发中&#xff0c;CSS 是控制网页外观和布局的核心工具。随着项目的复杂化和样式规则的增加&#xff0c;CSS 层叠&#xff08;cascade&#xff09;变得更加重要。为了更好地管理和控制样式规则的应用&#xff0c;CSS 引入了层叠层&#xff08;cascade layers&#x…

Qt入门学什么?

Qt是一个跨平台的C图形用户界面应用程序框架&#xff0c;它为应用程序开发者提供建立图形界面所需的所有功能。Qt框架以其面向对象、易于扩展的特性而受到广泛欢迎&#xff0c;并且支持多种平台&#xff0c;包括桌面、嵌入式和移动平台 。 对于Qt的入门学习&#xff0c;可以通过…

前端3d动画-----平移 transform: translate3d()

必须加这个属性&#xff1a;transform-style: preserve-3d; perspective: 900px; 设置了景深才能感到近大远小的感觉 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible&q…

ESP32 分区表介绍

前言 个人邮箱&#xff1a;zhangyixu02gmail.com关于分区表&#xff0c;很多人看了很多资料很可能依旧是一脸懵逼。不知道各位有没有玩过 EEPROM&#xff0c;他可以断电保存数据。这里你也可以理解为分区表将 Flash 中划分出来了一个 EEPROM。虽然这样说从专业的角度是毫无疑问…

对于llama3.1 8B模型,FP32和BF16混合精度训练,用的是AdamW优化器,模型训练时占用显存分析

目录 为什么先不考虑激活值的显存占用 1. 模型参数 含义 计算 2. 梯度参数 含义 3. 优化器参数 含义 4. 较固定总显存占用 计算 详细解释 5. 激活值计算&#xff1a; 计算公式 插入数值 计算步骤 结论 显存主要被用在四个模块上&#xff1a; 模型权重本身 梯度…

C语言基础(十一)

1、指针&#xff1a; C语言中的指针是一种非常重要的数据类型&#xff0c;可以直接访问和操作内存地址。指针存储变量的内存地址&#xff0c;而不是变量的值本身。通过使用指针&#xff0c;可以灵活地控制数据的存储和访问&#xff0c;实现复杂的数据结构如链表、树。 定义指…

Redis (day 3)

一、通过jedis连接数据库 1.首先导入依赖 <!-- https://mvnrepository.com/artifact/redis.clients/jedis --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>5.1.0</version></de…

Mac系统安装Homebrew【已成功】

1、正常安装失败原因 1.1命令行安装失败 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 原因 没挂&#x1fa9c;&#xff0c;不过我挂了梯子安装很多次也还是失败&#xff0c;所以可能是网站原因 1.2、网…

MyBatis进阶-1-面向接口编程

通过 MyBatis 底层自动创建接口实现类&#xff0c;我们可以直接对接口的方法进行编程 若简单的 sql 语句可以使用注解的方式进行&#xff0c;复杂的查询建议使用 xml 文件编写语句 注解使用时直接在接口的方法上加上对应语句的注解即可&#xff0c;而使用 xml 需要在文件中的…

ES6解构赋值详解;全面掌握:JavaScript解构赋值的终极指南

目录 全面掌握&#xff1a;JavaScript解构赋值的终极指南 一、数组解构赋值 1、基本用法 2、跳过元素 3、剩余元素 4、默认值 二、对象解构赋值 1、基本用法 2、变量重命名 3、默认值 4、嵌套解构 三、复杂的嵌套结构解构 四、函数参数解构赋值 1、对象解构作为函…