Книга: Написание скриптов для Blender 2.49

Now, strip — создание киноленты из анимации

Now, strip — создание киноленты из анимации

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

Хотя тут больше изображений для объединения, чем при нескольких видах камер, код для создания такой киноплёнки довольно похож.


Первой функцией, которую мы разрабатываем, будет strip() (лента), которая берет список имён файлов изображений для объединения, и необязательное имя, которое будет дано комбинированному изображению. Третий дополнительный аргумент - cols,  количество колонок в комбинированном изображении. По умолчанию он равен четырём, но для длинных последовательностей может быть более естественным печатать их на горизональной бумаге, и использовать здесь большую величину. Функция возвращает объект Image Блендера, содержащий комбинированное изображение.

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

def strip(files,name='Strip',cols=4):
   rows = int(len(files)/cols)
   if len(files)%int(cols) : rows += 1
   im = pim.open(files.pop(0))
   w,h= im.size
   edge=2
   edgecolor=(0.0,0.0,0.0)
   comp =  pim.new(im.mode,
                   (w*cols+(cols+1)*edge,
                   h*rows+(rows+1)*edge),
                   edgecolor)
   for y in range(rows):
      for x in range(cols):
         comp.paste(im,(edge+x*(w+edge),edge+y*(h+edge)))
         if len(files)>0:
            im = pim.open(files.pop(0))
         else:
            comp.save(name,format='png')
            return Image.Load(name)

Функция  render(), которую мы определяем, принимает количество пропускаемых кадров в виде аргумента и рендерит любое количество кадров между начальным и конечным кадрами. Эти начальный и конечный кадры могут быть заданы пользователем в панели кнопок рендера. Эти кнопки рендера также содержат величину шага, но эта величина не доступна в API Питона. Это означает, что наша функция будет несколько избыточнее, чем нам хотелось бы, так как мы должны создать цикл, который рендерит каждый отдельный кадр (выделено в следующем коде) вместо прямого вызова  renderAnim(). Следовательно, мы должны манипулировать атрибутами startFrame и endFrame контекста рендера (как и раньше), но мы будем осторожными и восстановим эти атрибуты перед возвратом списка имён файлов отрендеренных картинок. Если бы мы не нуждались в каком-либо программном контроле значения величины пропуска, мы могли бы просто заменить вызов render() вызовом renderAnim():

def render(skip=10):
   context = Scene.GetCurrent().getRenderingContext()
   filenames = []
   e = context.endFrame()
   s = context.startFrame()
   context.displayMode=0
   for frame in range(s,e+1,skip):
      context.currentFrame(frame)
      context.startFrame(frame)
      context.endFrame(frame)
      context.renderAnim()
      filenames.append(context.getFrameFilename())
   context.startFrame(s)
   context.endFrame(e)
   return filenames

После определения этих функций сам скрипт теперь просто вызывает render(), чтобы создавать изображения, и strip(), чтобы объединить их. Результирующее изображение Блендера перезагружается (reload) для его обновления на экране, если изображение с таким именем уже присутствовало, затем все окна перерисовываются (выделено):

def run():
   files = render()
   im=strip(files)
   bpy.data.images.active = im
   im.reload()
   Window.RedrawAll()
if __name__ == "__main__":
   run()

Полный код доступен как strip.py в файле combine.blend.

Оглавление книги


Генерация: 1.469. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз