Изменение масштаба изображения PIL - PullRequest
3 голосов
/ 25 августа 2009

Какой самый простой / чистый способ изменить масштаб изображения PIL?

Предположим, что у меня есть 16-битное изображение с 12-битной камеры, поэтому используются только значения 0–4095. Я хотел бы изменить масштаб интенсивности так, чтобы использовался весь диапазон 0–65535. Какой самый простой / чистый способ сделать это, когда изображение представлено как тип изображения PIL?

Лучшее решение, которое я нашел, это:

pixels = img.getdata()
img.putdata(pixels, 16)

Это работает, но всегда оставляет четыре младших бита пустыми. В идеале я хотел бы сместить каждое значение на четыре бита влево, а затем скопировать четыре старших значащих бита в четыре младших значащих бита. Я не знаю, как это сделать быстро.

Ответы [ 5 ]

2 голосов
/ 16 сентября 2009

Поскольку вы знаете, что значения пикселей равны 0-4095, я не могу найти более быстрый способ, чем этот:

new_image= image.point(lambda value: value<<4 | value>>8)

Согласно документации , лямбда-функция будет вызываться не более 4096 раз, независимо от размера вашего изображения.

РЕДАКТИРОВАТЬ: Поскольку функция, заданная для точки , должна иметь форму argument * scale + offset для в I изображении, то это лучше всего использовать функцию point:

new_image= image.point(lambda argument: argument*16)

Максимальное значение выходного пикселя будет 65520.

Второй дубль:

Модифицированная версия вашего собственного решения, использующая itertools для повышения эффективности:

import itertools as it # for brevity
import operator

def scale_12to16(image):
    new_image= image.copy()
    new_image.putdata(
        it.imap(operator.or_,
            it.imap(operator.lshift, image.getdata(), it.repeat(4)),
            it.imap(operator.rshift, image.getdata(), it.repeat(8))
        )
    )
    return new_image

Это позволяет избежать ограничения аргумента функции point.

2 голосов
/ 25 августа 2009

Почему вы хотите скопировать 4 мсб обратно в 4 мсб? У вас есть только 12 значащих бит информации на пиксель. Ничто из того, что ты делаешь, не улучшит это. Если у вас все в порядке с интенсивностью 4K, что хорошо для большинства приложений, тогда ваше решение является правильным и, вероятно, оптимальным. Если вам нужно больше уровней затенения, то, как написал Дэвид, пересчитайте, используя гистограмму. Но это будет значительно медленнее.

Но копирование 4 мсб в 4 lsb НЕ является способом:)

2 голосов
/ 26 августа 2009

Вам нужно сделать гистограмму stretch ( ссылка на похожий вопрос, на который я ответил ), а не гистограмма уравнение : растяжение гистограммы http://cct.rncan.gc.ca/resource/tutor/fundam/images/linstre.gif

Источник изображения

В вашем случае вам нужно умножить все значения пикселей на 16 , что является коэффициентом между двумя динамическими диапазонами (65536/4096).

1 голос
/ 25 августа 2009

Что вам нужно сделать, это Выравнивание гистограммы . Как это сделать с помощью python и pil:

EDIT: Код для сдвига каждого значения на четыре бита влево, а затем копирования четырех старших разрядов в четыре младших разряда

def f(n):
   return  n<<4 + int(bin(n)[2:6],2)

print(f(0))
print(f(2**12))

# output
>>> 0
    65664 # Oops > 2^16
0 голосов
/ 11 сентября 2009

Возможно, вам следует пройти 16. (число с плавающей точкой) вместо 16 (целое число). Я пытался это проверить, но по какой-то причине putdata вообще не умножается ... Так что я надеюсь, что это просто работает для вас.

...