图像灰度变换以及实现
作者:互联网
引言
对于数字图像处理而言,一般包含着空间域处理和变换域处理两种形式。空间域处理方法主要是直接以图像中的像素操作为基础,它主要分为灰度变换和空间滤波两类。
灰度变换也被称为图像的点运算(只针对图像的某一像素点)是所有图像处理技术中最简单的技术,其变换形式如下:
其中,T是灰度变换函数;r是变换前的灰度;s是变换后的像素。
图像灰度变换的有以下作用:
- 改善图像的质量,使图像能够显示更多的细节,提高图像的对比度(对比度拉伸)
- 有选择的突出图像感兴趣的特征或者抑制图像中不需要的特征
- 可以有效的改变图像的直方图分布,使像素的分布更为均匀
为了保证经过灰度变换后的输出图像在整体的外貌上,或者更准确地说在形态学上,与输入图像保持一致,灰度变换函数必须是严格单调递增函数。
在图像处理中,灰度变换主要应用于图像的对比度改善。在灰度变换中,最为常用的三类基本函数为线性函数(反转和恒等变换)、对数函数(对数和反对数变换)以及幂律函数(n次幂和n次根变换)。
1、图像反转
图像反转的原理很简单,就是颠倒黑白的运算,处理后的效果看起来像是原图的底片。其的表达式: s=L-1-r 。其中r表示处理前的灰度值,s表示处理后的灰度值。特别适用于增强嵌入在一副图像的暗区域中的白色或者灰色细节,尤其是当黑色面积在尺寸上占主导地位时。
opencv实现:
int main(int argc, char** argv) { Mat src; src = imread("D:/opencv练习图片/薛之谦.jpg"); imshow("Image", src); Mat srcDst = ~src; //图像反转 imshow("Reversal Image", srcDst); waitKey(0); return 0; }
图像反转的实现是比较简单的,在OpenCV中有对Mat的运算符重载,可以直接Mat srcDst = 255 - src
或者~src
来实现。从图可以看到,黑的部分变白,白的部分变黑了。
2、对数变换
对数变换的通用公式是:
其中,c是一个常数,,假设r≥0r≥0,根据上图中的对数函数的曲线可以看出:对数变换可以将图像的低灰度值部分扩展,显示出低灰度部分更多的细节,将其高灰度值部分压缩,减少高灰度值部分的细节,从而达到强调图像低灰度部分的目的。
对数变换对图像低灰度部分细节增强的功能过可以从对数图上直观理解:
原图上0~0.4的低灰度部分经过对数运算后扩展到0~0.8的部分,而整个0.4~1的高灰度部分被投影到只有0.8~1的区间,这样就达到了扩展和增强低灰度部分,压缩高灰度部分的值的功能。
从上图还可以看到,对于不同的底数,底数越大,对低灰度部分的扩展就越强,对高灰度部分的压缩也就越强。
opencv实现:
int main(int argc, char** argv) { Mat src; src = imread("D:/opencv练习图片/薛之谦.jpg"); imshow("Image", src); Mat srcLog(src.size(), CV_32FC3); for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { //对数变换公式s = clog(1 + r) srcLog.at<Vec3f>(i, j)[0] = log(1 + src.at<Vec3b>(i, j)[0]); srcLog.at<Vec3f>(i, j)[1] = log(1 + src.at<Vec3b>(i, j)[1]); srcLog.at<Vec3f>(i, j)[2] = log(1 + src.at<Vec3b>(i, j)[2]); } } //归一化到0~255 normalize(srcLog, srcLog, 0, 255, NORM_MINMAX); //转换成8bit图像显示 convertScaleAbs(srcLog, srcLog); imshow("对数变换", srcLog); waitKey(0); return 0; }
这使用的对数函数的底为10。由于灰度变换是灰度值之间的一对一的映射,而灰度值区间通常为[0,255],所以在进行灰度变换时,通常使用查表法。也就是,现将每个灰度值的映射后的结果计算出来,在变换时,通过查表得到变换后的灰度值。执行上面结果得到的结果如下:
对比可以发现:变换后的图像,整个图像明亮许多,也能分辨出原图中处于暗区域的更多细节。所以对数变换对照度不均图像中低灰度部分的细节增强很实用。
对数变换,还有一个很重要的性质,能够压缩图像像素的动态范围。例如,在进行傅立叶变换时,得到的频谱的动态范围较大,频谱值的范围通常为[0,106],甚至更高。这样范围的值,显示器是无法完整的显示如此大范围的灰度值的,因而许多灰度细节会被丢失掉。而将得到的频谱值进行对数变换,可以将其动态范围变换到一个合适区间,这样就能够显示更多的细节。
3、幂律变换(伽马变换)
伽马变换的公式为:
其中 c 和 γ 为正常数。其一般表达式的图像为:
伽马变换的效果与对数变换有点类似,对于γ<1,扩展低灰度范围,压缩高灰度范围;对于γ>1,压缩低灰度范围,扩展高灰度范围。这样就能够显示更多的图像的低灰度或者高灰度细节。
伽马变换主要用于图像的校正,对灰度值过高(图像过亮)或者过低(图像过暗)的图像进行修正,增加图像的对比度,从而改善图像的显示效果。
opencv实现:
int main(int argc, char** argv) { float pixels[256]; for (int i = 0; i < 256; i++) { //i的四次方 pixels[i] = powf(i,4); } Mat src; src = imread("D:/opencv练习图片/高曝光.png"); imshow("Image", src); Mat srcLog(src.size(), CV_32FC3); for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { //对数变换公式s = clog(1 + r) srcLog.at<Vec3f>(i, j)[0] = pixels[src.at<Vec3b>(i, j)[0]]; srcLog.at<Vec3f>(i, j)[1] = pixels[src.at<Vec3b>(i, j)[1]]; srcLog.at<Vec3f>(i, j)[2] = pixels[src.at<Vec3b>(i, j)[2]]; } } //归一化到0~255 normalize(srcLog, srcLog, 0, 255, NORM_MINMAX); //转换成8bit图像显示 convertScaleAbs(srcLog, srcLog); imshow("伽马变换", srcLog); waitKey(0); return 0; }
原图是一张有点过曝的图像,高灰度部分的细节不清楚,通过伽马变换扩展高灰度部分,增强对比度:这里选择的参数为c = 1,r=4(r>1),来扩展图像的高灰度区域,其结果如下:
还可以使用c = 1,r=0.4(r<1),来扩展图像的低灰度区域,其结果如下:
知识点:pow, powf, powl - 计算 x 的 y 次幂:xy
#include <math.h> //头文件
double pow(double x, double y); float powf(float x, float y); long double powl(long double x, long double y);
总结
本文主要对图像的几种常见的灰度变换进行了总结。
- 图像反转,是图像线性变换的一种,可以得到图像负片,能够有效的增强图像的暗色区域中的白色或者灰色细节
- 对数变换,扩展图像中的低灰度区域,压缩图像中的高灰度区域,能够增强图像中的暗色区域的细节;反对数变换与此相反。对数变换还有个重要作用是,能够压缩图像灰度值的动态范围,在傅立叶变换中能够显示更多的变换后的频谱细节。
- 伽马变换,主要用于图像的校正,根据参数 γγ的选择不同,能够修正图像中灰度过高(γ>1)或灰度过低(γ<1)
参考链接:(8条消息) 图像灰度变换及实现_牧野的博客-CSDN博客_图像灰度变换
标签:src,灰度变换,实现,srcLog,灰度,图像,对数变换 来源: https://www.cnblogs.com/xyf327/p/14750902.html