写在前面
如果直接按公式编程的话 ,需要执行大量浮点数的乘法、除法和指数运算。效率太低,在应用时是肯定不行的。
针对上述情况,有人提出了一种快速算法,如果能够确知图像的像素取值范围 , 例如 , 0 ~ 255 之间的整数 , 则图像中任何一个像素值只能 是 0 到 255 这 256 个整数中的某一个 ; 在 gamma 值 已知的情况下 ,0 ~ 255 之间的任一整数 , 经过“归一 化、预补偿、反归一化”操作后 , 所对应的结果是唯一的 , 并且也落在 0 ~ 255 这个范围内。
具体参考原文:https://blog.csdn.net/linqianbi/article/details/78617615
原图:
gamma=3:
代码
#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);
}