写在前面       

      如果直接按公式编程的话 ,需要执行大量浮点数的乘法、除法和指数运算。效率太低,在应用时是肯定不行的。 
  针对上述情况,有人提出了一种快速算法,如果能够确知图像的像素取值范围  , 例如  , 0 ~ 255 之间的整数  , 则图像中任何一个像素值只能 是  0  到  255  这  256  个整数中的某一个 ; 在  gamma 值 已知的情况下  ,0 ~ 255  之间的任一整数  , 经过“归一 化、预补偿、反归一化”操作后 , 所对应的结果是唯一的  , 并且也落在  0 ~ 255  这个范围内。

具体参考原文:https://blog.csdn.net/linqianbi/article/details/78617615

原图:

 Gamma校正原理及c++实现(查找表法)   

 

gamma=3:

  Gamma校正原理及c++实现(查找表法)

 

代码

#include <iostream>
#include <opencv2\core.hpp>
#include <opencv2\highgui.hpp>
#include <opencv2\imgproc.hpp>

void gamma_correction(cv::Mat& src, cv::Mat& dst, float K){
	uchar LUT[256];
	src.copyTo(dst);
	for (int i = 0; i < 256; i++){
		//float f = (i + 0.5f) / 255;
		float f = i  / 255.0;
		f = pow(f, K);
		//LUT[i] = cv::saturate_cast<uchar>(f*255.0f-0.5f);
		LUT[i] = cv::saturate_cast<uchar>(f*255.0);
	}
	
	if (dst.channels() == 1){
		cv::MatIterator_<uchar> it = dst.begin<uchar>();
		cv::MatIterator_<uchar> it_end = dst.end<uchar>();
		for (; it != it_end; ++it){
			*it = LUT[(*it)];
		}
	}
	else{
		cv::MatIterator_<cv::Vec3b> it = dst.begin<cv::Vec3b>();
		cv::MatIterator_<cv::Vec3b> it_end = dst.end<cv::Vec3b>();
		for (; it != it_end; ++it){
			(*it)[0] = LUT[(*it)[0]];
			(*it)[1] = LUT[(*it)[1]];
			(*it)[2] = LUT[(*it)[2]];
		}
	}

}

int main(){
	cv::Mat src = cv::imread("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Img\\(washed_out_aerial_image).tif");
	if (src.empty()){
		return -1;
	}
	cv::Mat dst;
	gamma_correction(src, dst, 3); //gamma变换

	cv::namedWindow("src");
	cv::imshow("src", src);
	cv::namedWindow("dst");
	cv::imshow("dst", dst);
	cv::waitKey(0);
}

 

相关文章: