OpenCV图像增强---灰度变换直方图均衡化

Posted GraceSkyer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV图像增强---灰度变换直方图均衡化相关的知识,希望对你有一定的参考价值。

图像增强的目的:改善图像的视觉效果或使图像更适合于人或机器的分析处理。通过图像增强,可以减少图像噪声,提高目标与背景的对比度,也可以增强或抑制图像中的某些细节。

 ---------------------------------------------------------------------------------------------------

灰度变换:把原图像的像素灰度经过某个函数变换成新图像的灰度。可分为直线灰度变换法和直方图修正法。

直线灰度变换法:线性、分段线性、非线性变换。

直方图修正法:直方图均衡化、直方图规定化。

 ---------------------------------------------------------------------------------------------------

图像直方图:是对像素的某种属性(如灰度、颜色、梯度等)分布进行统计分析的重要手段。

灰度直方图:是灰度级的函数,它反映了图像中每一灰度级出现的次数或频率。

直方图均衡化:把原始图像的直方图变换为均匀分布的形式,从而增加图像灰度的动态范围,以达到增强图像对比度的效果。

经过均衡化处理的图像,其灰度级出现的概率相同,此时图像的熵最大,图像所包含的信息量最大。

 

【注意,离散后是每块区域的概率相等,均衡化后并不是条直线哦。】

 

 

  细节概念等省略......

---------------------------------------------------------------------------------------------------

 线性灰度增强、对数变换、指数变换、直方图均衡化。代码见下(代码略粗糙...)【ImageEnhance.cpp部分代码】

  1 //线性灰度增强
  2 bool CImageEnhance::GrayLinearTransform(Mat &src, Mat &dst, uchar c, uchar d)  
  3 {  
  4     int b=0,a=255; 
  5     dst = src.clone();
  6     int row = dst.rows, col = dst.cols * dst.channels();
  7     uchar *cc = dst.data;
  8     for(int i = 0; i < row; ++i) {
  9         for(int j = 0; j < col; ++j) {
 10             int val = *cc;
 11             if(a > val) a = val;
 12             if(b < val) b = val;
 13             cc++;
 14         }
 15     }
 16     cc = dst.data;
 17     float k = float(d - c)/(b-a);  
 18     //CString c1; c1.Format(_T("a=%d,b=%d,c=%d,d=%d,k=%.2f\\n"), a,b,c,d,k);MessageBox(c1); 
 19     for(int i = 0; i < row; ++i) {
 20         for(int j = 0; j < col; ++j) {
 21             int val = *cc;
 22             int s = (int)(k*(val - a) + c);
 23             *cc = s;
 24             cc++;
 25         }
 26     }
 27     return true;  
 28 }  
 29 //对数变换 
 30 bool CImageEnhance::GraynoLinearlog(Mat &src, Mat &dst)  { 
 31     dst = src.clone();
 32     int row = dst.rows, col = dst.cols * dst.channels();
 33     uchar *cc = dst.data;
 34     double k = 255 / log10(256.0); 
 35     for(int i = 0; i < row; ++i) {
 36         for(int j = 0; j < col; ++j) {
 37             int val = *cc;
 38             *cc = k * log10(1.0*(val + 1));
 39             cc++;
 40         }
 41     }
 42     return true;  
 43 }  
 44 //指数变换  
 45 bool CImageEnhance::GraynoLinearindex(Mat &src, Mat &dst)  {
 46     dst = src.clone();
 47     int row = dst.rows, col = dst.cols * dst.channels();
 48     uchar *cc = dst.data;
 49     double k = 1.0 / 255; 
 50     for(int i = 0; i < row; ++i) {
 51         for(int j = 0; j < col; ++j) {
 52             int val = *cc;
 53             *cc = k * val * val;    
 54             cc++;
 55         }
 56     }
 57     return true;  
 58 }  
 59 
 60 MatND CImageEnhance::getHist1(Mat& image)
 61 {
 62     MatND hist;
 63     int channels[] = {0};
 64     int dims = 1;
 65     int histSize[] = {256};   //直方图箱子的个数
 66     float granges[] = {0, 255};
 67     const float *ranges[] = {granges};  //像素值范围
 68     //计算直方图
 69     calcHist(&image, 1, channels, Mat()/*不使用掩码*/, hist, dims/*这是一维的直方图*/, histSize, ranges);  
 70     return hist;  //这里得到的hiat是256行一列的Mat
 71 }
 72 
 73 //直方图均衡化
 74 bool CImageEnhance::Equalize_hist(cv::Mat& src,cv::Mat& dst)
 75 {
 76     //CMFC_Test_lyyDlg pic;
 77     MatND hist;
 78     int channels[] = {0};
 79     int dims = 1;
 80     int histSize[] = {256};   //直方图箱子的个数
 81     float granges[] = {0, 255};
 82     const float *ranges[] = {granges};  //像素值范围
 83     //计算直方图
 84     Mat image = src.clone();
 85     calcHist(&image, 1, channels, Mat()/*不使用掩码*/, hist, dims/*这是一维的直方图*/, histSize, ranges);  
 86     
 87     //MatND hist = getHist1(src);//pic.getHist(dst);
 88     float s[256];
 89     float p[256];
 90 
 91     cv::Mat lookup(cv::Size(1, 256), CV_8U);
 92     int pixNum = src.cols * src.rows;//总像素个数
 93     for (int i =0; i <256; i++) {
 94         s[i] = hist.at<float>(i) / pixNum;
 95         if (i ==0) {
 96             p[i] = s[i];
 97         } 
 98         else {
 99             p[i] = p[i -1] + s[i];
100         }
101     }
102     for (int i =0; i <256; i++) {
103         lookup.at <uchar>(i) = static_cast<uchar>(p[i]*255.0);
104     }
105   
106     cv::LUT(src, lookup, dst);//创建矩阵,把一个像素值映射到另一个像素值
107     return true;
108 }
ImageEnhance.cpp

 

效果如下:

原图像:

线性灰度增强:我这里默认a和b表示原图像灰度值的最小与最大值。以下示例取c=255,d=0,效果为使图像负像,即黑变白,白变黑。

  

对数变换:(使图像的低灰度范围得以扩展而高灰度范围得以压缩,变换后的图像更符合人的视觉效果,因为人眼对高亮度的分辨率要求高于对低亮度的分辨率)

  

指数变换:(指数大于1。与对数变换相反。)

 直方图均衡化:

 

 

求原图像的灰度直方图代码:

 

 1 //获得直方图
 2 MatND getHistt(Mat& image){
 3     MatND hist;
 4     int channels[] = {0};
 5     int dims = 1;
 6     int histSize[] = {256};   //直方图箱子的个数
 7     float granges[] = {0, 255};
 8     const float *ranges[] = {granges};  //像素值范围
 9     //计算直方图
10     calcHist(&image, 1, channels, Mat()/*不使用掩码*/, hist, dims/*这是一维的直方图*/, histSize, ranges);  
11     return hist;  //这里得到的hiat是256行一列的Mat
12 }
13 //  将图像的直方图展示出来
14 Mat draw_Hist(Mat &inputImage)
15 {
16     cv::MatND hist = getHistt(inputImage);
17     Mat showImage(256, 256, CV_8U,Scalar(255));
18     int i;
19     double maxValue = 0;
20     minMaxLoc(hist, 0, &maxValue, 0, 0);
21     for(i = 0; i < 256; i++)
22     {
23         float value = hist.at<float>(i);
24         int intensity = saturate_cast<int>(256 - 256 * (value/maxValue));
25         rectangle(showImage, Point(i, 256 - 1), Point((i+1)-1, intensity), Scalar(0));
26     }
27     //namedWindow("gray"); imshow("gray", showImage);
28     //cvMoveWindow("gray", 300, 300);
29     //waitKey(0);
30     return showImage;
31 }
View Code

 

 直方图显示:以下展示的 为以上的原图像以及直方图均衡化后的图像的  灰度直方图。

  

 

以上是关于OpenCV图像增强---灰度变换直方图均衡化的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV 完整例程49. 图像增强—局部直方图处理

opencv —— equalizeHist 直方图均衡化

分段线性变换与直方图修正

图像增强

opencv 一种灰度图像增强方式

图像灰度变换:直方图均衡和线性变换