OpenCV图像处理算法——8(直方图均衡化算法及代码实现)

直方图均衡化算法

前言

以下内容引用自:https://zhuanlan.zhihu.com/p/97344840

介绍

直方图均衡化,是对图像进行非线性拉伸,使得一定范围内像素值的数量的大致相同。这样原来直方图中的封顶部分对比度得到了增强,而两侧波谷的对比度降低,输出的直方图是一个较为平坦的分段直方图。具体来讲可以表现为下面这个图:
在这里插入图片描述
通过这种方法可以按照需要对图像的亮度进行调整,并且,这种方法是可逆的,也就是说知道了均衡化函数,也可以恢复原始的直方图。

算法原理

设变量 r r r代表图像中像素灰度级。对灰度级进行归一化处理,即 0 ⩽ r ⩽ 1 0\leqslant r \leqslant 1 0r1,其中 r = 0 r=0 r=0表示黑, r = 1 r=1 r=1表示白。对于一幅给定的图片来说,每个像素在 [ 0 , 1 ] [0,1] [0,1]的灰度级是随机的,用概率密度 p r ( r ) p_r(r) pr(r)来表示图像灰度级的分布。为了有利于数字图像处理,引入离散形式。在离散形式下,用 r k r^k rk代表离散灰度级,用 p r ( r k ) p_r(r^k) pr(rk)代表 p r ( r ) p_r(r) pr(r),并且下式子成立 : : p r ( r k ) = n k n p_r(r^k)=\frac{n^k}{n} pr(rk)=nnk
其中 0 ⩽ r k ⩽ 1 , k = 1 , 2 , ⋅ ⋅ ⋅ , n − 1 0\leqslant r^k \leqslant 1,k=1,2,···,n-1 0rk1,k=1,2,n1。式子中 n k n^k nk代表图像中出现 r k r^k rk这种灰度的像素个数, n n n是图像的总像素个数,图像进行直方图均衡化的函数表达式为: S i = T ( r i ) = ∑ i = 0 k − 1 n i n S_i=T(r_i)=\sum_{i=0}^{k-1}\frac{n_i}{n} Si=T(ri)=i=0k1nni式子中, k k k为灰度级数( R G B RGB RGB图像为 255 255 255)。相应的反变换为 r i = T − 1 ( S i ) r^i=T^{-1}(S_i) ri=T1(Si)

C++代码

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

//直方图均衡化
Mat Histogramequalization(Mat src) {
    int R[256] = { 0 };
    int G[256] = { 0 };
    int B[256] = { 0 };
    int rows = src.rows;
    int cols = src.cols;
    int sum = rows * cols;
    //统计直方图的RGB分布
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            B[src.at<Vec3b>(i, j)[0]]++;
            G[src.at<Vec3b>(i, j)[1]]++;
            R[src.at<Vec3b>(i, j)[2]]++;
        }
    }
    //构建直方图的累计分布方程,用于直方图均衡化
    double val[3] = { 0 };
    for (int i = 0; i < 256; i++) {
        val[0] += B[i];
        val[1] += G[i];
        val[2] += R[i];
        B[i] = val[0] * 255 / sum;
        G[i] = val[1] * 255 / sum;
        R[i] = val[2] * 255 / sum;
    }
    //归一化直方图
    Mat dst(rows, cols, CV_8UC3);
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            dst.at<Vec3b>(i, j)[0] = B[src.at<Vec3b>(i, j)[0]];
            dst.at<Vec3b>(i, j)[1] = B[src.at<Vec3b>(i, j)[1]];
            dst.at<Vec3b>(i, j)[2] = B[src.at<Vec3b>(i, j)[2]];
        }
    }
    return dst;
}

int main()
{
    Mat img, result;
    img = imread("test5.jpg", IMREAD_COLOR);

    namedWindow("Result", WINDOW_AUTOSIZE);

    namedWindow("Origin", WINDOW_AUTOSIZE);

    result = Histogramequalization(img);
    if (result.empty())
    {
        cout << "Error! THE IMAGE IS EMPTY.." << endl;
        return -1;
    }
    else
    {
        imshow("Origin", img);
        imshow("Result", result);
    }

    waitKey(0);
    return 0;
}

效果

在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Delv_Peter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值