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

时间:2019-01-19 23:24:43

标签: python image-processing autoexposurecompensation

我正在尝试编写一个程序,该程序采用充满12位RAW传感器值(范围为[512-4096]的矩阵)(512为拜耳传感器黑电平->即纯黑是定义并调整每个像素的EV,就像Adobe Camera Raw(ACR)“曝光”滑块一样。我试图弄清楚它是如何完成的。我浏览了许多博客,这些博客解释了如何计算EV,而且似乎是这样:

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

这似乎很不对劲,因为5 EV的调整会使图片变得不正确..而我在网上找不到其他资源。维基百科在Exposure Value上有很好的词条,但是似乎也没有我想要的东西……对此有什么帮助吗?

谢谢!

这是我的意思的示例:

EV为0的ACR中的RAW文件: Before

使用EV 5: After

我目前有这个公式:

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个小时...我不知道自己在做错什么,因为我无法让它一致地工作(具有多个电动汽车),总是绿色或洋红色的色调。我认为这是RAW照片这一事实使绿色通道混乱了。

1 个答案:

答案 0 :(得分:1)

假设您从原始图像开始,那么您处于线性空间。在这种情况下,更改曝光是一个乘法运算。

曝光值(EV)增加1表示将曝光量加倍。 Exposure 是对到达每个像素的光量的线性度量。将曝光加倍会使光量加倍。因为在摄影中,人们通常以当前曝光的分数来考虑,所以谈论“将EV增加1”而不是“将曝光乘以2”是有意义的。

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

如果输入图像是JPEG或TIFF文件,则可能在sRGB色彩空间中。这是一种非线性色彩空间,旨在增加8位图像文件的外观范围。在修改曝光之前,必须先将sRGB转换为线性RGB。大约可以通过将每个像素值提高到2.2的幂Wikipedia has the exact formulation来实现。


OP中的问题是由于黑电平不准确引起的。 raw.black_level_per_channel返回给定图像的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()