图像增强的目的:改善图像的视觉效果或使图像更适合于人或机器的分析处理。通过图像增强,可以减少图像噪声,提高目标与背景的对比度,也可以增强或抑制图像中的某些细节。
---------------------------------------------------------------------------------------------------
灰度变换:把原图像的像素灰度经过某个函数变换成新图像的灰度。可分为直线灰度变换法和直方图修正法。
直线灰度变换法:线性、分段线性、非线性变换。
直方图修正法:直方图均衡化、直方图规定化。
---------------------------------------------------------------------------------------------------
图像直方图:是对像素的某种属性(如灰度、颜色、梯度等)分布进行统计分析的重要手段。
灰度直方图:是灰度级的函数,它反映了图像中每一灰度级出现的次数或频率。
直方图均衡化:把原始图像的直方图变换为均匀分布的形式,从而增加图像灰度的动态范围,以达到增强图像对比度的效果。
经过均衡化处理的图像,其灰度级出现的概率相同,此时图像的熵最大,图像所包含的信息量最大。
【注意,离散后是每块区域的概率相等,均衡化后并不是条直线哦。】
细节概念等省略......
---------------------------------------------------------------------------------------------------
线性灰度增强、对数变换、指数变换、直方图均衡化。代码见下(代码略粗糙...)【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 }
效果如下:
原图像:
线性灰度增强:我这里默认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 }
直方图显示:以下展示的 为以上的原图像以及直方图均衡化后的图像的 灰度直方图。