2016-09-30 5 views
2

В моем приложении для редактирования изображений У меня есть функция преобразования 32-битного изображения с плавающей точкой из sRGB в линейное цветовое пространство. Формула:Векторизация sRGB для правильного линейного преобразования в Numpy

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

Мое изображение является трехмерным numpy.ndarray имени img32.

Моя реализация до сих пор:

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 со значениями истинности для < = 0.04045 и умножить на это.

Что было бы лучшим решением?

Я пытался что-то вроде:

img32[img32 < 0.04045] = img32/12.92 

, который работает на первом этапе, но терпит неудачу на второй:

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

вероятно потому, что он не работает, когда обернутый в np.power Функция

Любая помощь приветствуется.

+0

'лучше solution' - Лучше как? Память или производительность? – Divakar

+0

Что-то более чистое, потому что это кажется мне чем-то вроде взлома. Я в значительной степени ищу стандартный способ сделать это. Еще не проверял скорость (это достаточно быстро), но я думаю, что это определенно пустая трата памяти? Извините за неясность. – tde

ответ

1

Чистым способом будет 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) 

Если вы заботитесь о памяти много, и хотел бы написать назад результаты в входного массива, можно его в три этапа путем создания и выборочно установить elems, соответствующие этим двум условиям, например, так -

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% размера входного массива. Обратите внимание, что это может привести к небольшому снижению производительности.

+0

Отличное спасибо! – tde

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 
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') 
+0

Спасибо! Я использую np.where на данный момент, но позже я сравню скорость выполнения, чтобы увидеть, что работает быстрее и наиболее эффективно. – tde

 Смежные вопросы

  • Нет связанных вопросов^_^