根据 EV 值调整 RAW 图像的曝光

Adjust exposure of RAW image based on EV value

我正在尝试编写一个程序,该程序接受一个充满 12 位 RAW 传感器值(范围从 [512-4096])的矩阵(512 是拜耳传感器黑电平 --> 即什么纯黑色定义为)并调整每个像素的 EV,就像 Adob​​e Camera Raw (ACR) "exposure" 滑块一样。我试图弄清楚它基本上是如何完成的。我查了很多解释 EV 是如何计算的博客,它似乎是:

This link 似乎给出了公式:PixelAdjusted = Pixel * 2^EV

这似乎是非常错误的,因为 5 EV 的调整会使图片不成比例。而且我在网上找不到任何其他资源。维基百科在 Exposure Value 上有一个很好的条目,但它似乎也没有我要找的东西......对此有什么帮助吗?

谢谢!

这是我的意思的一个例子:

EV 为 0 的 ACR 中的 RAW 文件:

使用 EV 5:

我目前有这个公式:

black_level = 512
bit_depth = 2**12
normalized = max((raw_pixel - black_level),0) / (bit_depth) ## normalize to [0,1]
exposed = normalized * (2**EV)    ## expose by desired EV value

## scale back to normal level:
raw_pixel_new = exposed * bit_depth  

但这对任何非 5 的 EV 值都会失败,因此公式不正确。我也知道这个公式是错误的,因为如果 EV = 0 它就不起作用。我发现很多网站都解释说公式只是 new_pixel = pixel * 2^exposure 但这似乎不适用于 Raw 照片……我是不是漏掉了什么?

有什么想法吗?

这里是一些 python 代码和我用来测试的一些文件:

代码:
import rawpy
import numpy as np

from PIL import Image

bit_depth = 12
black_level = 512
exposure = 4


path = "/001_ev0.DNG"
raw = rawpy.imread(path)

im = raw.raw_image_visible
im = np.maximum(im - black_level, 0)
im *= 2**exposure
# im = im + black_level # for some reason commenting this out makes it slightly better
im = np.minimum(im,2**12 - 1)
raw.raw_image[:,:] = im
im = raw.postprocess(use_camera_wb=True,no_auto_bright=True)
img = Image.fromarray(im, 'RGB')
img.show() #This should look like the file: 001_ev4.tif
图片:

https://drive.google.com/open?id=1T0ru_Vid8ctM3fDdbx1hvxNojOXOzXxg

出于某种原因,我已经在这上面花了 14 个小时...我不知道我做错了什么,因为我无法始终 工作(有多个 EV)总是有绿色或洋红色调。我认为这是一张 RAW 照片这一事实搞砸了绿色通道...

假设您从原始图像开始,您处于线性 space 中。在这种情况下,改变曝光是一个乘法运算。

曝光值 (EV) 增加 1 对应于加倍曝光。 曝光 是到达每个像素的光量的线性度量。加倍曝光会使光量加倍。因为在摄影中人们通常根据当前曝光的分数来思考,所以谈论 "increasing EV by 1" 而不是 "multiplying exposure by 2".

是有意义的

因此,实际上,要将曝光值增加 n,请将像素值乘以 2n.

如果输入图像是 JPEG 或 TIFF 文件,它可能是 sRGB 颜色 space。这是一种非线性颜色 space,旨在增加 8 位图像文件的表观范围。在修改曝光之前,需要先将 sRGB 转换为线性 RGB。这可以通过将每个像素值提高到 2.2 的幂来近似地实现,Wikipedia has the exact formulation.


OP 中的问题是由不准确的黑电平引起的。 raw.black_level_per_channel returns 528 对于给定的图像(每个通道的值都相同,但我猜其他相机型号不一定是这种情况),而不是 512。此外,代码写道 raw.raw_image_visible 变回 raw.raw_image,这是不正确的。

以下代码产生正确的结果:

import rawpy
import numpy as np
from PIL import Image

bit_depth = 12
exposure = 5

path = "/001_ev0.DNG"
raw = rawpy.imread(path)
black_level = raw.black_level_per_channel[0] # assume they're all the same

im = raw.raw_image
im = np.maximum(im, black_level) - black_level # changed order of computation
im *= 2**exposure
im = im + black_level
im = np.minimum(im, 2**12 - 1)
raw.raw_image[:,:] = im
im = raw.postprocess(use_camera_wb=True, no_auto_bright=True)
img = Image.fromarray(im, 'RGB')
img.show()