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);		

}

图像增加结果 

 

 

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
常见的图像分割算法有很多,下面给你介绍几种常用的图像分割算法的Python实现。 1. K均值聚类算法:K均值聚类是一种简单而有效的图像分割算法OpenCV提供了实现K均值聚类的函数,在Python可以通过以下代码使用K均值聚类算法进行图像分割: ```python import cv2 image = cv2.imread('image.jpg') pixel_values = image.reshape(-1, 3) pixel_values = np.float32(pixel_values) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2) k = 3 _, labels, centers = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) segmented_image = centers[labels.flatten()] segmented_image = segmented_image.reshape(image.shape) cv2.imshow('Segmented Image', segmented_image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 2. 分水岭算法:分水岭算法是一种基于图像灰度和梯度信息的图像分割算法OpenCV库同样提供了实现分水岭算法的函数,可以通过以下代码在Python使用分水岭算法进行图像分割: ```python import cv2 import numpy as np image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) sure_bg = cv2.dilate(opening, kernel, iterations=3) dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0) sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown == 255] = 0 markers = cv2.watershed(image, markers) image[markers == -1] = [0, 0, 255] cv2.imshow('Segmented Image', image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上是两种常见的图像分割算法的Python实现,你可以根据需求选择合适的算法进行图像分割。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值