在Numpy中将sRGB矢量化为线性转换

时间:2016-09-30 13:00:30

标签: python numpy vectorization color-space srgb

在我的图像编辑应用程序中,我有一个将32位浮点图像从sRGB转换为线性颜色空间的功能。公式是:

if value <= 0.04045: (value / 12.92)
if value > 0.04045: ((value + 0.055) / 1.055)^2.4)

我的图片是一个名为 img32 的三维 numpy.ndarray

到目前为止我的实施:

boolarray = img32 <= 0.04045
lower = (img32 / 12.92) * boolarray.astype(np.int)
upper = np.power(((img32 + 0.055) / 1.055), 2.4) * np.invert(boolarray).astype(np.int)
img32 = lower + upper

所以,我正在创建一个新数组 boolarray ,其真值为&lt; = 0.04045并乘以。

什么是更好的解决方案?

我尝试过类似的事情:

img32[img32 < 0.04045] = img32 / 12.92

在第一步工作但在第二步失败:

img32[img32 >= 0.04045] = np.power(((img32 + 0.055) / 1.055), 2.4)

可能是因为它包含在 np.power 函数中时不起作用

感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

干净的方式是使用np.where,我们可以根据掩码在两个值之间进行选择。在我们的示例中,掩码可以是img32 >= 0.04045,我们会在((img32 + 0.055) / 1.055)**2.4时选择True,否则请选择img32/12.92

所以,我们会有这样的实现 -

np.where( img32 >= 0.04045,((img32 + 0.055) / 1.055)**2.4, img32/12.92 )

如果你非常关心内存并希望将结果写回到输入数组中,你可以分三步创建并选择性地设置对应于这两个条件的元素,如下所示 -

mask = img32 >= 0.04045
img32[mask] = ((img32[mask] + 0.055) / 1.055)**2.4
img32[~mask] = img32[~mask] / 12.92

示例案例 -

In [143]: img32 = np.random.rand(4,5).astype(np.float32)

In [144]: img32.nbytes
Out[144]: 80

In [145]: mask.nbytes
Out[145]: 20

因此,我们避免创建一个输出数组,该数组会花费我们80个字节,而是在掩码上使用20个字节。因此,在内存中保存75%输入数组大小。请注意,这可能会导致性能略有下降。

答案 1 :(得分:1)

您也可以使用numpy.piecewise

In [11]: img32 = np.random.rand(800, 600).astype(np.float32)

In [12]: img_linear = np.piecewise(img32, 
           [img32  <= 0.04045, img32 > 0.04045], 
           [lambda v: v/12.92, lambda v: ((v + 0.055)/1.055)**2.4] )

In [13]: img_linear.shape
Out[13]: (800, 600)

In [14]: img_linear.dtype
Out[14]: dtype('float32')

答案 2 :(得分:0)

b = (img32 < 0.04045)
img32[b] /= 12.92

not_b = numpy.logical_not(b)
img32[not_b] += 0.05
img32[not_b] /= 1.055
img32[not_b] **= 2.4