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

в 14:15, , рубрики: 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.

Автор: zurbaganin

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js