Tilt-Shift фотографии своими руками

    Что такое Tilt-Shift объективы и что с их помощью можно сделать знают многие. Недавно на хабре была статья о Tilt-Shift генераторе, который создает этот эффект путем обработки обычной фотографии. Но программка эта написана только для Windows, да еще и платить за нее надо. Все плагины для графических редакторов почему-то тоже требовали денег и лицензий. Поэтому было принято решение с этим вопросом разобраться самостоятельно и сделать инструмент пусть немного проще профессионального софта, и не идеально симулирующий оптику объектива, но бесплатный, открытый и доступный всем желающим! Что из этого получилось, а что нет — можете посмотреть сами.

    Начнем с того, что сделаем свою первую миниатюру.
    Приступая к работе, в первую очередь необходимо выбрать фотографию. Нет смысла пытаться обрабатывать изображения, которые не подходят изначально. Преимущественно для этого используются пейзажные, городские снимки, снятые с возвышения — это в первую очередь и помагает создать иллюзию маленького мира. Так же хорошо, если в кадре есть небольшие объекты, такие как транспорт и люди.



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

    Для работы я выбрал эту фотографию:



    После добавления насыщенности и применения фильтров в фотошопе получается такой результат:



    Разумеется, искушенного читателя не проведешь, и настоящий оптический эффект довольно легко отличить от фильтров, но все же при достаточно грамотной постановке кадра подручными средствами можно добиться неплохих результатов.
    По сути все, что пришлось сделать с изображением — наложить искусственное боке в нужных местах и откорректировать насыщенность цвета, которая помогает придать эффект пластиковых моделей объектам в кадре.

    Перейдем к программированию.

    Начнем с простого. Сначала нужно подготовить маску для изображения. Чтобы не загружать себя сразу лишней работой, сделаем ее в фотошопе. В темных местах величина альфа-слоя будет равна максимальному значению, в белых — нулю, то есть изображение в этих местах будет прозрачно.



    В месте с черными пикселями наложения боке происходить не будет и сцена останется в фокусе. Маска была сделана методом “так примерно покатит”, это всего лишь демонстрация подхода.
    Немного поковырявшись в python’е, получился такой небольшой и аккуратный скрипт:

    1. import Image
    2. import sys
    3. import numpy as np
    4. from scipy import ndimage
    5. import ImageEnhance
    6.  
    7. # INIT
    8. blur_size = 6
    9. image_base = "/Users/Mango/Desktop/tiltshift_alpha.png"
    10. image_mask = "/Users/Mango/Desktop/mask_tiltshift.png"
    11. image_output = "/Users/Mango/Desktop/tiltshift_preview.png"
    12.  
    13. # LOAD
    14. im_base = Image.open(image_base)
    15. im_mask = Image.open(image_mask)
    16. im_mask = im_mask.resize(im_base.size)
    17.  
    18. # PROCESS
    19. enh = ImageEnhance.Color(im_base)
    20. im_base = enh.enhance(1.7)
    21. enh = ImageEnhance.Contrast(im_base)
    22. im_base = enh.enhance(1.2)
    23.  
    24. im_blurred = np.array(im_base, dtype=float)
    25. im_blurred = ndimage.gaussian_filter(im_blurred, sigma=[blur_size,blur_size,0])
    26. im_blurred = Image.fromarray(np.uint8(im_blurred))
    27. im_mask = im_mask.convert("L")
    28. im_base = im_base.convert("RGBA")
    29.  
    30. # MERGE AND SAVE
    31. im_base.paste(im_blurred,mask=im_mask)
    32. im_base.save(image_output)

    Вначале получаем исходное изображение и маску, затем размер маски подгоняется под размер изображения и начинается обработка. С помощью модуля ImageEnhance регулируются такие показатели как цвет, яркость и контраст. После чего в im_blurred сохраняется копия изображения в виде массива. Для создания боке я использовал старый добрый фиьтр размытия Гаусса. Его результат отличается от того же Lens Blur в профессиональных редакторах, но для начала вполне неплохой результат.
    На финальной стадии размытое изображение накладывается на наш оригинал, используя альфа-маску. Так же стоит учесть, что каждый слой должен иметь правильную палитру. Маска используется в монохромном режиме L, а исходному изображению при помощи convert(«RGBA») добавляется альфа-слой, который и позволяем с помощью маски накладывать второй слой.
    Вот что получилось в итоге:



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



    В еще более упрощенном виде эту модель можно представить следующим образом:



    Вся система задается несколькими параметрами: направление, длина вектора А, зоны фокусировки и вектора Б. Все расстояния для простоты задаем по оси y.
    Построение градиента происходит следующим образом. Сначала по заданным расстояниям строится изображение шириной в один пиксель, оно будет выступать в роли паттерна. После чего разными манипуляциями можно придать ему любую форму и повернуть на нужный угол.
    Немного поэкспериментировав у меня получилась такая функция:

    1. import Image
    2. import ImageDraw
    3. import ImageOps
    4. import math
    5.  
    6. def draw_mask(angle,width,height,offset_init,offset_A,offset_focus,offset_B):
    7. offset = height*offset_init/100
    8. vectorA = offset+offset_A*height/100
    9. focus = vectorA+offset_focus*height/100
    10. vectorB = focus+offset_B*height/100
    11.  
    12. mask = Image.new('L'(width,height))
    13. mask_1px = Image.new('L'(1,height))
    14. draw_1px = ImageDraw.Draw(mask_1px)
    15. for y in range (0,offset)# draw white zone
    16. draw_1px.point((0,y),255)
    17. for y in range (offset,vectorA)# draw vectorA
    18. draw_1px.point((0,y),(vectorA-y)*(255/(vectorA-offset)))
    19. for y in range (vectorA,focus): # draw white zone
    20. draw_1px.point((0,y),0)
    21. for y in range (focus,vectorB): # draw vectorB
    22. draw_1px.point((0,y),255-(vectorB-y)*(255/(vectorB-focus)))
    23. for y in range (vectorB,height)# draw white zone
    24. draw_1px.point((0,y),255)
    25.  
    26. m_width,m_height = mask.size
    27. mask_1px = mask_1px.resize((int(m_width*3),m_height), Image.ANTIALIAS)
    28. mask_1px = ImageOps.invert(mask_1px)
    29. mask_top = mask_1px.rotate(angle,Image.NEAREST,1)
    30. mask_top = ImageOps.invert(mask_top)
    31.  
    32. mask.convert("RGBA")
    33. n_width,n_height = mask_top.size
    34. mask.paste(mask_top,(-n_width/2,-(n_height/2-height/2)))
    35. mask.convert("L")
    36. return mask



    Этот код учитывает угол поворота на случай, если захочется сделать инструмент более универсальным или прикрутить к веб-интерфейсу, чем я и собираюсь заняться в ближайшем будущем.
    Если кому понадобятся исходники, финальная версия есть на github.
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 60
    • +5
      Супер! Надеюсь, скоро появится веб-версия с возможностью загружать фотки и выгружать уже откорректированные.
    • +6
      В фотошопе это делается 2-5 простыми движениями (без использования дополнительных плагинов), если кому интересно, могу написать. Вот, что получается:

      Смотреть результат >>>

      Правда, конечно, Photoshop — не бесплатное решение, и свободный открытый скрипт — это круче! Так что, автору — спасибо и респект!
      • +1
        PS. Хотя, принцип, почти не отличается. Кто владеет на начальном уровне фотошопом, сделает тоже самое и сам, достаточно описаний метода в топике. В качестве инструмента (фильтра) размытия надо использовать Lens Blur.
        • +2
          Опишите по шагам, пожалуйста.
          • +2
            Берем исходную фотку, нажимаем Q (QuickMask), выбираем Gradient Tool (G) от черного к белому, опция Reflected Gradient и ведем от центра изображения к краю. Снимаем маску (Q) и применяем фильтр Lens Blur с подходящим радиусом.
            Итог sanneo.ru/images/tilt.jpg
            Времени заняло
            • +1
              Добавлю еще, что в опциях Lens Blur есть интересные пресеты, имитирующее различные объективы (т.е. размытие или боке, которое они дают). Конечно, имитация есть имитация, но все-же лучше, чем ничего…
              • +1
                Также добавлю, что необязательно именно от центра к краю, но можно таким образом «в резкости» оставить любой участок фотографии, который хотите «выделить».
                • +1
                  … и последним шагом, естественно, играем с Тоном/Насыщенностью (CTRL+U), Уровнями (CTRL+L) и если нужно, другими настройками. Если не получается, говорите, где заминка, поможем.
              • 0
                А в CS6 даже встроенный tilt-shift уже есть :)
                • +1
                  Сделал подобную вещь на бесплатном фотошопе за 1минуту.

                  image
                  Но скрипт тоже интересное решение.
                  • +2
                    Нелохой редактор, кстати, не видел его раньше. Если бы можно было бы слои группировать, было б вообще супер. Мне этого так не хватает в GIMP.
                    • +4
                      Если бы можно было бы слои группировать, было б вообще супер. Мне этого так не хватает в GIMP.

                      Выпущен GIMP 2.7.5 с опциональным однооконным интерфейсом и возможностью группировать слои.
                      • 0
                        Спасибо, надо потестить. Я ждал ради этого 2.8, думал, до выхода 2.8, думал, не видать мне групп слоев.
                  • +5
                    Вы не понимаете. Этот эффект, судя по всему, должны будут реализовать на всех языках программирования, включая брейнфак )
                  • +12
                    Обязательно посмотрите видео «Игрушечный Киев»: vimeo.com/38388574. Использовался обычный объектив, а эффект Tilt-Shift накладывался программно. И кстати, у ребят как-то натуральнее получилось это сделать.
                    • +7
                      Holy Shift! Впечатляющее видео!
                      • +3
                        Мне понравилось, но «программность» видна невооружённым взглядом. Шарма это обстоятельство не добавляет.
                        Чтобы сделать эффект качественно, нужна как минимум карта расстояний. Объекты в плоскости фокусировки не размываются, чем дальше от этой плоскости, тем сильнее размытие. Это либо достаточно кропотливая ручная работа в фотошопе, либо весьма и весьма умный алгоритм, умеющий считать расстояния по одной фоторгафии.

                        Что касается алгоритма, то как минимум нужно использовать что-то похожее habrahabr.ru/post/95541/.
                        • 0
                          Ещё один впечатляющий ролик: The City Of Samba
                          • 0
                            Великолепное видео и отличный саундрек. Очень круто.
                            • +1
                              Специально залогинился, чтобы поделиться ссылкой
                              Ляпис Трубецкой — Я верю
                            • +1
                              Я бы маску сделал более плавной по краям, слишком резко она «обравается», и это видно на конечном результате. Можно сделать ее пошире и переходы по краям более плавными. Будет лучше. ИМХО.
                              • +3
                                Нормальные Tilt-Shift все-равно отличаются от размытия в Фотошопе и иже с ним (к тому же, на примере в посте размытие слишком сильное). На первый взгляд похоже и прикольно, но не то, имхо.

                                У меня, кстати, есть мыльница от Canon, у которой есть встроенный эфект Tilt-Shift (пример: img-fotki.yandex.ru/get/6103/15097144.4a/0_5d54d_5affdb05_XL.jpg), но все-равно это не то.

                                А вообще самый смак — это не фотки, а видео, если еще и в режиме Slow Motion…

                                • 0
                                  Конечно не то! Но хороший tilt-shift объектив стоит зачастую как две хорошие зеркальные тушки, или даже как один вполне себе живой подержанный относительно свежий бюджетный автомобиль. Пока он еще не появился в собственном распоряжении, поиграться иной раз хочется. Просто ради собственного удовольствия. А если это доставляет удовольствие кому-то еще, то вообще супер. Но с настоящей оптикой — да еще и хорошей — не сравнится никакое программное решение, даже самое-самое.
                                • +3
                                  В принципе, если интересуют инструменты с открытым исходным кодом, такое можно запросто сделать в узловом редакторе Blender.

                                  Боке на этом изображении не видно, но среди есть куча узлов на все случаи жизни. Блюр тут даже не пригодился из-за наличия defocus, а вот тона подкрутить или перспективу — с этим любую сцену можно превратить в игрушку :)

                                  Маску тоже можно генерировать процедурно, просто мне лень было в соседнюю панель лезть. Но любой человек, работавший с композерами подтвердит, что Tilt-shift по предложенной модели делается в полпинка (тут не могу не вспомнить эту статью)
                                  • 0
                                    неожиденное применение блендеру!
                                    • +1
                                      А ещё можно потратить на 15 минут больше и нарисовать все вертикальные плоскости в виде 3d-фигур — и уже от них брать z-координату.
                                      А то у вас вот, например, центральное здание — полная лажа, как и у топикстартера.
                                      • 0
                                        Когда статью увидел, сам захотел тоже самое сделать :)
                                      • +3
                                        Но программка эта написана только для Windows, да еще и платить за нее надо. Все плагины для графических редакторов почему-то тоже требовали денег и лицензий.

                                        Ну. Не все: «GIMP plug-in Toy для имитации тильт-шифта» (страница модуля в реестре расширений GIMP).
                                        • 0
                                          Все равно видно, что тилта как такового нет.
                                          • +8
                                            А не лучше посидеть пару минут и нарисовать нормальную маску глубины? Будет «на глаз», конечно, но и обычные градиентные маски рисуются «на глаз». image
                                            • +2
                                              А можно ссылку на оригинал?
                                              Если эта маска — ручная работа — снимаю шляпу!
                                              • 0
                                                Нет, это отдельный канал с глубиной резкости отрендеренной трёхмерной сцены. Но, чисто теоретически, такое можно и руками нарисовать, пусть и не так четко. Всё-равно, при размытии маски, детали, скорее всего, пропадут. Нужно попробывать.
                                              • 0
                                                Да, это самый правильный подход. К тому же, прекрасно вписывающийся в использование гимпового плагина focus blur, у которого есть карта расстояний.
                                                • +2
                                                  На самом деле это выглядит как плохая фотография.
                                                  • 0
                                                    Может и так, я просто такую же методику применил как описано выше. Я же не специалист.
                                                • +1
                                                  Ну и конечно же ImageMagick: www.imagemagick.org/Usage/photos/#tilt_shift
                                                  • –2
                                                    Спасибо за статью, вырасту кармой, проголосую )
                                                    вот 5 минут поигрался в Snapseed на ipad. Прикольно, но фотки действительно надо подбирать. Не все подходят.





                                                    • +5
                                                      Классический пример ДБЛ
                                                      • –1
                                                        Классический пример БЛД
                                                        • +6
                                                          Как ни назови, а До Было Лучше
                                                          • –1
                                                            Ну извините, что загадил топик. Учту.
                                                    • +2
                                                      Большинство услуг человечество предоставляет за деньги из-за нежелания постигать нюансы услуги другой частью, и это правильно." Робин Гуды" выступают «Робин Гудами» только для малой части. Ура опен сорцу — ленивый платит, любознательный получает бесплатно новые знания и и услугу.
                                                      • +1
                                                        Баловство это всё, основное применение TS — предметка, когда надо повернутый объект уместить в ГРИП. TS как раз поворачивает плоскость резкости относительно матрицы фотоаппарата.
                                                        • +2
                                                          лучше бы обьективы TS делали доступные
                                                          • 0
                                                            я купил себе бюджетный вариант — lensbaby edge 80

                                                            результат:
                                                            image

                                                            image

                                                            image
                                                            • 0
                                                              во сколько обошлось?
                                                              • 0
                                                                я покупал 2 оптики сразу — Composer Pro with Sweet 35 + Edge 80 — вместе вышло $660
                                                                есть ощущение немного игрушечности от этих объективов, но приятно с ними «играться» :)
                                                                • 0
                                                                  а картинка как по ощущениям, фоточки маленькие не очень понятно…

                                                                  хотя картинка у них интересная судя по фоточкам выше
                                                                  • 0
                                                                    я не очень доволен качеством — шумы лезут, если темное фото. но для интернета — подойдет.
                                                                    нравится, как размывает — там 2.8 диафрагма
                                                                    снимал ночью — вообще интересные кадры получаются
                                                                    вот пример большой фотографии — farm8.staticflickr.com/7201/6942922685_de8f63383c_b.jpg
                                                              • 0
                                                                Фото с велосипедом странное.
                                                                Линия неразмытого изображения проходит от левого угла терассы, через голову спыщего мужика в правый нижний угол.
                                                                Какие-то странные ощущения при просмотре.
                                                                • 0
                                                                  угол меняется, но не всегда, когда хочется сделать быстрый кадр, есть возможность оперативно подобрать «правильный» угол
                                                                  • 0
                                                                    Ну я так и понял. Просто из-за неестественности размытости фотография немного странно выглядит
                                                              • +1
                                                                А вот тут замечательнейшее tilt-shift video, смонтированное из 4500 фото.
                                                              • 0
                                                                Забавно, но если набрать в гугл tild, то страница чуть повернется :) Извините за оффтоп…
                                                              • 0
                                                                В продолжение темы



                                                                Подобный скрипт на языке Processing. Радиус фильтра увеличивается по вертикали.

                                                                int N=8;
                                                                PImage[] imgs=new PImage[N];
                                                                for (int k = 0; k < imgs.length; k++) {
                                                                imgs[k]=loadImage(«test.png»);
                                                                }
                                                                for (int k = 1; k < imgs.length; k++) {
                                                                imgs[k].filter(BLUR,k-1);
                                                                }
                                                                PImage out = createImage(imgs[0].width,imgs[0].height,RGB);

                                                                for (int i = 0; i < imgs[0].width*imgs[0].height; i++) {
                                                                int h=floor(i/imgs[0].width);
                                                                int a=floor(N*h/imgs[0].height);
                                                                out.pixels[i]=imgs[N-a-1].pixels[i];
                                                                }
                                                                size(imgs[0].width,imgs[0].height);
                                                                image(out,0,0);

                                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.