Создаем движущиеся картинки с помощью Processing

image

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

Чтобы получить требуемую анимацию, необходимо редактировать альфа-канал каждого кадра. В качестве исходных картинок для скрипта я использовал серию снимков свечи. После запуска скрипта на экране появится только один неподвижный фоновый кадр. Кликайте на изображении в том месте, где хотите увидеть анимацию. Алгоритм работает в реальном времени. Для сохранения анимации нажмите клавишу «s». В папке со скетчем появится директория «out», в ней находятся кадры выходной анимации. Далее загружаем Gimp, открываем полученные изображения как слои и сохраняем их в формате gif, как анимацию. Вот исходный текст скрипта.

// Zurbaganin
// 2012

int nFrames =15; // количество кадров
PImage[] imgs = new PImage[nFrames]; // Массив кадров
PImage brush=new PImage (63, 63, RGB);//Создаем пустую кисть для рисования в альфа-канале

void setup() {
  background(255);
  createBrush();//генерируем кисть для рисования в альфа-канале

  size(1024, 768, P3D);//устанавливаем формат экрана
  frameRate(25); // частота кадров

  for (int k = 0; k < imgs.length; k++) {
    String imgName = nf(k, 2) + ".png";// генерируем имена файлов исходных картинок 
    imgs[k] = loadImage(imgName);//загружаем картинки в массив
    imgs[k].format=ARGB;//конвертируем картинки в 32-битный формат
  }
  nullAlpha();////Делаем все кадры прозрачными кроме первого
}
void draw() {
  int frame = frameCount % (nFrames);// генерируем указатель массива в зависимости от порядкового номера кадра скетча
  image(imgs[frame], 0, 0);//отображаем массив картинок как анимацию
}

void createBrush() //создаем кисть для рисования в альфаканале
{
  for (int i = 0; i < brush.height; i++) {
    for (int j = 0; j < brush.width; j++) {
      float gr;
      float a=dist(brush.width/2, brush.height/2, j, i);
      gr=92*(1-a/dist(brush.width/4, brush.height/4, 0, 0));
      brush.pixels[i*brush.width+j]=color(gr);
    }
  }
}

void mousePressed() //создаем окна с движущимися объектами.
//По нажатию левой клавиши указанная область перестает быть прозрачной
{
  if (mouseButton == LEFT) {
    for (int k = 1; k < imgs.length; k++) {
      for (int i = 0; i < brush.height; i++) {
        for (int j = 0; j < brush.width; j++) {
          int i1=mouseY-brush.height/2+i;
          int j1=mouseX-brush.height/2+j;

          float r=(int)red(imgs[k].pixels[i1*imgs[k].width+j1]);
          float g=(int)green(imgs[k].pixels[i1*imgs[k].width+j1]);
          float b=(int)blue(imgs[k].pixels[i1*imgs[k].width+j1]); 
          float a=(int)alpha(imgs[k].pixels[i1*imgs[k].width+j1]); 

          a=a+(int)red(brush.pixels[i*brush.width+j]);   
          if (a>255) {
            a=255;
          }
          // float a=255;

          imgs[k].pixels[i1*imgs[k].width+j1]=color(r, g, b, a);
        }
      }
    }
  }
}
void nullAlpha()//Делаем все кадры прозрачными кроме первого
{
  for (int k = 1; k < imgs.length; k++) {
    for (int i = 0; i < imgs[k].height; i++) {
      for (int j = 0; j < imgs[k].width; j++) {

        float r=(int)red(imgs[k].pixels[i*imgs[k].width+j]);
        float g=(int)green(imgs[k].pixels[i*imgs[k].width+j]);
        float b=(int)blue(imgs[k].pixels[i*imgs[k].width+j]); 
        float a=(int)alpha(imgs[k].pixels[i*imgs[k].width+j]);   
        a=0;//добавляем прозрачность с помощью альфаканала
        imgs[k].pixels[i*imgs[k].width+j]=color(r, g, b, a);
      }
    }
  }
}

void keyPressed() {
  if (key == 's' || key == 'S') {//сохраняем редактированные картинки в отдельную папку

    for (int k = 1; k < imgs.length; k++) {
      for (int i = 0; i < imgs[k].height; i++) {
        for (int j = 0; j < imgs[k].width; j++) {


          float r, g, b;
          float a=(int)alpha(imgs[k].pixels[i*imgs[k].width+j]); 

          if (a==0) {
            r=(int)red(imgs[0].pixels[i*imgs[0].width+j]);
            g=(int)green(imgs[0].pixels[i*imgs[0].width+j]);
            b=(int)blue(imgs[0].pixels[i*imgs[0].width+j]);
          } 
          else
          {
            r=(int)red(imgs[k].pixels[i*imgs[k].width+j]);
            g=(int)green(imgs[k].pixels[i*imgs[k].width+j]);
            b=(int)blue(imgs[k].pixels[i*imgs[k].width+j]);
          }

          a=255;
          // float a=255;

          imgs[k].pixels[i*imgs[k].width+j]=color(r, g, b, a);
        }
      }
    }

    for (int k = 0; k < imgs.length; k++) {
      imgs[k].save("/out/"+nf(k, 6)+".png");
    }
  }
}


Для нормальной работы скрипта, исходные изображения необходимо сохранить в формате png 1024х768 точек и переместить в директорию скетча. Имена файлов должны иметь вид: «01.png, 02.png … **.png». Укажите в коде ваше количество кадров, с помощью параметра nFrames.

Данный видеоролик демонстрирует работу программы.
Processing — свободное ПО, не требует установки, прекрасно работает под Linux и Windows.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 9

    0
    Совсем недавно пытался делать синемаграфы с помощью Cliplets. Для этого снимал короткие ролики в FullHD и программой вырезал нужную движущуюся область, но программа сохраняет только в видео формат и приходилось конвертировать его в множество изображений, которые опять надо собирать gif-аниматором, при этом надо найти нужные кадры. Вообщем получается 1.Cliplets>2.конвертер>3.аниматор. Cliplets обрезает видео (настроек у него не нашел), конвертеры (особенно онлайн) пережимают, аниматоров перепробовал кучу и так удобного и не нашел! Кое какие результаты получил, но совсем не то что ожидал. В итоге забил на это дело, слишком хлопотно. Возможно кто-то знает более простое решение?

    За скрипт отдельное спасибо.
      +1
      Самому написать программу? Библиотеки, думаю, есть…
        0
        Не программист, потому и способ описанный автором топика не то что хотелось бы.
          +1
          Программировать не нужно. Скачайте архив. В новый проект вставьте приведенный код. В директорию с кодом скопируйте изображения из которых хотите сделать анимацию. После нажатия кнопки RUN кликайте в тех точках, где должна быть анимация. Клавиша S сохраняет результирующие кадры в папку OUT. С помощью VirtualDub полученные кадры легко конвертировать в GIF — картинку.
            +1
            так вот что такое user friendly usability
          +1
          Думаете…
          OpenCV — рекомендую.
          +1
          Стандартное GIF изображение содержит только 256 цветов. Поэтому Вас и не устраивает результат. Проще всего конвертировать видео в GIF анимацию в бесплатном редакторе VirtualDub.
            +1
            Photoshop CS 5.1 может видео открывать, для сохранения его как gif в меню file выбрать Save for web & devices. Про FullHD можно забыть.
            +2
            Ознакомительная статья о Processing 1.0 на Хабре здесь

            Вот еще один пример работы алгоритма на основе видео



            Only users with full accounts can post comments. Log in, please.