局部自适应图像增强

OpenCv,局部自适应图像增强(Local Adaptive Contrast Enhancement)

转载自:https://blog.csdn.net/EbowTang/article/details/42373081

一、理论

         图像增强算法的基本原则是“降低低频区域,突出高频区域”,以此强化边缘,达到增强的目的。最简单的例子就是通过原始图像减去高斯模糊处理后的图像,就能够将边缘强化出来。

         直方图均衡化也是一种非常常见的增强方法。但是为了避免背景的干扰,更倾向于采用“局部”方法进行处理。我们这里着重研究自适应对比度增强(ACE)的相关内容。

        ACE的定义和原理看上去还是比较简单的。这里的都可以根据图像本身计算出来。而则需要单独计算。

          可以为单独的常量,或者通过来代替。这里的D是一个全局的值,比如平均值。

二、实现

        涉及到局部的运算,自然而然会想到使用卷积的方法。更好的是Opencv提供了专门的函数用来做这个工作—BLUR

文档中写到:

 
  1. bool ACE_Enhance(cv::Mat& src_img, cv::Mat& dst_img, unsigned int half_winSize, double Max_Q);

  2. double GetMeanValue(cv::Mat& src_img);

  3. double GetVarianceValue(cv::Mat& src_img, double MeanVlaue);

  4.  
  5. //************************************************************************

  6. // 函数名称: ACE_Enhance

  7. // 访问权限: public

  8. // 创建日期: 2016/11/23

  9. // 创 建 人:

  10. // 函数说明: 单通道增强

  11. // 函数参数: cv::Mat & src_img 输入图像

  12. // 函数参数: cv::Mat & dst_img 输出图像

  13. // 函数参数: unsigned int half_winSize 增强窗口的半窗大小

  14. // 函数参数: double Max_Q 最大Q值

  15. // 返 回 值: bool

  16. //************************************************************************

  17. bool ACE_Enhance(Mat& src_img, Mat& dst_img, unsigned int half_winSize, double Max_Q)

  18. {

  19. if (!src_img.data)

  20. {

  21. cout << "没有输入图像" << endl;

  22. return false;

  23. }

  24.  
  25. int rows(src_img.rows);

  26. int cols(src_img.cols);

  27. unsigned char* pdata = nullptr;

  28. unsigned char* pdata1 = nullptr;

  29. cv::Mat tmpDstImg(rows, cols, CV_8UC1, cv::Scalar::all(0));

  30.  
  31. for (int i = half_winSize; i < (rows - half_winSize); i++)

  32. {

  33. pdata = tmpDstImg.ptr<unsigned char>(i);

  34. pdata1 = src_img.ptr<unsigned char>(i);

  35. for (int j = half_winSize; j < (cols - half_winSize); j++)

  36. {

  37. cv::Mat tempArea = src_img(cv::Rect(j - half_winSize, i - half_winSize, half_winSize * 2 + 1, half_winSize * 2 + 1)); //截取窗口图像

  38. double MeanVlaue = GetMeanValue(tempArea);//平均值

  39. double varian = GetVarianceValue(tempArea, MeanVlaue);//均方差

  40. if (varian > 0.1)

  41. {

  42. double cg = 100.0 / sqrt(varian);

  43. cg = cg > Max_Q ? Max_Q : cg;

  44. double pixelvalue = cg*((double)pdata1[j] - MeanVlaue);

  45.  
  46. int tempValue = MeanVlaue + pixelvalue;

  47. tempValue = tempValue > 255 ? 255 : tempValue;

  48. tempValue = tempValue < 0 ? 0 : tempValue;

  49. pdata[j] = tempValue;

  50. }

  51. }

  52. }

  53. dst_img = tmpDstImg;

  54.  
  55. return true;

  56. }

  57.  
  58. //************************************************************************

  59. // 函数名称: GetMeanValue

  60. // 访问权限: public

  61. // 创建日期: 2016/11/18

  62. // 创 建 人:

  63. // 函数说明: 获取图像的平均灰度值

  64. // 函数参数: cv::Mat & src_img 输入图像

  65. // 返 回 值: double

  66. //************************************************************************

  67. double GetMeanValue(Mat& src_img)

  68. {

  69. if (CV_8UC1 != src_img.type())

  70. {

  71. return -1.0;

  72. }

  73.  
  74. int rows(src_img.rows); //height

  75. int cols(src_img.cols); //width

  76. unsigned char* data = nullptr;

  77. double PixelValueSum(0.0); //总共的像素值

  78.  
  79. for (int i = 0; i < rows; i++)

  80. {

  81. data = src_img.ptr<unsigned char>(i);

  82. for (int j = 0; j < cols; j++)

  83. {

  84. PixelValueSum += (double)data[j];

  85. } //计算图像的总共像素值

  86. }

  87.  
  88. double result(PixelValueSum / static_cast<double>(rows*cols)); //计算图像的均值

  89.  
  90. return result;

  91. }

  92.  
  93. //

  94. // 函数名称: GetVarianceValue

  95. // 访问权限: public

  96. // 创建日期: 2016/11/18

  97. // 创 建 人:

  98. // 函数说明: 计算图像的均方差

  99. // 函数参数: cv::Mat & src_img 输入图像

  100. // 函数参数: double MeanVlaue 图像的均值

  101. // 返 回 值: double

  102. //

  103. double GetVarianceValue(Mat& src_img, double MeanVlaue)

  104. {

  105. if (CV_8UC1 != src_img.type())

  106. {

  107. return -1.0;

  108. }

  109.  
  110. int rows(src_img.rows); //height

  111. int cols(src_img.cols); //width

  112. unsigned char* data = nullptr;

  113. double PixelValueSum(0.0); //总共的像素值

  114.  
  115. for (int i = 0; i < rows; i++)

  116. {

  117. data = src_img.ptr<unsigned char>(i);

  118. for (int j = 0; j < cols; j++)

  119. {

  120. PixelValueSum += pow((double)(data[j] - MeanVlaue), 2);

  121. } //计算图像方差

  122. }

  123.  
  124. double result(PixelValueSum / static_cast<double>(rows*cols)); //计算图像的均方差

  125.  
  126. return result;

  127. }

程序保留:

 
  1. #include <stdio.h>

  2. #include <iostream>

  3. #include "fftw3.h"

  4. #include <stdlib.h>

  5. #include <string.h>

  6. #include <limits.h>

  7.  
  8. #include "string"

  9. #include "vector"

  10. #include <windows.h>

  11. #include <opencv2/legacy/legacy.hpp>

  12. #include <opencv2/nonfree/nonfree.hpp>//opencv_nonfree模块:包含一些拥有专利的算法,如SIFT、SURF函数源码。

  13. #include "opencv2/core/core.hpp"

  14. #include "opencv2/features2d/features2d.hpp"

  15. #include "opencv2/highgui/highgui.hpp"

  16. #include <opencv2/nonfree/features2d.hpp>

  17.  
  18. //参考1:基于“局部标准差”的图像增强(原理、算法、代码)

  19. //http://www.cnblogs.com/jsxyhelu/p/4857721.html

  20. //参考2:使用局部标准差实现图像的局部对比度增强算法。

  21. //http://www.cnblogs.com/Imageshop/p/3324282.html

  22. using namespace cv;

  23. using namespace std;

  24.  
  25.  
  26. //点乘法,elementWiseMultiplication

  27. Mat matrixWiseMulti(Mat &m1, Mat &m2){

  28. Mat dst = m1.mul(m2);//注意是对应矩阵位置的元素相乘

  29. return dst;

  30. }

  31. //ACE算法原理:

  32. //ACE算法原理表达式:f(i,j)=Mx(i,j)+G(i,j)*[x(i,j)-Mx(i,j)]

  33. //高频成分:x(i,j)-Mx(i,j),x(i,j)表示当前中心像素,Mx(i,j)表示局部平均值

  34. //增益系数:G(i,j),可以直接令其为系数C(一般总是大于1)

  35. //

  36.  
  37. //图像局部对比度增强算法

  38. //float MaxCG:对高频成分的最大增益值

  39. //int n:局部半径

  40. //int C;对高频的直接增益系数

  41. //Mat src:原图像

  42. Mat ACE(Mat &src, int C = 3, int n = 3, float MaxCG = 7.5){

  43. int rows = src.rows;

  44. int cols = src.cols;

  45.  
  46. Mat meanLocal;

  47. Mat varLocal;

  48. Mat meanGlobal;

  49. Mat varGlobal;

  50.  
  51. blur(src.clone(), meanLocal, Size(n, n));//meanMask为图像局部均值

  52. imshow("低通滤波", meanLocal);

  53. Mat highFreq = src - meanLocal;//高频成分:x(i,j)-Mx(i,j)

  54. imshow("高频成分", highFreq);

  55.  
  56. varLocal = matrixWiseMulti(highFreq, highFreq);

  57. blur(varLocal, varLocal, Size(n, n)); //varMask为此时为图像局部方差

  58. //换算成局部标准差(开根号)

  59. varLocal.convertTo(varLocal, CV_32F);

  60. for (int i = 0; i < rows; i++){

  61. for (int j = 0; j < cols; j++){

  62. varLocal.at<float>(i, j) = (float)sqrt(varLocal.at<float>(i, j));

  63. }

  64. }

  65. meanStdDev(src, meanGlobal, varGlobal); //meanGlobal为全局均值 varGlobal为全局标准差,实际均是一个数

  66. Mat gainArr =0.5 * meanGlobal / varLocal;//增益系数矩阵:G(i,j),可以直接令其为系数C(一般总是大于1)

  67. /*

  68. for (int i = 0; i < rows; i++){

  69. for (int j = 0; j < cols; j++)

  70. cout<<gainArr.at<float>(i, j)<<" " ;

  71. cout << endl;

  72. if (i == 1)

  73. break;

  74. }*/

  75.  
  76. //对增益矩阵进行截止

  77. for (int i = 0; i < rows; i++){

  78. for (int j = 0; j < cols; j++){

  79. if (gainArr.at<float>(i, j) > MaxCG){

  80. gainArr.at<float>(i, j) = MaxCG;

  81. }

  82. }

  83. }

  84. gainArr.convertTo(gainArr, CV_8U);

  85. gainArr = matrixWiseMulti(gainArr, highFreq);

  86. Mat dst1 = meanLocal + gainArr;

  87. imshow("Lee改进的D方法", dst1);

  88. Mat dst2 = meanLocal + C*highFreq;//直接利用系数C进行高频成分放大

  89. imshow("直接系数C方法", dst2);

  90. return dst2;

  91. }

  92.  
  93.  
  94. Mat myACE(Mat &src, int n = 7, float MaxCG = 7.5){

  95. int rows = src.rows;

  96. int cols = src.cols;

  97. Mat dst(src.rows, src.cols, CV_8UC1, Scalar::all(0));

  98.  
  99. if (src.type() == CV_8UC1)

  100. int aa = src.type();

  101. Mat meanLocal;

  102. Mat varLocal;

  103. Mat meanGlobal;

  104. Mat varGlobal;

  105.  
  106. blur(src.clone(), meanLocal, Size(n, n));//meanMask为图像局部均值

  107. Mat highFreq = src - meanLocal;//高频成分:x(i,j)-Mx(i,j)

  108.  
  109. varLocal = matrixWiseMulti(highFreq, highFreq);

  110. blur(varLocal, varLocal, Size(n, n)); //varMask为此时为图像局部方差

  111. //换算成局部标准差(开根号)

  112. varLocal.convertTo(varLocal, CV_32F);

  113. for (int i = 0; i < rows; i++){

  114. for (int j = 0; j < cols; j++){

  115. varLocal.at<float>(i, j) = (float)sqrt(varLocal.at<float>(i, j));

  116. }

  117. }

  118. meanStdDev(src, meanGlobal, varGlobal); //meanGlobal为全局均值 varGlobal为全局标准差,实际均是一个数

  119. Mat gainArr = 0.5 * meanGlobal / varLocal;//增益系数矩阵:G(i,j),可以直接令其为系数C(一般总是大于1)

  120. //对增益矩阵进行截止

  121. for (int i = 0; i < rows; i++){

  122. for (int j = 0; j < cols; j++){

  123. if (gainArr.at<float>(i, j) > MaxCG){

  124. gainArr.at<float>(i, j) = MaxCG;

  125. }

  126. }

  127. }

  128. gainArr.convertTo(gainArr, CV_8U);

  129. gainArr = matrixWiseMulti(gainArr, highFreq);

  130. dst = meanLocal + gainArr;

  131. //imshow("Lee改进的D方法", dst);

  132. return dst;

  133. }

  134.  
  135. int main()

  136. {

  137. const char* img_path = "oct.bmp";

  138. //const char* img_path = "yanjing.jpg";

  139. //const char* img_path = "luowen.tif";

  140. //const char* img_path = "colors_large.png";

  141. //const char* img_path = "input_0.png";

  142. //const char* img_path = "a1.jpg";

  143. //const char* img_path = "seed.tif";

  144. //const char* img_path = "flyman_gray.bmp";

  145. //const char* img_path = "CT.bmp";

  146. //const char* img_path = "rcc.jpg";

  147. Mat src = imread(img_path, 0);

  148. imshow("src", src);

  149. int n = 50;

  150. float MaxCG = 10.5;

  151. Mat dst=myACE(src,n,MaxCG);

  152. imshow("myACE",dst);

  153. waitKey();

  154. return 0;

  155. }

猜你喜欢

转载自blog.csdn.net/CVAIDL/article/details/82853538
今日推荐