Python 在Numpy中正确地将sRGB矢量化为线性转换

Python 在Numpy中正确地将sRGB矢量化为线性转换,python,numpy,vectorization,color-space,srgb,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) 可能是因为它被包装在np.power函数中时不起作用 非常感谢您的帮助。一个干净的方法是让我们根据掩码在两个值之间进行选择。在我们的例子中,掩码可以是img32>=0.04045,我们将在True时选择((img3

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

if value <= 0.04045: (value / 12.92)
if value > 0.04045: ((value + 0.055) / 1.055)^2.4)
可能是因为它被包装在np.power函数中时不起作用

非常感谢您的帮助。

一个干净的方法是让我们根据掩码在两个值之间进行选择。在我们的例子中,掩码可以是
img32>=0.04045
,我们将在
True
时选择
((img32+0.055)/1.055)**2.4
,否则选择
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

如果您非常关心内存,并且希望将结果写回输入数组,那么可以通过创建并有选择地设置与这两个条件对应的元素(如下所示),分三步完成-

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%。请注意,这可能会导致性能略有下降。

b=(img32<0.04045)
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
img32[b]/=12.92 not_b=numpy.logical_not(b) img32[not_b]+=0.05 img32[非b]/=1.055 img32[非欧元区]**=2.4
您还可以使用:

[11]中的
:img32=np.random.rand(800600).astype(np.float32)
[12]中:img_线性=np.分段(img32,
[img32 0.04045],
[lambda v:v/12.92,lambda v:((v+0.055)/1.055)**2.4])
In[13]:img_线性形状
Out[13]:(800600)
在[14]中:img_linear.dtype
Out[14]:数据类型('float32')

更好的解决方案
-如何更好?内存方面还是性能方面?一些更干净的东西,因为在我看来这有点像黑客。我正在寻找一种标准的方法来做这件事。还没有测试过速度(相当快),但我想这肯定是在浪费内存?抱歉说不清楚,谢谢!我现在使用的是np.where,但稍后我会比较一下执行速度,看看什么运行得最快,效率最高。相反的是(与sRGB呈线性关系):
img=np.where(img<0.0031308,img*12.92,1.055*(pow(img,(1.0/2.4))-0.055)
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
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')