循序渐进之(五)空间域图像增强之自适应直方图均衡化(AHE)

文字摘自:对比度受限的自适应直方图均衡化(CLAHE)

直方图均衡化(HE)是一种很常用的直方图类方法,基本思想是通过图像的灰度分布直方图确定一条映射曲线,用来对图像进行灰度变换,以达到提高图像 对比度的目的。该映射曲线其实就是图像的累计分布直方图(CDF)(严格来说是呈正比例关系)。然而HE是对图像全局进行调整的方法,不能有效地提高局部 对比度,而且某些场合效果会非常差。如:

上述原图和HE结果图的直方图分别为:

因为从原图的直方图中求取的映射函数(CDF)形状为:

将它作用于原图像会导致直方图被整体右移,没有充分利用整个灰度动态范围。

为了提高图像的局部对比度,有人提出将图像分成若干子块,对子块进行HE处理,这便是AHE(自适应直方图均衡化),使用AHE处理上图得到:

结果直方图:

可 以看出结果图像的灰度较好地分布在了全部动态范围上。从结果图像上也可以看出,局部对比度的确得到了提高,视觉效果要优于HE。但是仍然有个问题:AHE 对局部对比度提高过大,导致图像失真。看看背景区,本来的黑色背景现在已经变成白色了,原因是因为背景区中的局部子块统计得到的直方图在0灰度处幅值太高 (实际上全黑子图基本上就集中在0灰度处),这样导致映射曲线斜率过高,将所有灰度值都映射到整个灰度轴的右侧,所以结果图中背景偏白。

(上边的AHE算法实现的图像处理效果为添加了线性插值功能,这里代码实现的AHE,暂时没有加入线性插值功能,所以可以看出图像分块)

代码参考:CLAHE的实现和研究   中的AHE算法部分。

#include<iostream>
#include<opencv.hpp>
using namespace std;
using namespace cv;
int main()
{Mat originImage = imread("E://匹配.jpg", 0);imshow("原图", originImage);Mat src = originImage.clone();const int blockNumber = 8;//把图像分成block数量int width = src.cols;int height = src.rows;int singleBlockWidth = src.cols / 8;//每个block大小int singleBlockHeight = src.rows / 8;int pixelNumber[blockNumber *blockNumber][256] = { 0 };//存储不同block中各个不同灰度像素数量float total[blockNumber *blockNumber][256] = { 0.0 };//累计直方图for (int i = 0; i < blockNumber; i++){for (int j = 0; j < blockNumber; j++){int startPixelW = (i)*singleBlockWidth;int endPixelW = (i+1)*singleBlockWidth;int startPixelH = (j)*singleBlockHeight;int endPixelH = (j+1)*singleBlockHeight;int number = i + 8 * j;//统计运算到哪一个block了int singleBlockPixelNumber = singleBlockWidth*singleBlockHeight;for (int x = startPixelW; x < endPixelW; x++)//统计不同block中各个不同灰度像素数量for (int y = startPixelH; y < endPixelH; y++){int pixelValue = src.at<uchar>(y, x);pixelNumber[number][pixelValue]++;}for (int k = 0; k < 256; k++)//计算累计直方图{if (k == 0)total[number][k] = 1.0*pixelNumber[number][k] / singleBlockPixelNumber;elsetotal[number][k] = total[number][k - 1] + 1.0*pixelNumber[number][k] / singleBlockPixelNumber;}}}for (int i = 0; i < blockNumber; i++)//利用累计直方图对于原像素灰度在各自block中进行映射{for (int j = 0; j < blockNumber; j++){int startPixelW = (i)*singleBlockWidth;int endPixelW = (i+1)*singleBlockWidth;int startPixelH = (j)*singleBlockHeight;int endPixelH = (j+1)*singleBlockHeight;int number = i + 8 * j;int singleBlockPixelNumber = singleBlockWidth*singleBlockHeight;for (int x = startPixelW; x < endPixelW; x++)for (int y = startPixelH; y < endPixelH; y++){int pixelValue = src.at<uchar>(y, x);src.at<uchar>(y, x) = total[number][pixelValue] * 255;}}}imshow("均衡图", src);waitKey(0);return 0;
}

效果如下:

加入线性插值功能,代码参考:CLAHE的实现和研究 中的CLAHE算法部分(这里的线性插值代码好像较为复杂,后续看有没有更简便的实现手段)。。

#include<iostream>
#include<opencv.hpp>
using namespace std;
using namespace cv;
int main()
{Mat originImage = imread("E://匹配.jpg", 0);imshow("原图", originImage);Mat src = originImage.clone();Mat src1 = originImage.clone();const int blockNumber = 8;//把图像分成block数量int width = src.cols;int height = src.rows;int singleBlockWidth = src.cols / 8;//每个block大小int singleBlockHeight = src.rows / 8;int pixelNumber[blockNumber *blockNumber][256] = { 0 };//存储不同block中各个不同灰度像素数量float total[blockNumber *blockNumber][256] = { 0.0 };//累计直方图for (int i = 0; i < blockNumber; i++){for (int j = 0; j < blockNumber; j++){int startPixelW = (i)*singleBlockWidth;int endPixelW = (i + 1)*singleBlockWidth;int startPixelH = (j)*singleBlockHeight;int endPixelH = (j + 1)*singleBlockHeight;int number = i + 8 * j;//统计运算到哪一个block了int singleBlockPixelNumber = singleBlockWidth*singleBlockHeight;for (int x = startPixelW; x < endPixelW; x++)//统计不同block中各个不同灰度像素数量for (int y = startPixelH; y < endPixelH; y++){int pixelValue = src.at<uchar>(y, x);pixelNumber[number][pixelValue]++;}for (int k = 0; k < 256; k++)//计算累计直方图{if (k == 0)total[number][k] = 1.0*pixelNumber[number][k] / singleBlockPixelNumber;elsetotal[number][k] = total[number][k - 1] + 1.0*pixelNumber[number][k] / singleBlockPixelNumber;}}}for (int i = 0; i < blockNumber; i++)//利用累计直方图对于原像素灰度在各自block中进行映射{for (int j = 0; j < blockNumber; j++){int startPixelW = (i)*singleBlockWidth;int endPixelW = (i + 1)*singleBlockWidth;int startPixelH = (j)*singleBlockHeight;int endPixelH = (j + 1)*singleBlockHeight;int number = i + 8 * j;int singleBlockPixelNumber = singleBlockWidth*singleBlockHeight;for (int x = startPixelW; x < endPixelW; x++)for (int y = startPixelH; y < endPixelH; y++){int pixelValue = src1.at<uchar>(y, x);src1.at<uchar>(y, x) = total[number][pixelValue] * 255;}}}imshow("均衡图无线性差值", src1);for (int i = 0; i < width; i++){for (int j = 0; j < height; j++){//four coners  if (i <= singleBlockWidth / 2 && j <= singleBlockHeight / 2){int num = 0;src.at<uchar>(j, i) = (int)(total[num][src.at<uchar>(j, i)] * 255);}else if (i <= singleBlockWidth / 2 && (j >= ((blockNumber - 1)*singleBlockHeight +singleBlockHeight / 2))) {int num = blockNumber*(blockNumber - 1);src.at<uchar>(j, i) = (int)(total[num][src.at<uchar>(j, i)] * 255);}else if (i >= ((blockNumber - 1)*singleBlockWidth + singleBlockHeight / 2) && j <=singleBlockHeight / 2) {int num = blockNumber - 1;src.at<uchar>(j, i) = (int)(total[num][src.at<uchar>(j, i)] * 255);}else if (i >= ((blockNumber - 1)*singleBlockWidth + singleBlockWidth / 2) && j >= ((blockNumber - 1)*singleBlockHeight + singleBlockHeight / 2)) {int num = blockNumber*blockNumber - 1;src.at<uchar>(j, i) = (int)(total[num][src.at<uchar>(j, i)] * 255);}//four edges except coners  else if (i <= singleBlockWidth/ 2){//线性插值  int num_i = 0;int num_j = (j -singleBlockHeight / 2) /singleBlockHeight;int num1 = num_j*blockNumber + num_i;int num2 = num1 + blockNumber;float p = (j - (num_j*singleBlockHeight +singleBlockHeight / 2)) / (1.0f*singleBlockHeight);float q = 1 - p;src.at<uchar>(j, i) = (int)((q*total[num1][src.at<uchar>(j, i)] + p*total[num2][src.at<uchar>(j, i)]) * 255);}else if (i >= ((blockNumber - 1)*singleBlockWidth+ singleBlockWidth/ 2)) {//线性插值  int num_i = blockNumber - 1;int num_j = (j -singleBlockHeight / 2) /singleBlockHeight;int num1 = num_j*blockNumber + num_i;int num2 = num1 + blockNumber;float p = (j - (num_j*singleBlockHeight +singleBlockHeight / 2)) / (1.0f*singleBlockHeight);float q = 1 - p;src.at<uchar>(j, i) = (int)((q*total[num1][src.at<uchar>(j, i)] + p*total[num2][src.at<uchar>(j, i)]) * 255);}else if (j <=singleBlockHeight / 2) {//线性插值  int num_i = (i - singleBlockWidth/ 2) / singleBlockWidth;int num_j = 0;int num1 = num_j*blockNumber + num_i;int num2 = num1 + 1;float p = (i - (num_i*singleBlockWidth+ singleBlockWidth/ 2)) / (1.0f*singleBlockWidth);float q = 1 - p;src.at<uchar>(j, i) = (int)((q*total[num1][src.at<uchar>(j, i)] + p*total[num2][src.at<uchar>(j, i)]) * 255);}else if (j >= ((blockNumber - 1)*singleBlockHeight +singleBlockHeight / 2)) {//线性插值  int num_i = (i - singleBlockWidth/ 2) / singleBlockWidth;int num_j = blockNumber - 1;int num1 = num_j*blockNumber + num_i;int num2 = num1 + 1;float p = (i - (num_i*singleBlockWidth+ singleBlockWidth/ 2)) / (1.0f*singleBlockWidth);float q = 1 - p;src.at<uchar>(j, i) = (int)((q*total[num1][src.at<uchar>(j, i)] + p*total[num2][src.at<uchar>(j, i)]) * 255);}//双线性插值else {int num_i = (i - singleBlockWidth/ 2) / singleBlockWidth;int num_j = (j -singleBlockHeight / 2) /singleBlockHeight;int num1 = num_j*blockNumber + num_i;int num2 = num1 + 1;int num3 = num1 + blockNumber;int num4 = num2 + blockNumber;float u = (i - (num_i*singleBlockWidth+ singleBlockWidth/ 2)) / (1.0f*singleBlockWidth);float v = (j - (num_j*singleBlockHeight +singleBlockHeight / 2)) / (1.0f*singleBlockHeight);src.at<uchar>(j, i) = (int)((u*v*total[num4][src.at<uchar>(j, i)] +(1 - v)*(1 - u)*total[num1][src.at<uchar>(j, i)] +u*(1 - v)*total[num2][src.at<uchar>(j, i)] +v*(1 - u)*total[num3][src.at<uchar>(j, i)]) * 255);}//最后这步,类似高斯平滑src.at<uchar>(j, i) = src.at<uchar>(j, i) + (src.at<uchar>(j, i) << 8) + (src.at<uchar>(j, i) << 16);}}imshow("均衡图线性差值", src);waitKey(0);return 0;
}

效果如下:

循序渐进之(五)空间域图像增强之自适应直方图均衡化(AHE)相关推荐

  1. 图像增强:自适应直方图均衡化(AHE)

    文章目录 算法简介 代码实现 效果展示 处理前 处理后 算法简介 自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术.和普通的直方图均衡算法不同,AHE算法通过计算图像的局部直方 ...

  2. OpenCv:直方图均衡化(HE),自适应直方图均衡化(AHE),限制对比度自适应直方图均衡化(CLAHE)

    总结了使用Python OpenCv处理图像直方图均衡化(HE),自适应直方图均衡化(AHE),限制对比度自适应直方图均衡化(CLAHE)的方法. 目录 直方图均衡化(HE) 自适应直方图均衡化(AH ...

  3. 自适应直方图均衡化 AHE

    直方图均衡化之后,第二个实验是自适应直方图均衡化. 由于图片明暗分布的问题,对一张图片进行全局的直方图均衡化可能导致明部或者暗部的细节丢失.为了优化均衡化效果,我们对可以对不同区域进行直方图均衡化以获 ...

  4. 图像增强—自适应直方图均衡化(AHE)-限制对比度自适应直方图均衡(CLAHE)

    一.自适应直方图均衡化(Adaptive histgram equalization/AHE) 1.简述 自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术.和普通的直方图均衡算 ...

  5. 【图像处理】——图像增强Python实现直方图均衡化

    目录 一.相关概念 1.灰度直方图概念(hist) 2.灰度概率累积函数(cdf) 3.灰度直方图均衡化(equalizehist) 4.均衡化适用范围 二.均衡化的目的以及求解步骤 1.目的 2.求 ...

  6. 直方图均衡化、自适应直方图均衡化

    一.直方图均衡化 简述 直方图均衡化的英文名称是:Histogram Equalization.  图像对比度增强的方法可以分成两类:一类是直接对比度增强方法;另一类是间接对比度增强方法.直方图拉伸和 ...

  7. 限制对比度自适应直方图均衡化算法原理、实现及效果

    一.自适应直方图均衡化(Adaptive histgram equalization/AHE) 1.简述 自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术.和普通的直方图均衡算 ...

  8. DIP关键算法-自适应直方图均衡化

    1 自适应直方图均衡化(AHE) 自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术.和普通的直方图均衡算法不同,AHE算法通过计算图像的局部直方图,然后重新分布亮度来来改变图像 ...

  9. 限制对比度自适应直方图均衡化

    一.自适应直方图均衡化(Adaptive histgram equalization/AHE) 1.简述 自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术.和普通的直方图均衡算 ...

最新文章

  1. 1004 Counting Leaves (30 分)【难度: 中 / 知识点: 树的遍历】
  2. Azkaban的Web Server源码探究系列20:resolvebuildFlow
  3. js中几种实用的跨域方法原理详解
  4. Java笔记(基础第二篇)
  5. ap drawing 课件_ILITEK TP AP introduction.ppt
  6. 《C++ Primer》13.1.2节练习
  7. 设计模式笔记(24)---访问者模式(行为型)
  8. vue @input带参数_Vue 全家桶开发的一些小技巧和注意事项
  9. aqs clh java_【Java并发编程实战】----- AQS(一):简介
  10. 图像识别(3)---验证码篇
  11. 动态规划之回文串问题
  12. 打败 Python、JS、C# 成最受欢迎编程语言,是时候掌握 Rust 了吗?
  13. vscode vue项目设置代理为locahost 始终无法连接本地项目
  14. Mac OS X 内核Rootkit开发指南
  15. 前鹅厂面试官亲手整理出的高频必问软件测试基础面试题(1)!!!
  16. Excel 多级下拉菜单设置,数据有效性
  17. 通过网页免费下载音乐(F12)
  18. windows下cmd命令(全面)更新版
  19. Python篇:用python画xy散点图
  20. 2019最新iOS面试题及答案

热门文章

  1. 物联卡中心:移动物联卡如何查询套餐?
  2. 如何少花钱又过好日子(转载)
  3. (这种方法简直就是在作弊) 7-25 一位的十六进制转换为十进制 (10 分) java
  4. python基础语法-温度转换
  5. wi-fi以连接但无法上网_Wi-Fi无法扩展以弥合数字鸿沟
  6. 微信公众号、小程序使用注意事项
  7. java基础——包裹类型
  8. 网络摄像机的网络连接
  9. 恢复出厂设置后itms注册失败_宽带注册ITMS失败怎么弄呀?
  10. [ERROR] [MY-010457] [Server] --initialize specified but the data directory has files in it. Aborting