Тиснение изображений в Python с PIL-добавлением глубины, азимута и т. д

Я пытаюсь выбить изображение с помощью PIL.

PIL обеспечивает основной способ тиснения изображения (используя ImageFilter.EMBOSS).

в пакетах редактирования изображений, таких как GIMP, вы можете изменять такие параметры, как Азимут, глубина и высота в этом рельефном изображении.

как это сделать с PIL? По крайней мере, я хочу настроить "глубину" рельефного изображения.

обновление: я пробовал вещи, предложенные Павлом (изменение filterargsнапример scale, offset и Матрица), Но я не мог изменить эффект "глубины". Так что все еще ищу ответ.

вот сравнение эффекта тиснения с использованием PIL (слева) и GIMP (справа). Оригинальная картина находится здесь, http://www.linuxtopia.org/online_books/graphics_tools/gimp_advanced_guide/gimp_guide_node74.html.

alt text

2 ответов


если вы не можете достичь своей цели, используя или сочетание операций (например, вращение, затем применение фильтра тиснения, повторное вращение), (или повышение контраста, а затем тиснение), то вы можете прибегнуть к изменению (или созданию собственной) матрицы фильтра.

внутри ImageFilter.py вы найдете этот класс:

##
# Embossing filter.

class EMBOSS(BuiltinFilter):
    name = "Emboss"
    filterargs = (3, 3), 1, 128, (
        -1,  0,  0,
        0,  1,  0,
        0,  0,  0
        )

размещение -1 в другом углу матрицы изменит Азимут и сделает его -2 мая имейте влияние вы смотрите для.

матрица применяется пиксель-на-пиксель. Каждый элемент матрицы соответствует текущему пикселю и окружающим пикселям; центральное значение представляет текущий пиксель. Новый, преобразованный текущий пиксель будет создан как комбинация всех 9 пикселей, взвешенных по значениям в матрице. Например, матрица с нулями и 1 в центре не изменит изображения.

Дополнительные параметры scale и offset. Для встроенного тиснения, значения 1 (масштаб) и 128 (офсет). Изменение этих параметров изменит общую силу результата.

От ImageFilter.py:

# @keyparam scale Scale factor.  If given, the result for each
#    pixel is divided by this value.  The default is the sum
#    of the kernel weights.
# @keyparam offset Offset.  If given, this value is added to the
#    result, after it has been divided by the scale factor.

поскольку я не знаком с эффектами параметра "глубина" GIMP, я не могу сказать, который, скорее всего, сделает то, что вы хотите.

вы также можете сделать матрицу другого размера. Замените (3,3) на (5,5), а затем создайте 25-элементную матрицу.

внести временные изменения в фильтр без пересохранения исходный код, просто сделайте это:

ImageFilter.EMBOSS.filterargs=((3, 3), 1, 128, (-1, 0, 0, 0, 1, 0, 0, 0, 0))

Edit: (принимая включает в себя подхода)

from PIL import Image
import numpy

# defining azimuth, elevation, and depth
ele = numpy.pi/2.2 # radians
azi = numpy.pi/4.  # radians
dep = 10.          # (0-100)

# get a B&W version of the image
img = Image.open('daisy.jpg').convert('L') 
# get an array
a = numpy.asarray(img).astype('float')
# find the gradient
grad = numpy.gradient(a)
# (it is two arrays: grad_x and grad_y)
grad_x, grad_y = grad
# getting the unit incident ray
gd = numpy.cos(ele) # length of projection of ray on ground plane
dx = gd*numpy.cos(azi)
dy = gd*numpy.sin(azi)
dz = numpy.sin(ele)
# adjusting the gradient by the "depth" factor
# (I think this is how GIMP defines it)
grad_x = grad_x*dep/100.
grad_y = grad_y*dep/100.
# finding the unit normal vectors for the image
leng = numpy.sqrt(grad_x**2 + grad_y**2 + 1.)
uni_x = grad_x/leng
uni_y = grad_y/leng
uni_z = 1./leng
# take the dot product
a2 = 255*(dx*uni_x + dy*uni_y + dz*uni_z)
# avoid overflow
a2 = a2.clip(0,255)
# you must convert back to uint8 /before/ converting to an image
img2 = Image.fromarray(a2.astype('uint8')) 
img2.save('daisy2.png')

надеюсь, это поможет. Теперь я понимаю, почему вы были разочарованы результатами пила. Wolfram Mathworld-хороший ресурс для обновления векторной алгебры.

до

alt text

после

alt text


чтобы увеличить глубину тиснения фильтра, увеличьте радиус маски фильтра. Низкая глубина:

h = [[1, 0, 0]
     [0, 0, 0]
     [0, 0, -1]]

по сравнению с высокой глубиной:

h = [[1, 0, 0, 0, 0, 0, 0]
     [0, 0, 0, 0, 0, 0, 0]
     [0, 0, 0, 0, 0, 0, 0]
     [0, 0, 0, 0, 0, 0, 0]
     [0, 0, 0, 0, 0, 0, 0]
     [0, 0, 0, 0, 0, 0, 0]
     [0, 0, 0, 0, 0, 0, -1]]

чтобы изменить Азимут, поместите ненулевые коэффициенты под другим углом:

h = [[0, 0, 1]
     [0, 0, 0]
     [-1, 0, 0]]

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

в любом случае, для вычисления и отображения изображения с помощью Scipy решение:

import scipy.misc, scipy.signal
im = scipy.misc.imread(filename)
im_out = scipy.signal.convolve2d(im, h, 'same')
scipy.misc.imshow(im_out)

надеюсь, что это помогает.

EDIT: хорошо, как намекнул пол с PIL, вы можете настроить параметры фильтра или даже определить совершенно новое ядро. Параметры масштаба и смещения не имеют ничего общего с тем, что вы ищете. Размер фильтра наиболее важен для регулировки глубины.

при дальнейшем исследовании PIL не позволяет изменять размер фильтра за пределами 5x5. Кажется странным. Поэтому, вы не получите как драматическое изменение в глубина, как вы, вероятно, ожидаете.

для полного контроля вы можете попробовать решение Scipy I и Paul, упомянутое ранее. Измените размер фильтра на что-то нелепое, например 21x21, и посмотрите, делает ли это тип разницы, который вы хотите.