OpenCV中基于Retinex的图像增强实现

美国物理学家埃德温∙兰德(Edwin Land) 在 1971 年提出一种被称为色彩的理论,并在颜色恒常性的基础上提出的一种图像增强方法。Retinex 理论认为物体的颜色是由物体对长波、中波和短波光线的反射能力决定的,而不是由反射光强度的绝对值决定的,即物体的色彩不受光照非均性的影响,具有一致性。

根据 Retinex 理论,它会将一幅给定的图像 S(x,y) 分解成两幅不同的图像:反射物体图像R(x,y)和入射光图像 L(x,y)。可以表示为:

其原理如下所示:

人眼得到的图像数据取决于入射光和物体表面对入射光的反射。Retinex理论就是通过图像S得到物体的反射性质R。所以实际上Retinex方法去除了入射光 L的性质最终得到了物体原本该有的样子。

Retinex图像增强处理步骤如下:

 

  1.  利用取对数的方法将照射光分量和反射光分量分离:

  2. 用高斯模板对原图像做卷积,相当于对原图做低通滤波,得到低通滤波后的图像D(x,y),其中F(x,y)表示高斯滤波函数。

  3.  在对数域中,用原图像减去低通滤波图像,得到高频增强的图像G(x,y)。

  4. 对G(x,y)取反对数,得到增强后的图像:

  5. 对R(x,y)做对比度增强,得到最终的结果图像。

SSR算法:

SSR (Singal Scale Retinex),即单尺度视网膜算法是 Retinex 算法中最基础的一个算法。运用的就是上面的方法,具体步骤如下:

  • 输入原始图像 I(x,y) 和滤波的半径范围 sigma;
  • 计算原始图像 I(x,y) 高斯滤波后的结果,得到 L(x,y);
  • 按照公式计算,得到 Log[R(x,y)];
  • 将得到的结果量化为 [0, 255] 范围的像素值,然后输出结果图像。

需要注意的是,最后一步量化的过程中,并不是将 Log[R(x,y)] 进行 Exp 化得到 R(x,y) 的结果,而是直接将 Log[R(x,y)] 的结果直接用如下公式进行量化:

Mat::convertTo函数

该函数能改变图像的深度,而且可以实现原地改变。但是不能改变图像的通道数。

//函数原型 
void convertTo(OutputArray dst, int rtype, double alpha, double beta, Stream& stream) const;

参数1:输出图像

参数2:需要的输出矩阵类型

参数3和参数4:缩放参数

缩放参数实际等价于公式:m(x,y) = saturate_cast(α(*this)(x,y)+β)

log()函数

log()函数的功能是计算每个数组元素绝对值的自然对数

//函数原型
void log(InputArray src,OutputArray dst)

参数1:输入图像

参数2:输出图像(求对数以后的图像)

normalize()函数

该函数归一化输入数组使它的范数或者数值范围在一定的范围内。

//函数原型
void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
                int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());

参数1:输入图像

参数2:输出图像

参数3:范围下限

参数4:范围上限

参数5:选择归一化的方式

参数6: 当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同。

图像文件的数据类型

一般的图像文件格式使用的是 Unsigned 8bits吧,CvMat矩阵对应的参数类型就是CV_8UC1,CV_8UC2,CV_8UC3。 其中U代表 Unsigned 无符号、C代表CvMat 后面的数字代表通道数(最后的1、2、3表示通道数,譬如RGB3通道就用CV_8UC3)

float 是32位的,对应CvMat数据结构参数就是:CV_32FC1,CV_32FC2,CV_32FC3...
double是64bits,对应CvMat数据结构参数:CV_64FC1,CV_64FC2,CV_64FC3。

Vec2b—表示每个Vec2b对象中,可以存储2个char(字符型)数据
       Vec3b—表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
       Vec4b—表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图

SSR算法实现

void SingleScaleRetinex(const Mat& src, Mat& dst, int sigma)
{
	Mat doubleImage, gaussianImage, logIImage, logGImage, logRImage;
	//转换范围,所有图像元素增加1.0保证log操作正常,防止溢出
	src.convertTo(doubleImage, CV_64FC3, 1.0, 1.0);     
	//高斯模糊,当size为零时将通过sigma自动进行计算
	GaussianBlur(doubleImage, gaussianImage, Size(0, 0), sigma);   
	//OpenCV的log函数可以计算出对数值。logIImage和logGImage就是对数计算的结果。
	log(doubleImage, logIImage);
	log(gaussianImage, logGImage);
	//Retinex公式,Log(R(x,y))=Log(I(x,y))-Log(G(x,y)))
	logRImage = logIImage - logGImage;   
	//将结果量化到[0,255]范围内,NORM_MINMAX表示线性量化,CV_8UC3表示将图像转回
	normalize(logRImage, dst, 0, 255, NORM_MINMAX, CV_8UC3);		

}

图像增加结果 

 

 

发布了222 篇原创文章 · 获赞 174 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/zy010101/article/details/104968146