C#,保持亮度的动态直方图均衡化(Brightness Preserving Dynamic Histogram Equalization:BPDHE)源代码

 

图像增强的主要目的是显示隐藏的图像细节,或者用新的动态范围增加图像对比度。直方图均衡(HE)是用于图像对比度增强的最流行的技术之一,因为HE在计算上快速且易于实现。HE通过基于输入灰度级的概率分布重新映射图像的灰度级来执行其操作。然而,HE很少用于视频监控、数码相机和电视等消费电子应用,因为HE往往会引入一些令人讨厌的伪影和不自然的增强,包括强度饱和效应。这个问题的原因之一是HE通常会显著改变图像的亮度,从而使输出图像变得饱和,具有非常亮或暗的强度值。因此,为了增强消费电子产品的图像,亮度保持是需要考虑的一个重要特性。

为了克服HE的局限性并保持图像的亮度,人们提出了几种保持亮度的直方图均衡技术。首先,Kim提出了保持亮度的双直方图均衡(BBHE),BBHE根据输入图像的平均值将输入图像直方图分为两部分,然后独立地对每个部分进行均衡。因此,由于保留了原始平均亮度,所以保留了平均亮度。Wan等人引入了二元子图像直方图均衡(DSIHE),它类似于BBHE,只是输入图像的中值用于直方图分割,而不是平均亮度[5]。Chen和Ramli提出了最小平均亮度误差双直方图均衡(MMBEBHE),这是BBHE方法的扩展,提供了最大的亮度保持。该算法找出原始图像和增强图像之间的最小平均亮度误差。它采用最优点作为分离点,而不是输入图像的平均值或中值。尽管这些方法可以执行良好的对比度增强,但根据直方图中灰度分布的变化,它们也会导致更令人讨厌的副作用。递归平均分离HE(RMSHE)是BBHE的另一个改进版本。该方法递归地将直方图分离为多个子直方图,而不是像BBHE中那样将两个子直方图分离。最初,根据原始直方图的平均亮度创建两个子直方图。随后,来自先前获得的两个子直方图的平均亮度被用作创建更多子直方图的第二和第三分离点。以类似的方式,递归地执行该算法,直到满足所需数量的子直方图。然后,HE方法独立地应用于每个子直方图。前面讨论的方法是基于通过使用中值或平均亮度将原始直方图划分为几个子直方图。尽管上述方法很好地保持了平均亮度,但这些方法不能进一步扩展位于动态范围的最小值或最大值附近的亚直方图区域。然而,它也并非没有副作用,例如褪色的外观、不希望的棋盘效果和图像亮度的显著变化。

为了解决上述问题,Abdullah Al-Wadud等人引入了动态直方图均衡(DHE)技术。DHE基于局部极小值对原始直方图进行分割。然而,DHE并不考虑亮度的保持。为此,Ibrahim和Kong提出了保持亮度的动态直方图均衡(BPDHE)。该方法基于平滑直方图的局部最大值来分割图像直方图。它为每个分区分配一个新的动态范围。最后,对输出强度进行归一化,使所得图像的平均强度等于输入强度。尽管BPHE在平均亮度保持方面表现良好,但亮度归一化的比率起着重要作用。较小的比值会导致不显著的对比度增强。对于大比率(即比率值大于1),最终强度值可能超过输出动态范围的最大强度值。超出的像素将被量化为灰度级的最大强度值,并产生强度饱和问题(在MATLAB环境中)。Sheet等人提出了保持亮度的动态模糊直方图均衡(BPDFHE)。这是BPDFHE的增强版本。BPDFHE技术以这样的方式操纵图像直方图,即不发生直方图峰值的重新映射,而只发生两个连续峰值之间的谷部分中的灰度值的重新分布。使用BPDFHE方法的结果显示出良好的对比度增强和小的伪影。

为了克服不必要的过度增强和噪声放大,提出了基于模糊逻辑的灰度和彩色图像直方图均衡技术。所提出的FHE方法不仅保持了图像的亮度,而且提高了原始图像的局部对比度。首先,利用模糊集理论计算模糊直方图。其次,根据原始图像的中值将模糊直方图一分为二。最后,HE方法被独立地应用于每个子直方图以提高对比度。

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace Legal.Truffer.ImageProcess

{

public partial static class CVUtility
{

    /// <summary>
    /// 直方图均衡化
    /// 保持亮度的动态直方图均衡化(Brightness Preserving Dynamic Histogram Equalization:BPDHE)
    /// </summary>
    /// <param name="src"></param>
    /// <returns></returns>
    public static Mat Equalization_BPDHE(Mat src)
    {
        double[] B = new double[256];
        for (int k = 0; k < 255; k++)
        {
            int t1 = 0, t2 = 0, t3 = 0;
            for (int m = 0; m < src.Rows; m++)
            {
                for (int n = 0; n < src.Cols; n++)
                {
                    if (src.At<Vec3b>(m, n)[0] == k) t1 = t1 + 1;
                    if (src.At<Vec3b>(m, n)[1] == k) t2 = t2 + 1;
                    if (src.At<Vec3b>(m, n)[2] == k) t3 = t3 + 1;
                }
            }

            int t = t1 + t2 + t3;
            double b = 1.0f / (src.Rows * src.Cols * 3.0);
            double x = t * b;
            B[k] = x;
        }

        double[] T1 = new double[256];
        for (int i = 1; i < 256; i++)
        {
            for (int j = 1; j < i; j++)
            {
                T1[i - 1] = B[j - 1] + T1[i - 1];
            }
        }

        double[] T2 = new double[256];
        for (int i = 1; i < 256; i++)
        {
            T2[i - 1] = Math.Round((T1[i - 1] * 255) + 0.5);
        }

        Mat bpdhe = new Mat();
        src.CopyTo(bpdhe);
        for (int i = 0; i < 255; i++)
        {
            for (int j = 0; j < src.Rows; j++)
            {
                for (int k = 0; k < src.Cols; k++)
                {
                    if (bpdhe.At<Vec3b>(j, k)[0] == i)
                        bpdhe.At<Vec3b>(j, k)[0] = (byte)T2[i];
                    if (bpdhe.At<Vec3b>(j, k)[1] == i)
                        bpdhe.At<Vec3b>(j, k)[1] = (byte)T2[i];
                    if (bpdhe.At<Vec3b>(j, k)[2] == i)
                        bpdhe.At<Vec3b>(j, k)[2] = (byte)T2[i];
                }
            }
        }

        return bpdhe;
    }
}

}


http://www.niftyadmin.cn/n/472346.html

相关文章

作为产品经理,你需要具备这些能力

作为一名产品经理&#xff0c;除了具备想象力和创造力外&#xff0c;更需要具备将想法转化为可行性方案并推进实现的能力&#xff0c;以及快速确立目标并排除困难的能力。在项目管理方面&#xff0c;你需要具备以下能力&#xff1a; 产品规划能力&#xff1a;你需要比其他人更…

Spring Boot中的@EnableAutoConfiguration注解

Spring Boot中的EnableAutoConfiguration注解 介绍 Spring Boot是一个非常流行的Java框架&#xff0c;它可以快速创建基于Spring的应用程序。Spring Boot提供了许多自动配置功能&#xff0c;使得开发者可以非常容易地创建一个可运行的应用程序。其中&#xff0c;EnableAutoCo…

使用CSS的polygon属性画各个方向的半圆环

CSS的polygon属性 CSS polygon()函数是一个图形函数&#xff0c;用于指定某种基本图形类型。polygon()函数用于定义一个多边形 .container{width: 50px;height: 50px;border: 13px solid #0c73fe;border-radius: 50px;/* 上半圆环 */clip-path: polygon(100% 50%, 0 50%, 0 0, …

直流恒流源电路分析-运放恒流源设计

7种直流恒流源电路分析 传感器及发光器件常需恒流源供电&#xff0c;精确测量微小电阻一般也要用到恒流源。恒流源的本质是其具有调节负载两端电压的能力&#xff0c;凡具有电压调整能力的器件均可构成恒流源&#xff0c;包括运放、稳压芯片、三极管、MOS管等。下面以运放和电…

前端 baseUrl 通过 自己现在浏览器的 ip port 来拼, 不需要在换环境或者port的时候改来改去

前端 baseUrl 通过 自己现在浏览器的 ip port 来拼, 不需要在换环境或者port的时候改来改去 let url window.location.href; let urlStr url.split(/); let parts urlStr[2].split(:) let ip parts[0]let port parts[1]let baseUrl http://${ip}:${port}/api

Java - 使用 JSON 序列化/反序列化深拷贝解决方案

问题描述 今天遇到一个深拷贝的问题&#xff0c;之前也调研过很多个深拷贝工具类&#xff0c;但是发现后期有各种问题。 原因分析 FastClone&#xff1a;因为无参构造问题&#xff0c;对部分类型无法序列化&#xff0c;比如&#xff1a;Boolean 等Kryo&#xff1a;因为无参构…

QString与基本数据类型如何转换?(Qt面试题)

QString与基本数据类型的转换 在 Qt 中&#xff0c;可以使用以下方法将 QString 转换为基本数据类型&#xff1a; 将 QString 转换为整数类型&#xff08;int&#xff09;&#xff1a;可以使用 QString 类的 toInt() 方法。例如&#xff1a; QString str "123"; …

【Java|多线程与高并发】线程池详解

文章目录 1. 线程池简介2. 创建线程池3. 工厂模式简介4. 线程池的使用5. 实现线程池6. ThreadPoolExecutor的构造方法讲解7. 线程池的线程数量,如何确定? 1. 线程池简介 Java线程池是一种用于管理和重用线程的机制&#xff0c;它可以在需要执行任务时&#xff0c;从线程池中获…