gpt4 book ai didi

c++ - 从 JPEG 图像中提取亮度的正确方法是什么( Gamma 校正等)?

转载 作者:太空狗 更新时间:2023-10-29 20:06:13 26 4
gpt4 key购买 nike

简而言之:我无法从 JPEG 照片的 RGB 值中提取有意义的光强度,而尝试考虑 Gamma 校正或 sRGB 只会让事情变得更糟。

我正在做一个玩具项目,其中涉及处理一堆用间隔计拍摄的照片图像。基本上,我想用它们做一个延时,并进行一些修正,使剪辑更整洁。我使用佳能数码单反相机。

我需要一个函数,给定一个 JPEG 文件,计算出“平均场景亮度”。结果应该是一个简单的数字;不需要用任何绝对光度单位来表示,我只是做相对比较。因此,例如,您拍摄某个房间的照片,然后该函数返回“5.0”。然后你在照明中添加第二个灯泡,与第一个灯泡的类型完全相同,放在它旁边,然后再次拍摄。该函数现在应该为您提供“10.0”。

因此,我目前对该功能的实现结合了几个方面:ISO 速度、快门速度、光圈(从 EXIF 中提取)和平均图像亮度。 Exif 的东西显然更重要,因为在自动模式下,相机会尝试使用这样那样的设置,因此图像亮度会出现在中灰点附近。然而,ISO/快门/光圈设置的分辨率都是 1/3 级或更小,因此检测图像亮度对于“微调”很重要。

在我这样做的过程中,我得到了一些明显虚假的结果,而且我越深入挖掘,就越感到困惑。所以最后我设置了一个“几乎严肃”的实验:

测试设置:房间内简单的一面墙,用白炽灯点亮,照度相当均匀。使用两台相机比较结果:5D 50mm prime,350D 35mm prime。与墙壁的距离:约 3 米。所有照片均以 1/10 秒的快门速度拍摄。相机设置:手动、“忠实模式”(无增强、无饱和度或对比度凸起)、Tungsten WB、无自定义功能、JPEG-Fine、sRGB 色彩空间。镜头没有滤镜。照明没有改变,我只改变了 ISO 和光圈设置。这是我得到的结果:

     Avg   Spd   ISO  Aperture
1. 0.3507, 0.10, 100, f/2.8
2. 0.5382, 0.10, 200, f/2.8
3. 0.3557, 0.10, 200, f/4.0
4. 0.2709, 0.10, 200, f/5.0
5. 0.2118, 0.10, 200, f/5.6
6. 0.1718, 0.10, 200, f/6.3
7. 0.1459, 0.10, 200, f/7.1
8. 0.1112, 0.10, 200, f/8.0
9. 0.0883, 0.10, 200, f/9.0

第一列是平均像素值(直接来自 JPEG),对整个图像进行平均,转换为灰度为 (R+G+B)/3。通过将 [0..255] 范围除以 255,颜色在 [0..1] 范围内归一化。所以,在 1) 和 2) 之间,我只改变了 ISO 设置,图像应该变得两倍明亮,但平均像素值只上升了 53%(没有任何过度曝光的区域)。

2..3:光圈缩小一档,所以图像应该变亮一半,所以 1) 和 3) 一致(额外的亮度可能是由于减少了暗角)

3..5:同样,向下一档,5) 应该是 3) 的一半

5..8:相同,应该是一半(不过这基本上没问题)。

这一切都非常非常奇怪。顺便说一句,两台相机的结果是一致的,表明这不仅仅是特定型号的特殊性。

这没有应用任何 Gamma 校正。 JPEG 读取代码是用 C++ 编写的,基本上遵循 IJG 示例代码(djpeg 实用程序)。现在,JPEG 保存 Gamma 校正值,因此像素值应被视为 sRGB 色彩空间中的值(获取源像素,转换为 [0..1],并应用 sRGB->linear RGB transform 。让我们试试看:

     Avg   Spd   ISO  Aperture
1. 0.1140, 0.10, 100, f/2.8
2. 0.2746, 0.10, 200, f/2.8
3. 0.1175, 0.10, 200, f/4.0
4. 0.0682, 0.10, 200, f/5.0
5. 0.0424, 0.10, 200, f/5.6
6. 0.0287, 0.10, 200, f/6.3
7. 0.0213, 0.10, 200, f/7.1
8. 0.0133, 0.10, 200, f/8.0
9. 0.0092, 0.10, 200, f/9.0

我还尝试了“普通” Gamma 校正( Gamma = 2.2),结果与 sRGB 校正情况非常相似。

所以我非常非常不解。有人可以解释相机 JPEG 的 RGB 强度应该如何真正解释为,因为我没有想法:)

最佳答案

于是,随着我继续阅读,谜底慢慢揭开。

虽然相机的传感器在理论上能够测量线性光强度,但它显然不会这样做,而是模仿胶片的行为,胶片具有众所周知的非线性响应(例如,参见 this,图3).因此,dSLR 的响应曲线远不是线性的,而是更像这样:

exposure response on a digital camera

因此,如果没有精确校准,从像素值中获取绝对场景亮度是不切实际的。

但是,我只想对照片进行亮度调整,而大致正确的亮度估计对我来说是个窍门,所以我继续重构我的相机 (Canon 350D) 的传递函数:

log-linear response curve of Canon 350D's sensor

白色数据点对应于不同光圈值(f/22、f/20、f/18、f/16 等,以 1/3 级为增量)的不同曝光。与上图一样,X 轴是入射亮度的对数,而 Y 轴是像素值的线性( Gamma 校正后)。假设图形在单位正方形内,我还通过五阶多项式计算了一条近似拟合曲线:

(((((- 6.76219 * x) + 12.0459) * x - 5.8683) * x + 1.72338) * x - 0.148753) * x + 0.0105364;

对于 [0.05, 1] 中的 x

因此,如果您获得原始(“真实”)亮度,则获取像素值将如下所示:

  1. 获取输入亮度的对数并对其进行线性变换,以便在 [0..1] 间隔内有 7⅓ 档曝光,
  2. 应用上述多项式(不过您需要对 [0..0.05) 区间进行特殊处理)。
  3. 应用 sRGB 压缩。

将此转换称为 T,我的应用程序中的整个工作流现在是这样工作的:

  1. T-1 处理输入的 JPEG 图像,
  2. 结果值以浮点格式保存,并被视为线性 RGB 值,
  3. 在将结果保存回 JPEG 之前应用 T

关于c++ - 从 JPEG 图像中提取亮度的正确方法是什么( Gamma 校正等)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8938861/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com