文章目录

  • 一、伽马变换算法详解
  • 二、在实现算法之前的预备知识
  • 四、代码实现(C++版)


一、伽马变换算法详解

我们先来看一下伽马变换的公式:图像伽马变换python 图像 伽马_c++,其中,图像伽马变换python 图像 伽马_图像伽马变换python_02 是做了伽马变换之后的图像的像素值、图像伽马变换python 图像 伽马_opencv_03 是原图像的对应位置的像素值。图像伽马变换python 图像 伽马_光强_04图像伽马变换python 图像 伽马_光强_05 是正的常数。我们下面重点关心一下 图像伽马变换python 图像 伽马_光强_05



图像伽马变换python 图像 伽马_图像伽马变换python_07


这个图到底是什么意思呢?我这么解释吧:大家是不是都有用过 P图 软件,在一般的软件界面中,都会有一个 “ 曲线 ”的选项,我们可以通过改变曲线的形状来调整图像局部或者全局的亮度。

图像伽马变换python 图像 伽马_图像伽马变换python_08


这样的比喻可能从数字图像处理的角度不完全准确,但是它给我们的启示是:曲线是凸状的,则图像就会变亮;曲线是凹状的,则图像就会变暗。

这反应在外面上面的伽马变换曲线图也是类似的:曲线是凸状的,则图像就会变亮;曲线是凹状的,则图像就会变暗。 所以外面可以归纳出:

  1. 图像伽马变换python 图像 伽马_光强_09
  2. 图像伽马变换python 图像 伽马_图像伽马变换python_10

那么,我们为什么需要伽马校正,又或者说,伽马校正为何有效?

首先、伽马校正能更有效的保存图像亮度信息。下图展示的是未经过伽马矫正和经过伽马矫正的图像信息:



图像伽马变换python 图像 伽马_c++_11


我们发现,未经伽马校正的情况下,在低灰度值时,有较大范围的灰度值被保存成同一个值,造成信息丢失;同时高灰度值时,很多比较接近的灰度值却被保存成不同的值,造成空间浪费。经过伽马校正后,改善了存储的有效性和效率。

另外,人眼对外界光源的感光值与输入光强不是呈线性关系的,而是呈指数型关系的。在光强较弱的时候,我们人眼能够感觉到较为细微的光强变化;但是在亮度较高时,要想察觉到光强的改变就没那么容易了。

二、在实现算法之前的预备知识

  1. 两种图像存储类型 CV_8U 和 CV_32F 的区别:CV_8U是 unsign 的8位/像素-即一个像素的值在0-255区间,这是大多数图像和视频格式的正常范围CV_32F是 float -像素是在0-1.0之间的任意值,这对于一些数据集的计算很有用,但是它必须通过将每个像素乘以255来转换成8位来保存或显示
  2. OpenCV 的归一化函数 normalize。函数原型如下:
void cv::normalize(InputArry src,InputOutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,int dtype=-1,InputArray mark=noArry())

其中,对于归一化方式,CV_MINMAX 方式的公式如下:图像伽马变换python 图像 伽马_光强_12
其中,如果 图像伽马变换python 图像 伽马_伽马校正_13 是最小值的时候,图像伽马变换python 图像 伽马_c++_14;如果 图像伽马变换python 图像 伽马_伽马校正_13 是最大值的时候,图像伽马变换python 图像 伽马_c++_16

  1. OpenCV 里面 convertScaleAbs 函数功能是将CV_32F 等类型的输出图像转变成CV_8U型的图像

四、代码实现(C++版)

Mat gammaTrans(Mat& m_img, double gamma, int n_c)
{
	/*
	CV_8U是 unsign 的8位/像素-即一个像素的值在0-255区间,这是大多数图像和视频格式的正常范围。
	CV_32F是 float -像素是在0-1.0之间的任意值,这对于一些数据集的计算很有用,但是它必须通过将每个像素乘以255来转换成8位来保存或显示。
	*/
	Mat m_imgGamma(m_img.size(), CV_32FC3);
	for (int i = 0; i < m_img.rows; i++)
		for (int j = 0; j < m_img.cols; j++)
		{
			m_imgGamma.at<Vec3f>(i, j)[0] = n_c * pow(m_img.at<Vec3b>(i, j)[0], gamma);  //使用动态寻址方式
			m_imgGamma.at<Vec3f>(i, j)[1] = n_c * pow(m_img.at<Vec3b>(i, j)[1], gamma);
			m_imgGamma.at<Vec3f>(i, j)[2] = n_c * pow(m_img.at<Vec3b>(i, j)[2], gamma);
		}
	normalize(m_imgGamma, m_imgGamma, 0, 255, CV_MINMAX);
	convertScaleAbs(m_imgGamma, m_img);  //将CV_32F的图像转成CV_8U的
	return m_img;
}

下面,我们对于一张水下模糊图片进行伽马矫正(这张水下图像整体由于亮度偏高而导致模糊),我们看看效果

#include <opencv2/highgui/highgui.hpp>    
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
Mat gammaTrans(Mat& m_img, double gamma, int n_c);
int main()
{
	Mat scr, dst;
	scr = imread("test1.jpg", 1);
	imshow("原图", scr);
	dst = gammaTrans(scr, 4, 1);
	imshow("Gamma变换效果图", dst);
	waitKey();
	return 0;
}

图像伽马变换python 图像 伽马_伽马校正_17

这暂时就是本次 图像伽马变换python 图像 伽马_c++_18