
На Хабре есть статья, как получить синемаграфы с помощью бесплатной программы от 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.
