Pull to refresh

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

Reading time3 min
Views11K
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.

Tags:
Hubs:
+17
Comments9

Articles

Change theme settings