Работа с видео
Создадим новый скетч под именем playing_video.pde.
Добавим видеофайл в папку data скетча путем перетаскивания видеофайла в
окно Processing.
Сначала импортируем библиотеку video. Откройте меню Sketch | Import
Library | video. Также нужно объявить объект класса Movie перед функцией setup(). В
функции setup() мы загрузим видеофайл с жесткого диска и запустим видео в режиме
повторения.
Функция movieEvent() нужна для чтения кадров с
видеофайла. Функция movieEvent() автоматически вызывается каждый раз, когда доступен новый
кадр. Для захвата кадра нужно использовать метод read() класса Movie. Вывести этот
кадр на экран можно с помощью функции image().
В draw() выведем на экран текущий кадр с помощью функции
image().
import processing.video.*;
Movie m;
void setup()
{
size( 640, 480 );
// Загружаем файл из папки data
m = new Movie( this, "cat.mov" );
m.loop();
}
void draw()
{
background( 0 );
image( m, 0, 0, width, height );
}
void movieEvent( Movie m )
{
m.read();
}
Экспорт последовательности изображений
GStreamer
framework позволяет экспортировать вашу работу в виде последовательности изображений, чтобы затем создать из них видео.
Ниже приведен полный код для этого примера. Используются объекты PVector для рисования на экране линий и кругов, движущихся по принципу Броуновского движения. Когда
скетч достигнет 900-го кадра, приложение остановится.
int randomNum;
PVector[] points;
float radius = 2;
void setup()
{
size( 1280, 720 );
smooth();
background( 234, 228, 17 );
points = new PVector[64];
for ( int i = 0; i < points.length; i++ ) {
points[i] = new PVector(random(width), random(height));
}
frameRate( 30 );
randomNum = floor( random( 10000, 90000 ) );
noFill();
stroke( 0, 64 );
}
void draw()
{
for ( int i = 0; i < points.length; i++ ) {
float newX = points[i].x + random( -10, 10 );
float newY = points[i].y + random( -10, 10 );
stroke( i*4, 64 );
line( points[i].x, points[i].y, newX, newY );
ellipse( newX, newY, radius, radius );
points[i].x = newX;
points[i].y = newY;
}
radius++;
if ( radius > 10 ) {
radius = 2;
}
saveFrame("images/export-"+randomNum+"-#####.tga");
// save 900 frames = 30 sec @ 30 fps
if ( frameCount >= 900 ) {
exit();
}
}
После запуска скетча вы найдете в папке images в папке вашего скетча
последовательность изображений типа TGA.
Самое важное в создании видео - это правильно установить размер и частоту кадров в
функции setup(). В примере задан размер кадра 1280 x 720 пикселей и частоту
кадров 30 кадров в секунду. Это даст вам представление о том, как будет выглядеть видео
когда вы запустите скетч. Этот формат видео хорош для размещения видео на таких вебсайтах как Vimeo и YouTube. Но обратите внимание, что если в каждом кадре вы делаете
сложные вычисления, это может притормозить скетч и реальная частота кадров будет
меньше, чем та, которую вы укажете в функции frameRate().
Каждый кадр будет сохранен с помощью функции saveFrame(). В имени файла
изображения используется случайное целое число под именем randomNum, поэтому в
одной и той же папке можно сохранить несколько последовательностей изображений.
Сделать выход из скетча после сохранения последовательности изображений также будет
хорошей идеей. Это делается с помощью функции exit(). Если нужно 30-скекундное
видео, понадобится сохранить 900 кадров. Рассчитать это количество просто: число
кадров в секунду x число секунд = количество кадров.
Последовательность изображений сохраняется в формате TGA. Это самый простой способ
сохранить изображения в Processing, так как формат TGA не сжимается. Вы можете
использовать PNG или JPEG, но помните, что это замедлит ваш скетч.
Работа с отдельными пикселями видео
Мы можем изменить отображение видео на экране, изменив цвет некоторых пикселей.
import processing.video.*;
Movie m;
int numPixels;
void setup()
{
size( 640, 480 );
numPixels = width * height;
m = new Movie( this, "marbles.mov" );
m.loop();
}
void draw()
{
background( 0 );
image( m, 0, 0, width, height );
loadPixels();
for ( int i = 0; i < numPixels; i++ ) {
float b = brightness( pixels[i] );
if ( b > 245 ) {
pixels[i] = lerpColor( pixels[i], color(0, 0, 0), map(b, 0, 255,
0, 1));
}
}
updatePixels();
}
void movieEvent( Movie m )
{
m.read();
}
Сначала импортируем библиотеку video,
объявляем объект Movie, загружаем видеофайл и запускаем непрерывное проигрывание.
В методе draw() выводим каждый
кадр на экран с помощью функции image(). После этого мы изменяем цвет тех пикселей,
яркость которых меньше 245.
После вывода изображений на экран вызывается функция loadPixels() для загрузки
всех пикселей с экрана в массив пикселей. Для прохода по всем пикселям и проверки
яркости используется цикл for. Для тех пикселей, которые ярче 245, цвет пикселя
смешивается с черным. После замены цветов вызывается функция updatePixels() для
показа на экране нового изображения.
Функция lerpColor() используется для смешивания двух цветов. Первые два параметра
этой функции используются для указания цветов, которые вы хотите смешать, а третий
параметр определяет, каким образом цвета будут смешиваться. Этот параметр находится
в диапазоне от 0 до 1. Если вы запишете 0.1, результирующий цвет будет ближе к первому
цвету. Если вы запишете 0.9, то он будет больше похож на второй цвет. Для смешивания
цветов в равных пропорциях вы можете указать в третьем параметре 0.5.
Если яркость вашего видео меньше, чем этого, вы можете снизить границу яркости. Это
приведет к другому результату. Также для установки границы яркости вы можете
использовать значения hue() и saturation() каждого пикселя.
Фильтры
Функция filter() позволяет устанавливать фильтры на видео. Добавьте новую строчку кода после вызова image() из предыдущего примера.
image( m, 0, 0, width, height );
filter( POSTERIZE, 4 );
Можно устанавливать следующие режимы.
- BLUR: этот режим применяет к пикселям на экране фильтр размывания Гаусса. Второй параметр устанавливает радиус размывания. Если вы не укажете этот параметр то радиус размытия будет равен 1 пикселю. Но помните, что если вы используете большой радиус размывания, ваш скетч замедлится.
- DILATE: этот режим увеличивает освещенные области изображения. Это удобно, если вы хотите снизить контрастность.
- ERODE: этот режим действует обратно режиму DILATE - уменьшает освещенные участки изображения. Вы можете применять его для уменьшения контрастности изображения.
- GRAY: этот режим конвертирует все цвета видео в оттенки серого.
- INVERT: в этом режиме изображение превращается в негатив.
- OPAQUE: этот режим переключает канал альфа изображения на непрозрачность.
- POSTERIZE: этот режим уменьшает количество цветов в изображении. Второй параметр служит для установки количества цветов.
- THRESHOLD: этот режим делает все пиксели черными и белыми.
Управление скоростью видео
Можно увеличивать скорость просмотра видео, а также уменьшать или смотретьв обратном порядке. В setup() установим скорость 1.0. В функции draw() выводим на экран текущий кадр с помощью функции image(). Также выведем на экран значение переменной speed с помощью функции text(). Функция mousePressed() будет устанавливать скорость видео. Мы преобразуем значение переменной mouseX до диапазона от -2 до 2. Для установки скорости проигрывания
согласно этой величине мы используем метод speed() класса Movie.
import processing.video.*;
Movie movie;
float speed;
void setup()
{
size(640, 480);
movie = new Movie(this, "cats.mov");
movie.loop();
speed = 1.0;
}
void draw() {
background(0);
image(movie, 0, 0, width, height);
fill(0);
text("Speed: " + speed, 20, 20);
}
void movieEvent(Movie movie) {
movie.read();
}
void mousePressed() {
speed = map(mouseX, 0, width, -2, 2);
movie.speed(speed);
}
Метод speed() класса Movie используется для установки скорости проигрывания видео.
Если указать скорость 1.0, видео будет проигрываться с нормальной скоростью. Если
скорость будет равна 0.5, видео будет проигрываться с половинной скоростью. Для
ускорения видео установите скорость больше 1.0. Отрицательное значение запустит
проигрывание в обратном порядке.