ISP——Gamma Correction

现象

在这里插入图片描述

上图是百度上找的一张图,是电子发烧友网站的网友的,如果发现侵权了请告知。觉得这张图能很好的看出不同gamma曲线带给人的直观感受的变化。从上往下看左侧黑色块黑得越来越严重,对比度也在逐渐加深。但是需要注意的时这幅图时一个反伽马曲线的特性,和ISP中的gamma表现时反的,这个具体后面回介绍。这个给这张图主要是对gamma有一个直观的理解。

Gamma产生的原因

CRT属性导致

在液晶屏幕诞生前,CRT显示器时唯一的一种显示器,有的同学可能没见过,所以贴张图出来,就是老式电视和电脑那种后面带有一大坨的的显示屏。

在这里插入图片描述

这种显示器的工作方式如图所示

在这里插入图片描述

屏幕后面一大坨就是一个阴极射线管,工作原理大致就是后面的电子前发射电子,经加速电场和偏移电场的作用达到屏幕上指定的位置,然后屏幕的特殊材质会发光产生画面。然后屏幕显示的亮度就和电子的数量有关,而这个又和电子枪的电压有关,所以屏幕亮度就和电子枪的电压又一个函数关系
I s r e e n = f ( V ) I_{sreen} = f(V) Isreen=f(V)
但是需要注意的是这个函数关系不是线性的,也就是说当电子枪的电压升高为原来的两倍,但是屏幕亮度并不能变为原本的两倍,后面经过实验总结发现CRT的这种非线性关系满足对数关系

在这里插入图片描述

正式因为显示时会把亮度压低,所以为了还原成原本的线性特征,需要在显示之前进行一下矫正,使其恢复为线性,如是就有的gamma矫正,这也是最早对gamma的理解。到现在液晶显示可不满足这种特性,但是为了兼容以前的视频格式,也会认为在显示的时候添加这个一个反伽马矫正。

在这里插入图片描述

人眼的亮度特性

对于gamma还有一种说法就是,人眼的亮度响应曲线不是线性的而是如下图的关系

在这里插入图片描述

所以为了更好符合人眼的特性,就需要对暗区进行加强以提高画面的动态范围和暗区细节,更好的响应人眼对暗部更敏感的特性。而屏幕显示的时候又刚好有一个反伽马的特性,这一种说法认为这是一种巧合。

小结

目前这两种说法也没有人定义对错,就是两种不同的理解方式,所以也不要进入误区,关键点在于理解gamma的应用会给图像带来怎么样的变化。但是我个人更倾向于后面人眼的说法,至于为什么,我会在后面提到。关于gamma这一块儿网上有很多写得好的帖子我就不在多余赘述了,下面提供两个我觉得写的不错的博文的链接,有兴趣的可以看看

gamma校正

LUT法

在这里插入图片描述

如图的论文中提到了一种LUT法的实现方式。理解起来很简单,就是提前把每个像素值经gamma矫正后对应的值求出来,然后把这些数据直接存储到一个数中,到矫正的时候根据输入的值就能直接通过数组下标就能找到对应的矫正后的值,这种方式最大的有点就时快,几乎不消耗硬件资源,因为几乎不用做任何计算的处理,但是这种方式的弊端在于需要大量的内存来存储这么这个表。但是现在随着技术的发展内存对于硬件也不是什么限制了,一个手机动辄就8G的内存了,可以通过加DDR来提高内存,所以现在很多方案在用这种查表得方式做gamma矫正。例如海思,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JRBXn49a-1628479118494)(images\HiLUT.png)]

上图就是海思SDK中的实现方式,就是在一个头文件中定义这么一个数组,完全对应每一个输入值,然后海思用的是10bits,所以这个数组很大。

clc;clear; close all;
data = csvread('data/Gamma_Data_DEC_20210804103309.csv');
plot(data);
xlim([0, 1024]);
ylim([0, 4098]);
hold on;
plot([0, 1024], [0, 4098], 'r');

在这里插入图片描述

线性插值法

在这里插入图片描述

线性插值法也很好理解,就是在gamma曲线上提取一些采样点,然后把采样点的输入输出作为xy存储起来,然后矫正的时候如果在采样点上就接直接输入矫正值,如果不在,那么肯定在某两个采样点之间,那么就可以就可以通过这两个采样点的线性方程求解出该点的校正值。但是这种方式会有一定的误差,因为线性方程并布恩那个完全拟合gamma曲线。这种方式在一些廉价的方案里面会用到

在这里插入图片描述

如上图是一款链家ISP的插值方式,通过17个采样点来拟合曲线。

clc;clear;close all;
data = textread('data\gamma.txt', '%s');
xStr = char(data(1));
yStr = char(data(2));
xC = strsplit(xStr, ',');
yC = strsplit(yStr, ',');
x = hex0x2Dec(xC);
y = hex0x2Dec(yC);
plot(x, y);
hold on;
plot([0 255], [0 1023], 'r')
xlim([0, 256]);
ylim([0, 1024]);

在这里插入图片描述

这调曲线就是拟合出来的效果。

小结

  • 通过插值方式的这个gamma曲线就是我说我比较认同gammma的原因是受人眼特性的 影响而来。因为如果是为了矫正CRT的反伽马特性,那么gamma矫正曲线应该是比较规范的一条曲线,这样才能保证正法结合后恢复成线性。这条gamma是我在实际项目中在用的一条gamma,因为客户应用的特殊性,然后对颜色要求不高,这种gamma能将画面效果调到最好,所以我们调gamma主要还是为了人眼看着舒服合适,说到底还是为了人眼看东西的特性。

  • 上面两个曲线我们也可以看出来输出的大小比输入大。一版都是这样,输出会提高位数来保留更多信息量,减少非线性变换带来的信息损失。因为线性的时候肯定是每个输入对应一个输出,但是经过gamma变换后,就会出现对多个输入对应的一个输出的现象,这种输入的这些信息量就会损失,而如果提高输出的位数,用更多的数来表示,就能保证对每个输入都有一个输出与之对应从而保证信息不损失。

模拟gamma法

还有一种方式就是通过模拟的方式来做gamma矫正,但是这种方式不输入ISP PIPELINE中的算法,所以只是简单提一下。

在这里插入图片描述

这种方法的大概思路就是AD转换的时候经过一定的处理使其呈现非线性的特性。如上图定义Vramp和Vsig,当电压达到Vramp时产生一个斜坡信号,同时始终信号开始工作并计数,然后当电压到达Vsig时latch信号发生一个跳变使得始终信号停止基数,然后这个电压值就会和这种始终信号有一个非线性特性,人后根据这个特性进行gamma矫正。然后这种方式不涉及ISP算法,所以不作重点讲解,有兴趣的同学可以联系我提供论文研究。

附属说明

有的ISP除了有Ygamma还有RGBgamma,其实这个RGBgamma也很好理解,RGBgamma就是针对RGB三个通道分别有一条gamma曲线进行调整,这样就可以分别控制RGB三色通道从而对颜色产生控制。

相关链接

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要编写正伽马校正(Positive Gamma Correction),需要进行以下步骤: 1. 设置伽马值:正伽马校正是一种非线性的校正方法,通过将像素值的平方根或其它次方应用于原始像素值来调整图像亮度。伽马值通常在1.8到2.5之间,可以根据实际需要进行调整。 2. 计算伽马校正表:将每个像素值进行伽马校正,生成一个伽马校正表。可以使用以下公式进行计算:Gamma-corrected value = Original value^(1/Gamma)。 3. 应用伽马校正:将伽马校正表应用于图像中的所有像素,以生成正伽马校正的图像。 下面是一个使用ESP32和libili9341库的示例代码,用于进行正伽马校正: ```c++ #include <Adafruit_GFX.h> #include <Adafruit_ILI9341.h> #define TFT_CS 10 #define TFT_DC 9 #define TFT_RST 8 // Create a new instance of the display library Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); float gammaValue = 2.2; // Set gamma value for positive gamma correction void setup() { // Initialize the display tft.begin(); } void loop() { // Load image data into a buffer uint16_t buffer[320 * 240]; for (int i = 0; i < 320 * 240; i++) { buffer[i] = /* load pixel data */; } // Generate gamma correction table uint8_t gammaTable[256]; for (int i = 0; i < 256; i++) { gammaTable[i] = pow(i / 255.0, gammaValue) * 255.0 + 0.5; } // Apply gamma correction to image data for (int i = 0; i < 320 * 240; i++) { uint16_t pixel = buffer[i]; uint8_t r = (pixel & 0xF800) >> 11; uint8_t g = (pixel & 0x07E0) >> 5; uint8_t b = pixel & 0x001F; r = gammaTable[r]; g = gammaTable[g]; b = gammaTable[b]; buffer[i] = (r << 11) | (g << 5) | b; } // Display the image tft.startWrite(); tft.setAddrWindow(0, 0, 319, 239); tft.pushColors(buffer, 320 * 240); tft.endWrite(); } ``` 在这个示例中,我们使用了ESP32和libili9341库来控制显示屏。我们首先加载图像数据到一个缓冲区中,然后使用伽马值计算一个伽马校正表。最后,我们将伽马校正表应用于图像数据,并将结果显示在显示屏上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值