вторник, 12 февраля 2013 г.

PixiVisor - передача видео через звук

Расскажу об одной необычной программе, которую выпустил несколько дней назад. Будет здорово, если найдутся люди, которым это окажется так же интересно, как мне. 
Это PixiVisor 
В основе - передача видеосигнала через звук.



Идея


Увлекаясь всякими странными штуками, я уже давненько вынашиваю план создания записывающего устройства для нарезки грампластинок, дабы получить твердую копию своей музыки, которую потом можно и увидеть и потрогать. И как-то задумавшись о применении такого аппарата, в голову пришла мысль: "а почему бы не записать на пластинку видео?" Для этого всего лишь потребуется последовательно преобразовывать каждый кадр в звук. И самый простой способ преобразования - построчно сканировать изображение, а яркость пикселя рассматривать как амплитуду отсчета (сэмпла). 
Для этого подойдет любой компьютер с дешевой звуковой картой. В качестве базовой частоты дискретизации выберем самую распространенную - 44100 Гц. Оптимальное разрешение - 64 на 64 пикселя. Кадровая частота = 44100 / ( 64 * 64 ) = 10.76. Не так уж много для качественной картинки, но для экспериментов вполне сойдет. 
Но представив реализацию этого алгоритма на базе двух компьютеров, обменивающихся изображением по аудио кабелю или через микрофон, стало ясно, что применение такой техники далеко не ограничивается записью видео на звуковой носитель. И о том, что получилось в итоге, в красочных примерах расскажу ниже.

Реализация


В качестве языка программирования был выбран Pixilang, как легко портируемый и заточенный на работу с растровой графикой.
Получилась программа, разделенная на две части: передатчик (Transmitter) и приемник (Receiver). 
Передатчик загружает картинку (JPG, PNG, GIF) или анимацию (GIF) и начинает вещать - на лету конвертировать каждый кадр в звук. Выглядит это примерно так: на экране играет анимация, а из динамиков доносится не очень приятное на слух жужжание. 
Приемник выполняет обратное преобразование - звук, принятый через микрофон или линейный вход, превращается в изображение, которое мы видим на экране. Изображение черно-белое, но для него можно назначить одну из 64 цветовых палитр. Принятую анимацию можно записывать в GIF. 
Запускаем приемник и передатчик на разных устройствах, чтобы посмотреть, как они общаются. Так как для тестирования использовались телефон (Android) и планшет (iOS), полный функционал есть только у версии PixiVisor для этих платформ. В версиях для Windows, Linux и OSX временно не работает приемник. Для начала проверим передачу по воздуху, без проводов. 



Что мы видим? 
Красивые искажения картинки, связанные в первую очередь с отражением звука в комнате и с фильтрацией на уровне железа передатчика и приемника. 
Четкая синхронизация отсутствует, поэтому нужно либо на стороне приемника подгонять пальцем картинку, либо в настройках одной из сторон менять значение параметра Finetune.
Влияние положения руки на распространение звука особенно хорошо видно в следующем ролике:



Теперь попробуем передать видеосигнал по аудио кабелю. 
На устройствах Android и iOS отсутствует линейный аудио вход, но есть возможность подключения гарнитуры через разъем TRRS (Jack) с четырьмя контактами. Этим можно воспользоваться и, спаяв нехитрый переходник, получить линейный моно вход. Схема приведена в конце следующего ролика. Можно взять и готовый конвертер. Например, iRig, или какой-нибудь внешний USB аудио интерфейс.



По проводу качество заметно улучшилось. Осталось лишь влияние фильтров на входе и выходе подопытных устройств. iPad заметно глушит низкие частоты при получении сигнала из вне. На картинке это проявляется так: более заметными становятся контуры изображения, а равномерно закрашенные области теряются. Android телефон LG Optimus Hub наоборот глушит высокие при приеме - картинка теряет четкие контуры. 
Но если теперь видео идет у нас по обычному аудио проводу, то почему бы не попробовать исказить этот сигнал при помощи звукового оборудования (процессоры эффектов, микшеры)? Для примера возьмем карманный аналоговый синтезатор Korg Monotron, который послужит нам в роли низкочастотного фильтра.



Лично меня результат впечатлил. Monotron размывает картинку по горизонтали. При этом параметр Peak (Resonance) добавляет контрастные хвосты и искажает изображение до неузнаваемости. 
Попробуем воспользоваться аналоговым микшером Behringer Xenyx 1202FX для микширования двух видеосигналов и наложения эффектов Reverb и Delay (микшер имеет встроенный процессор эффектов).



И получаем самый интересный результат. Два видеосигнала легко смешиваются, а обработка эффектами Reverb и Delay приводит к неожиданно красивым переливам исходной картинки.

Выводы


Для передачи плавной анимации с разрешением хотя бы 320x240 эта технология конечно не годится. 

Кроме того и первоначальная задумка записывать изображение на аналоговый звуковой носитель столкнулась с небольшой преградой - скорость воспроизведения может плавать, от чего нарушится синхронизация и картинка будет дергаться. 

Синхронизацию можно попробовать реализовать по тому же принципу, что и во "взрослом" телевидении - включив синхроимпульсы между кадров. Но это несколько усложнит алгоритм и внесет дополнительные неудобства для легкого микширования и обработки видеосигналов. 

Чтобы микширование и обработка минимально зависели от синхронизации, на стороне приемника картинку нужно делать бесшовной (как текстура). В этом случае на второй план уходит передача осмысленных изображений с четкими границами кадра (например, фотографии). А на первом плане оказывается передача бесшовных паттернов, которые хорошо показаны в последнем видеоролике. Здесь можно провести аналогию с синтезом звука. Например, один звуковой генератор выдает синус, другой - белый шум. Их можно смешивать, перемножать, не подгоняя фазу одного генератора под фазу другого. Точно так же и с видео в формате PixiVisor: один передатчик выдает бесшовную картинку (паттерн) синуса, другой - белый шум. И эти два сигнала без проблем смешиваются, фильтруются, а на выходе получается красивая анимация, в которой границы кадра не имеют значения. 

Конечно же видеоарт - не единственное достойное применение для программы. Я уверен, что кто-нибудь в процессе экспериментов с PixiVisor найдет еще что-нибудь интересное.

воскресенье, 3 февраля 2013 г.

Blender 2.65a. Полет видеоредактора нормальный :) В предыдущих версиях были глюки с синхронизацией видео и звука.

среда, 26 декабря 2012 г.

Псевдо-HDR эффект средствами Pixilang


Псевдо-HDR эффект (или тональное отображение, хотя я не уверен в уместности этого термина в данном случае, когда за основу берется обычная 24битная картинка) - грубо говоря, выборочное вытягивание уровней одной фотографии таким образом, чтобы темные участки стали более яркими и контрастными. Приведу пример. Вы сделали снимок против Солнца. В итоге хорошо вышло небо с облаками, а деревья и какие-то детали в тени получились темными и неразборчивыми. Здесь этот эффект в какой-то мере спасет ситуацию. Главное не переборщить, так как более темные участки содержат большее количество шумов.

Понятно, что существует масса программ с реализацией описанного эффекта. Но мне всегда было интересно создать такую функцию средствами пиксельно-ориентированного языка Pixilang, автором которого я являюсь :) Зачем? Во-первых, чтобы понять, как  оно работает. Во-вторых, чтобы при желании можно было обрабатывать не только фотографии, но и любую графику, анимацию, видео. В-третьих, чтобы любой мог добавить эту функцию в свою программу.

Сказано - сделано. Посмотрим сначала на исходник получившейся программы.

/*
    hdr_simulation.pixi

    Copyright (c) 2012, Alexander Zolotov
    http://www.warmplace.ru

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to 
    deal in the Software without restriction, including without limitation the 
    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    sell copies of the Software, and to permit persons to whom the Software is 
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in 
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
*/

scr = get_screen()
xsize = get_xsize( scr )
ysize = get_ysize( scr )
clear()

//$src - source image (container of PIXEL type)
//$filter_radius (in percent)
fn apply_hdr_effect( $src, $filter_radius, $intensity )
{
    $src_xsize = get_xsize( $src )
    $src_ysize = get_ysize( $src )

    //Make grayscale copy:
    $img2 = clone( $src )
    $c = new( $src_xsize, $src_ysize, FLOAT32 )
    split_rgb( 0, $src, -1, $c ) //Get red channel
    split_rgb( 1, $img2, $c, $c, $c )

    //Blur grayscale image:
    $scr = get_screen()
    set_screen( $img2 )
    $size = ( $src_xsize * $filter_radius ) / 100
    effector( EFF_HBLUR, $size )
    effector( EFF_VBLUR, $size )
    set_screen( $scr )

    //Invert it:
    op_cn( OP_XOR, $img2, WHITE )

    //Do normalization:
    split_rgb( 0, $img2, $c )
    op_cc( OP_MUL, $c, $c ) //Add contrast
    op_cc( OP_MUL, $c, $c ) //Add contrast
    if $intensity != 1
    {
op_cn( OP_MUL, $c, $intensity )
    }
    op_cn( OP_ADD, $c, 1 ) //Add base level
    $r = clone( $c ) 
    $g = clone( $c ) 
    $b = clone( $c )
    split_rgb( 0, $src, $r, $g, $b )
    op_cc( OP_MUL, $r, $c )
    op_cc( OP_MUL, $g, $c )
    op_cc( OP_MUL, $b, $c )
    split_rgb( 1, $src, $r, $g, $b )
    remove( $r )
    remove( $g )
    remove( $b )
    
    remove( $c )
    remove( $img2 )
}

//Load image:
img = load( "images/dark.jpg" )
set_flags( img, CFLAG_INTERP )
img_xsize = get_xsize( img )
img_ysize = get_ysize( img )
s = 1
if img_xsize > xsize || img_ysize >= ysize
{
    s1 = xsize / img_xsize
    s2 = ysize / img_ysize
    if s1 < s2 { s = s1 } else { s = s2 }
}
pixi( img, 0, 0, WHITE, s, s )
frame( 500 )

apply_hdr_effect( img, 3, 2 )
set_flags( img, CFLAG_INTERP )
save( img, "hdr.jpg", FORMAT_JPEG, 95 )

start_timer( 0 )
while 1
{
    t = get_timer( 0 )
    transp( t / 64 )
    pixi( img, 0, 0, WHITE, s, s )
    frame()
    while get_event() { if EVT[ EVT_TYPE ] == EVT_QUIT { halt } }
}

Функция apply_hdr_effect( $img, $radius, $intensity ) обрабатывает псевдо-HDR фильтром картинку $img. Параметры: $radius - радиус blur-фильтра; $intensity - интенсивность эффекта (нормальное значение - 1 или 2).

Теперь посмотрим на результаты.

Исходное изображение:
После обработки:

Исходное изображение:
После обработки:

Исходное изображение:
После обработки:

Исходное изображение:
После обработки:

Думаю, что со временем программа обрастет дополнительными возможностями. Последняя версия находится в дистрибутиве Pixilang, в папке examples/graphics, файл hdr_simulation.pixi. Надеюсь, кому-то это окажется полезным :)

вторник, 25 декабря 2012 г.

Pixilang v3.4.3

Для поддержания новогоднего настроения :)
Pixilang обновился до версии 3.4.3.

Что нового:
  • лицензия изменена с New BSD на MIT; 
  • текст лицензии стал более простым, а код по прежнему можно свободно изменять и использовать в своих разработках, в том числе в коммерческих; 
  • Android: поддержка архитектур x86 and ARMv7-A; 
  • Android: возможность подключения внешних нативных библиотек (.so); см. примеры в папке native_library;
  • новые операции обработки данных op_cn(): OP_COLOR_SUB2, OP_DIV2; в них операнды переставлены местами; 
  • новые функции для работы с матрицами трансформации: t_push_matrix() and t_pop_matrix(); 
  • новые граф. примеры: labyrinth, clock, save_gif_anim2, hdr_simulation, tiny_generator1-5; 
  • исправлены ошибки.