采集的图像部分区域较亮,而部分区域较暗,需要进行亮度矫正来调整整个图片的亮度,使得整体亮度较为均匀。
传统Gamma函数亮度矫正
gamma校正原理
假设图像F中有一个像素A,值是 200 ,那么对这个像素进行校正必须执行如下步骤:
1.归一化 :将像素值转换为 0 ~ 1 之间的实数。 算法如下 : F/255 。对于像素 A 而言 , 其对应的归一化值为 0. 7843 。
2.预补偿 :求出gamma 值。这一步包含一个 求指数运算。若 gamma = 1 /2.2 = 0. 454545 , 对归一化后的 A 值进行预补偿的结果就 是 0. 7843 ^0. 454545 = 0. 8954 。
3.反归一化 :将经过预补偿的实数值反变换为 0 ~ 255 之间的整数值,即将预补偿的实数值乘以255。0.8954×255=228 , 这个 228 就是最后送 入显示器的数据。
即当 gamma<1时,输出图像变亮;当gamma >1时,输出图像变暗。
以下是python代码:
#-*-coding: UTF-8-*-
import numpy as np
import cv2
import math
from matplotlib import pyplot as plt
#import Recognise
#读取图片
img = cv2.imread('5.jpg')
#将原图片(RGB)转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#显示并保存
cv2.imshow('gray', gray)
cv2.imwrite('gray.jpg', gray)
#将灰度图做gamma校正运算
image = np.power(gray/255.0, 1/2.2)
cv2.imshow('imagechange', image)
#由于后面需要进行类型转换,转换成uint8,所以需要对其乘以255处理
image = image * 255
cv2.imwrite('imagechange.jpg',image)
#这里需要将image->转换为uint8类型,因为会出现类型不匹配
gray2rgb = cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_GRAY2RGB)
#保存图片
cv2.imwrite('gray2rgb.jpg', gray2rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()
假设图像的分辨率为 800*600 ,对它进行 gamma 校正,需要执行 48 万个浮点数乘法、除法和指数运算。效率太低,根本达不到实时的效果。
针对上述情况,提出了一种快速算法,如果能够确知图像的像素取值范围 , 例如 , 0 ~ 255 之间的整数 , 则图像中任何一个像素值只能 是 0 到 255 这 256 个整数中的某一个 ; 在 gamma 值 已知的情况下 ,0 ~ 255 之间的任一整数 , 经过“归一 化、预补偿、反归一化”操作后 , 所对应的结果是唯一的 , 并且也落在 0 ~ 255 这个范围内。
如前例 , 已知 gamma 值为 2. 2 , 像素 A 的原始值是 200 , 就可求得 经 gamma 校正后 A 对应的预补偿值为 228 。基于上述原理 , 我们只需为 0 ~ 255 之间的每个整数执行一次预补偿操作 , 将其对应的预补偿值存入一个预先建立的 gamma 校正查找表 (LUT:Look Up Table) , 就可以使用该表对任何像素值在 0 ~ 255 之 间的图像进行 gamma 校正。
以下是c++代码:
#include <iostream>
#include <opencv2/opencv.hpp>
// 伽马亮度矫正函数
cv::Mat gammaCorrection(const cv::Mat& inputImage, float gamma)
{
cv::Mat outputImage;
cv::Mat lookupTable(1, 256, CV_8U);
// 计算伽马校正的查找表
for (int i = 0; i < 256; ++i)
{
lookupTable.at<uchar>(i) = cv::saturate_cast<uchar>(pow(i / 255.0, gamma) * 255.0);
}
// 应用查找表进行伽马校正
cv::LUT(inputImage, lookupTable, outputImage);
return outputImage;
}
int main()
{
// 读取图像
cv::Mat inputImage = cv::imread("input.jpg", cv::IMREAD_COLOR);
// 检查图像是否成功读取
if (inputImage.empty())
{
std::cout << "Failed to read the image!" << std::endl;
return -1;
}
// 设置伽马值
float gamma = 2.2;
// 进行伽马亮度矫正
cv::Mat outputImage = gammaCorrection(inputImage, gamma);
// 显示原始图像和矫正后的图像
cv::imshow("Original Image", inputImage);
cv::imshow("Gamma Corrected Image", outputImage);
cv::waitKey(0);
return 0;
}
参考链接
https://blog.csdn.net/qq_35044509/article/details/78713289?
https://blog.csdn.net/LaoYuanPython/article/details/106966800?