anr*_*eff 3 c++ camera exif image image-processing
简而言之:我不能从JPEG照片的RGB值中提取有意义的光强度,并且试图考虑伽马校正或sRGB只会使事情变得更糟.
我正在做一个玩具项目,涉及处理一堆照片图像,用间隔计拍摄.基本上,我想用它们做一个时间流逝,进行一些修正,使剪辑更整洁.我用的是佳能dSLR.
我需要一个函数,在给定JPEG文件的情况下,它会计算出"平均场景亮度".结果应该是一个简单的数字; 不需要在任何绝对光度单位中表达,我只做相对比较.因此,例如,你拍摄一些房间的照片,然后函数返回"5.0".然后在灯光下添加第二个灯泡,与第一个灯泡完全相同,放在旁边,再次拍摄.该功能现在应该给你"10.0".
因此,我目前对此功能的实现结合了以下几个方面:ISO感光度,快门速度,光圈(从EXIF中提取)和平均图像亮度.Exif的东西显然更重要,因为在自动模式下,相机会尝试使用这样的设置,因此图像亮度会在中灰点附近.然而,ISO /快门/光圈设置的分辨率均为1/3或更低,因此检测图像亮度对于"微调"非常重要.
在我这样做的时候,我得到了一些明显的虚假结果,我挖的越多,我就越困惑.所以最后我设置了一个"几乎认真"的实验:
测试设置: 房间内的简单墙壁,用白炽灯照明,照明非常均匀.使用两个相机来比较结果:5D与50mm素数,350D与35mm素数.到墙的距离:约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
Run Code Online (Sandbox Code Playgroud)
第一列是平均像素值(直接来自JPEG),在整个图像上平均,转换为灰度为(R + G + B)/ 3.通过将[0..255]范围除以255,将颜色在[0..1]范围内归一化.因此,在1)和2)之间,我只更改ISO设置,图像应变为亮度的两倍,但平均像素值仅上升53%(没有任何过度曝光的区域).
2..3:光圈一个停止,所以图像应该变亮一半,所以1)和3)一致(额外的亮度可能是由于渐晕减少)
3..5:再次,一次停止,5)应该是3)的亮度的一半
5..8:同样,应该是一半(这基本上没问题).
这一切都非常非常奇怪.顺便说一下,两台相机之间的结果是一致的,这表明这不仅仅是特定型号的特殊性.
这没有应用任何伽马校正.JPEG读取代码使用C++,基本上遵循IJG示例代码(djpeg实用程序).现在,JPEG保存了伽马校正值,因此像素值应该被视为sRGB颜色空间中的值(获取源像素,转换为[0..1],并应用sRGB->线性RGB变换.让我们尝试一下:
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
Run Code Online (Sandbox Code Playgroud)
我也尝试了"普通"伽马校正(gamma = 2.2),结果与sRGB校正情况非常相似.
所以我非常,非常困惑.有人可以解释一下如何将相机JPEG的RGB强度真正解释为,因为我没有想法:)
所以,当我读到时,这个谜团慢慢展开.
而相机的传感器是理论上能够测量线性光强度的,它显然不这样做,而是模仿照相胶片,其具有公知的非线性响应的行为(例如,参见此,图3).因此,dSLR的响应曲线远不是线性的,但更像是这样的:

因此,如果没有精确校准,从像素值中获得绝对场景亮度是不切实际的.
但是,我只想对照片进行亮度调整,并且有一个近似正确的亮度估计对我来说很有用,所以我继续重建我的相机的传输功能(佳能350D):

白色数据点对应于各种光圈值下的不同曝光(f/22,f/20,f/18,f/16等,以1/3级为增量).正如上图所示,X轴在输入亮度方面是对数的,而Y轴在像素值方面是线性的(在伽马校正之后).假设图形在单位平方中,我还通过五阶多项式计算了近似拟合曲线:
(((((- 6.76219 * x) + 12.0459) * x - 5.8683) * x + 1.72338) * x - 0.148753) * x + 0.0105364;
Run Code Online (Sandbox Code Playgroud)
对于[0.05,1]中的x
所以,如果你有原始("真实")亮度,获得像素值会像这样:
定义此转换T,我的应用程序中的整个工作流程现在如下所示: