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