Адаптивная подсветка с датчиком из веб-камеры

Софт под Linux, разные программы, но только связанные с Linux

Модератор: /dev/random

nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Адаптивная подсветка с датчиком из веб-камеры

Сообщение nick87720z »

Предыдущий стартовый пост мне показался немного сумбурным. По идее тема не столько про подсветку в целом, сколько про эфективную реализацию датчика освещения на основе вебки. Способ установки яркости - последний и по идее, наименее критичный шаг.

В предыдущем названии темы было слово "не концепт". Сам не знаю, как теперь это объяснять :) . Просто мои улучшения строятся на основе статьи Squier: https://habr.com/ru/post/136388/
Если делить на "proof of concept" и "рабочие" решение, то тут по идее любое решение - рабочее.
Однако, как уже ответили в комментариях в статье, у кого-то даже при частоте 1/5fps был постоянно нагружен процессор. Меня это тогда заставило отказаться от идеи адаптивной подсветки (т.к. не нашел других готовый решений). К тому же, когда делаю большие обновления (типа пересборки мира), кроме постоянного нехвата производительности иногда легко словить своп, поэтому по возможности приспосабливаю свое окружение именно под такие условия.

Недавно я вернулся к этой теме, предварительно набив руку на скриптах к испольнителям tint2. Удалось получить такой вариант, что нагрузка почти незаметна (нужно пристально считать проценты в htop чтоб заметить разницу), а реакция - 30fps вместо 1/5fps (даже фейд как в acpilight лишний). В общем, думаю описать возможные улучшения, которые пришли в голову.

1. Первым улучшением был перевод максимального количества работы на ffmpeg. ImageMagick - слишком мощный и требовательный для такой задачки.
Добавляем параметры ffmpeg:
-s 1x1: съемка в наименьшем возможном разрешении (для меня 160x120)
-vf "scale=1:1" - сразу в 1x1
-pix_fmt gray: вывод в сером
-vcodec png: выбираем несложный формат с поддержкой grayscale
convert теперь остается только переводчиком в текстовый формат.
Математику переводим на awk.
Почему awk - я сравнивал bash, dash, bc и awk используя тест: i=0; while (i<1000000) i+=1;
dash быстрее bash в 3..4x, bc быстрее еще на столько же, и awk без -M (множественная точность) быстрее bc также или даже больше (хотя с -M он даже проигрывает на пару процентов).

Shell

ffmpeg -f v4l2 -s 1x1 -i /dev/video0 -vcodec png -vf scale=1:1:flags=fast_bilinear -f image2 -pix_fmt gray /tmp/snapshot.png 2>/dev/null
convert snapshot.png txt:- | sed 's/[^(]*(\s*\([0-9]*\)[,\.)].*/\1/p;d' |\
awk '{
in_max=255 # Цвет ввода для 100% подсветки
bl_max=100 # Диапазон подсветки
bl_min=0
bl = $1 * bl_max / in_max
print bl > bl_max ? bl_max : bl < bl_min ? bl_min : bl }'
Выражение sed дополнено, чтобы обрабатывать десятичную точку.

2. ffmpeg может висеть на фоне с запущенной камерой, периодически обновляя файл.
Добавляем опции вывода:
-update true: включить обновление, опция мюксера image2
-r 2: частота обновлений (для примера - 2 fps)
Остальная часть обработки синхронизируется с помощью inotifywait из inotify-tools. Главный профит - камера не закрывается между обновлениями, так что их частота теперь ограничена только быстродействием системы. Вообще все кроме convert можно перенести на постоянную основу. stdbuf необходим всему, что само не сбрасывает буфера. По идее у sed есть для этого опция, но почему-то с stdbuf лучше чем с опцией.

Shell

ffmpeg -f v4l2 -s 1x1 -i /dev/video0 -vcodec png -vf scale=1:1:flags=fast_bilinear -f image2 -update true -r 2 -pix_fmt gray /tmp/snapshot.png 2>/dev/null &
{ while inotifywait -q -e modify /tmp/snapshot.png; do
convert...
done;} | stdbuf -oL sed ...| stdbuf -oL awk
3. Есть куда более быстрый способ получить текстовые значения из ffmpeg. Меняем формат вывода на rawvideo и меняем вывод на стандартный вывод. Для чтения используем hexdump.
Буферизацию до hexdump отключаем от слова совсем.

Shell

stdbuf -o0 ffmpeg -f v4l2 -s 1x1 -i /dev/video0 -vcodec rawvideo -vf "scale=1:1:flags=fast_bilinear" -f rawvideo -r 2 -pix_fmt gray - 2>/dev/null \
| stdbuf -oL hexdump -e '1/1 "%u\n"'
Тут в принципе можно успокоиться, этот вариант рвет предыдущие по эффективности как тузик грелку. Однако место для улучшений еще есть.
Повторяющиеся значения можно отсеять до hexdump:

Shell

| stdbuf -o0 tr -s '[\000-\377]' \
Часть вычислений в конце можно тоже перенести в ffmpeg. Добавляем фильтр curve:

Shell

-vf scale="1:1:flags=fast_bilinear",curves=all="0/0 ${in_max}/1"
Это корректирует вывод с учетом in_max, вычисления в конце слегка меняются:

Код: Выделить всё

bl = $1 * bl_max / 255
Если же диапазон значения подсветки входит в диапазон вывода ffmpeg, то можно всю математику перенести на фильтр curve и избавиться от awk:

Код: Выделить всё

 curves=all="0/${bl_min} ${in_max}/${bl_max}" 
А часть конвейера начиная с hexdump резко сокращается.
Выполнение комманд:

Shell

| stdbuf -oL hexdump -e '1/1 "xbacklight -set %u\n"' | sh

Shell

| stdbuf -oL hexdump -e '1/1 "light -S %u\n"' | sh
Прямая запись в управляющий файл:

Shell

| stdbuf -oL hexdump -e '1/1 "%u\n"' > ${ctlfile}
К сожалению, в ACPI пределы в разы больше чем 255, например для меня содержимое из max_brightness - 4882. Чтобы записывать такие значения из ffmpeg, необходимо сменить формат вывода на 16 bpc, и тут необходимо выбирать между вариантами LE и BE - gray16le или gray16be. При этом часть фильтрации тоже должна быть в режиме 16bpc, чтобы избежать потери точности, которое для меня равно 4882/255 = менее 20 уровней. Как минимум фильтр curve точно должен работать в 16-битном режиме, а именно в rgb48{l,b}e. Есть ли выигрыш от такого перехода - пока не знаю, руки пока не дошли сделать полноценный бенчмарк с видео-файлом в tmpfs. Хотя кхм, точность подсветки определенно должна быть на высоте :) (если такая точность вообще важна).
tr бесполезен при 16bpc (широкие символы не поддерживаются). Для фильтрации повторов используем grep после hexdump:

Shell

| stdbuf -oL hexdump -e '1/2 "%u\n"' \
| stdbuf -oL grep -v -e '^*'
'*' выводится hexdump как символ повтора, но только один раз на всю очередь повторов, поэтому нагрузки немного.

Еще хорошо было бы менять частоту самой камеры, однако установка одинакового параметра -r X и для входа и для выхода дает неожиданные сюрпризы.
Допустим, вы ставите -r5, а минимальный fps камеры - 15. Камера свой параметр повышает до 15, но... параметр для выхода увеличивается на такое же соотношение - если этот параметр одинаковый для входа и выхода, то частота на выходе равна частоте камеры. Но самое интересное - если на входа -r5, а на выходе -r1, то реальная частота на выходе составит 3fps. Можно получить точный fps следующим образом:

Shell

r_in=$( v4l2-ctl --device /dev/video0 -p $(echo | awk "{ print 1/${delay} }") | awk '{print $5}' )
ffmpeg -f v4l2 -s 1x1 -r ${r_in} -i /dev/video0 ...
Сглаживание скачков яркости - можно через awk, предварительно удалив фильтрацию повторов (теперь цепочка до awk - как тактовый генератор). А можно опять в ffmpeg - добавляем фильтр tmix после curves (погуглив ffmpeg time blur после совета ФНЧ ниже):

Код: Выделить всё

-vf scale="1:1:flags=fast_bilinear",curves=all="0/0 ${bl_mul}/1",tmix=frames=128 
(128 - максимальное значение frames, при 30fps - переход до 4сек).

Проблему старшего байта можно решить, заменив hexdump на od из coreutils. Заодно минус одна внешняя зависимость. Правда, если для управления яркостью используется выполнение команд вроде xbacklight, то количество зависимостей не меняется. Можно для обертки цифр в команды для запуска использовать sed, т.к. он побыстрее awk. Сразу вариант 16-битного вывода:

Код: Выделить всё

c_mul=$( echo | awk "{print $max_color / 255}" )
bl_ceil=$( echo | awk "{print $maxbright / 65536}" )
bl_floor=$( echo | awk "{print $minbright / 65536}" )

stdbuf -o0 ffmpeg -f v4l2 -s 1x1 -i /dev/video0 -vcodec rawvideo \
-vf scale=1:1:flags=fast_bilinear,format=gray16le,scale=flags=fast_bilinear,curves=all="0/${bl_floor} ${c_mul}/${bl_ceil}" \
-f rawvideo -r 2 -pix_fmt gray16le - < /dev/null 2>/dev/null  \
| stdbuf -o0 tr -s '[\000-\377]'   \
| stdbuf -oL od -v -An -w1 -tu1 --endian=little \
| stdbuf -oL sed 's|.*|light -S &|' | sh
Последний раз редактировалось nick87720z 30.11.2020 17:59, всего редактировалось 5 раз.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка (не концепт)

Сообщение Bizdelnick »

nick87720z писал(а):
20.11.2020 20:23
Сразу предупреждаю, в dash не работает из за странного упущения, из за которого $(jobs -p) там неработает. Если что, это не башизм (см. man 1p jobs).
Лучше использовать $!:

Shell

$ sleep 10 &
$ echo $!
10487
$ jobs -p
10487
$
Добавлено (22:01):
А в принципе затея вызывает сомнения, потому как у самой камеры адаптивно подстраивается чувствительность.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка (не концепт)

Сообщение nick87720z »

Bizdelnick писал:
20.11.2020 21:57
Лучше использовать $!:

Shell

$ sleep 10 &
$ echo $!
10487
$ jobs -p
10487
$
Добавлено (20.11.2020 22:01):
Они дают разные результаты, если фоновой процесс - конвейер. Для меня $! давал pid последнего в цепочке процесса (awk), который совсем не критичен для всей цепочки (а вот по ffmpeg вся цепочка завершается). Ну да, просто job -p можно запустить, но толку от него. Или я сделаю jobs -p | read pid, и тогда read pid окажется в подоболочке.
Bizdelnick писал:
20.11.2020 21:57
А в принципе затея вызывает сомнения, потому как у самой камеры адаптивно подстраивается чувствительность.
Хм да, наверное стоит добавить - и автоэкспозицию и фпс камеры. Я использовал gtk-v4l (сочетается с другим софтом, вроде скайпа).
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка (не концепт)

Сообщение Bizdelnick »

nick87720z писал(а):
20.11.2020 22:24
Они дают разные результаты, если фоновой процесс - конвейер. Для меня $! давал pid последнего в цепочке процесса (awk), который совсем не критичен для всей цепочки (а вот по ffmpeg вся цепочка завершается).
Заверните конвейер в сабшелл, тогда будет его PID.

Shell

$ ( sleep 10 | cat ) &
$ ps $!
PID TTY STAT TIME COMMAND
13829 pts/4 S 0:00 dash
$ pstree $!
dash─┬─cat
└─sleep
$ kill $!
[2] + Done (sleep 10 | cat)
$
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка (не концепт)

Сообщение nick87720z »

Bizdelnick писал:
20.11.2020 23:02
Заверните конвейер в сабшелл, тогда будет его PID.
ffmpeg и так гоняется в субшелле (но не весь конвейер). Есть известная проблема, когда процессы подоболочки не завершаются при ее завершении, для примера:
https://stackoverflow.com/questions/8363519/how-do-i-terminate-all-the-subshell-processes
В режиме --no-grab это не имеет значения. Я потому и добавил exec, чтоб ffmpeg в постоянном режиме становился ответственным.
Заворачивание всего конвеера также бессмысленно, конвеер остается работать - нужно именно ffmpeg завершать.
Кстати, интересный вариант таймера, никогда бы не додумался ставить его в начале конвеера :)
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка (не концепт)

Сообщение olecya »

А вот хорошая на мой взгляд была подсказка на хабре определить по уровню серого, попробую что нибудь из этого сделать:

Shell

lsmod | grep v4l2 #проверим модули
sudo dnf install v4l-utils
v4l2-ctl --list-devices
EasyCamera: EasyCamera (usb-0000:00:13.0-1.2):
/dev/video0
/dev/video1

Shell

v4lctl -c /dev/video0 snap jpeg 160x120 webcam.jpg
convert webcam.jpg -colorspace GRAY -resize 1x1 txt: | grep -oP '\d+(?=\.\d*%)'
6
Сижу в комнате с закрытыми шторами. Включаю свет значение вырастает до 16. Можно принять за 100 значение 20 а значит коэффициент 5.
На всякий случай установим потолок в 100 и выведем значение:

Shell

dc -e '[100]sm?5*dZ3=m2k100/p' <<<16
.80
dc -e '[100]sm?5*dZ3=m2k100/p' <<<20
1.00
dc -e '[100]sm?5*dZ3=m2k100/p' <<<50
1.00
В общем смысл понятен. И далее:

Shell

xgamma -gamma $(convert webcam.jpg -colorspace GRAY -resize 1x1 txt: | grep -oP '\d+(?=\.\d*%)' | dc -e '[100]sm ?5*dZ3=m2k100/p')
или:
Я привыкла в небольших пределах менять яркость через гамму, это не правильно поэтому можно придумать через xrandr.
Узнаю имя дисплея:

Shell

xrandr --listmonitors
Monitors: 1
0: +*eDP 1366/344x768/194+0+0 eDP
И подставляю имя в команду:

Shell

xrandr --output eDP --brightness 0.5
В скрипте это будет лишнее но на всякий случай в одной команде возвращаем зрение:

Shell

: $(xrandr --listmonitors); xrandr --output $_ --brightness 1.0
Как одна команда:

Shell

: $(xrandr --listmonitors) && xrandr --output $_ --brightness $(convert webcam.jpg -colorspace GRAY -resize 1x1 txt: | grep -oP '\d+(?=\.\d*%)' | dc -e '[100]sm ?7*dZ3=m2k100/p')
Все вместе (при условии что у вас один монитор):

Код: Выделить всё

#!/bin/bash
X=$(xrandr --listactivemonitors | sed -n '2s/.* //p')
while true; do
  v4lctl -c /dev/video0 snap jpeg 160x120 /tmp/webcam.jpg
  xrandr --output "$X" --brightness $(convert /tmp/webcam.jpg -colorspace GRAY -resize 1x1 txt: |
    grep -oP '\d+(?=\.\d*%)' | dc -e '[100]sm?5*dZ3=m2k100/p')
  sleep 5
done
Это конечно детская игрушка по сравнению с представленным проектом но может что то из этого будет полезным
Добавлено (12:41):
nick87720z писал(а):
20.11.2020 20:23
tint2
Это меня навело на мысль, отображать яркость в статусе. У меня обычный i3status бар
В конфиге i3status/config добавила следующие строчки:

Код: Выделить всё

order += "read_file bright"
...
read_file bright {
        format = "%content"
        path = "/tmp/bright"
}
А в сам скрипт ввела массив из двух значений, первое целочисленное будет вывод в процентах и второе дробное для установки яркости:

Код: Выделить всё

#!/bin/bash
X=$(xrandr --listactivemonitors | sed -n '2s/^.* //p')
while true; do
  v4lctl -c /dev/video0 snap jpeg 160x120 /tmp/webcam.jpg
  lit=($(convert /tmp/webcam.jpg -colorspace GRAY -resize 1x1 txt: |
    grep -oP '\d+(?=\.\d*%)' | dc -e '[100]sm?5*dZ3=mp2k100/p'))
  xrandr --output $X --brightness ${lit[1]}
  echo $lit% >/tmp/bright
  sleep 5
done
Добавлено (12:52):
Добавила еще и изменение по гамме, получилось классно:

Код: Выделить всё

xgamma -quiet -gamma ${lit[1]}
Добавлено (13:19):
nick87720z писал(а):
20.11.2020 20:23
(НЕ КОНЦЕПТ)
Что означает это в заголовке темы?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка (не концепт)

Сообщение Bizdelnick »

nick87720z писал(а):
21.11.2020 05:54
Кстати, интересный вариант таймера, никогда бы не додумался ставить его в начале конвеера
Даже не думал об этом. Просто для примера вбил первую команду, которая пришла в голову.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка (не концепт)

Сообщение olecya »

olecya писала:
21.11.2020 11:44
sleep 5
Поставила на 1 секунду но процессор этого даже не заметил.
Добавлено (14:49):
Выход по Crl+C
надо ловушку добавлять:

Код: Выделить всё

trap "xrandr --output $X --brightness 1; exit" SIGINT
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка (не концепт)

Сообщение nick87720z »

olecya писала:
21.11.2020 11:44
Что означает это в заголовке темы?
Имел ввиду "proof of concept". Может конечно и не самое удачное название - у каждого свои рамки, что является концепт-пруфом, а что рабочим решением. Я стремился к повышению производительности.
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка (не концепт)

Сообщение nick87720z »

olecya писала:
21.11.2020 11:44

Shell

lsmod | grep v4l2 #проверим модули
sudo dnf install v4l-utils
v4l2-ctl --list-devices
EasyCamera: EasyCamera (usb-0000:00:13.0-1.2):
/dev/video0
/dev/video1

Код: Выделить всё

#!/bin/bash
X=$(xrandr --listactivemonitors | sed -n '2s/^.* //p')
while true; do
  v4lctl -c /dev/video0 snap jpeg 160x120 /tmp/webcam.jpg
  lit=($(convert /tmp/webcam.jpg -colorspace GRAY -resize 1x1 txt: |
    grep -oP '\d+(?=\.\d*%)' | dc -e '[100]sm?5*dZ3=mp2k100/p'))
  xrandr --output $X --brightness ${lit[1]}
  echo $lit% >/tmp/bright
  sleep 5
done
Тут надо уточнить - v4lctl идет не с v4l-utils, а с xawtv. К сожалению, мне не удалось попробовать этот метод, т.к. в портаже он удален, а то что сейчас у jorgicio (вплоть до 3.107) у меня оканчивается ошибкой ассемблера в libng.
Как оказалось, скриншот можно сделать одним v4l-utils, с помощью v4l2-ctl (https://stackoverflow.com/questions/63544349/convert-yuy2-yuyv-to-png-from-the-command-line):

Shell

# Узнаем доступные форматы
v4l2-ctl --device /dev/video0 --list-formats-ext
# Настройка камеры
v4l2-ctl --device /dev/video0 --set-fmt-video=width=480,height=480,pixelformat=YUYV
# Снимок
v4l2-ctl --device /dev/video0 --stream-mmap --stream-to=frame.raw --stream-count=1
Чтобы прочитать это напрямую, в imagemagick не хватает поддержки yuyv (yuv не подойтет, даже ffmpeg делает это преобразование перед lutyuv). По ссылке предлагается преобразовывать с помощью dd к другому формату, uyvy:

Shell

# Преобразование в png
dd if=frame.raw conv=swab | convert -sampling-factor 4:2:2 -size 640x480 -depth 8 uyvy:- frame.png
# Полное преобразование, до grep
dd if=frame.raw conv=swab | convert -sampling-factor 4:2:2 -size 640x480 -depth 8 uyvy:- -colorspace GRAY -resize 1x1 txt:
Кстати, вспомнил метод яркости через xrandr. Много где предлагали. Однако, это не подсветка монитора, а скорее цветовая коррекция. Я бы предложил попробовать либо утилиты xbacklight, light (https://github.com/haikarainen/light), либо сразу писать в /sys/class/backlight/:

Shell

# Первое попавшееся устройство для примера
for ctldir in /sys/class/backlight/* ; do break; done
# Значение яркости на 100%
bl_max=$(cat ${ctldir}/brightness_max)
# Установка яркости
dd if=frame.raw conv=swab | convert -sampling-factor 4:2:2 -size 640x480 -depth 8 uyvy:- -colorspace GRAY -resize 1x1 txt: | grep --color=never -oP '\d+(?=\.\d*%)' | dc -e "[${bl_max}]sm?${bl_max}*255/d${bl_max}<mp" > ${ctldir}/brightness
Выражение в dc параметризовано, чтоб сразу направлять в файл brightness.
Последний раз редактировалось nick87720z 27.11.2020 15:21, всего редактировалось 1 раз.
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка (не концепт)

Сообщение olecya »

У меня был еще вариант, но глянула, он к сожалению тоже в пакете xawtv. Работает аналогично только проще вызов:

Shell

streamer -o webcam.jpeg
Обязательно расширение именно jpeg. Интересно, что в линухе мало программ кроме gcc которые бы выбирали действие по расширению, но вот одна из них налицо.
Добавлено (14:30):
Нашла еще простенький но мощный инструмент представленный в репе федоры. Есть опция -l позволяет запускать программу в цикле, у меня 1 секунда выставлена и опция -b запуск в фоне. Так что можно помещать эту строчку за пределами цикла программы.

Shell

fswebcam -bl 1 --scale 60x40 test.jpg
Ну или так:

Shell

fswebcam test.jpg
Еще мысль возникла. Судя по названию к слову "адаптивная" явно напрашивается плавное изменение яркости при сильных колебаниях освещенности. То есть перед установкой очередного уровня яркости сравниваем с предыдущим, если значение не изменилось ничего не далаем, а если изменилось но незначительно то отправляем в пайп на дальнейшую установку, а если например изменилось больше определенного порога то отправляем последовательно несколько увеличивающихся значений в пайп, а из пайпа(именованного канала) считываем уже через каждую секунду для установки. Тем самым размазываем изменение яркости по времени. А из за того, что мы не посылаем в пайп одинаковые значения то очередь всегда будет стремится вернутся к единице.
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка (не концепт)

Сообщение olecya »

olecya писала:
27.11.2020 13:56
пайпа(именованного канала)
Да это меня понесло. В баше нет вместимости канала. Можно попробовать обойтись утилитой buffer
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка (не концепт)

Сообщение nick87720z »

olecya писала:
27.11.2020 13:56
Добавлено (27.11.2020 14:30):
Нашла еще простенький но мощный инструмент представленный в репе федоры. Есть опция -l позволяет запускать программу в цикле, у меня 1 секунда выставлена и опция -b запуск в фоне. Так что можно помещать эту строчку за пределами цикла программы.

Shell

fswebcam -bl 1 --scale 60x40 test.jpg
Ну или так:

Shell

fswebcam test.jpg
Похоже на годную замену ffmpeg. Судя по опциям, он тоже может висеть фильтром, сводя в 1x1 и выдавая в raw gray8. Кстати, надо бы стартовой сообщение обновить, а то как-то сумбурно получилось. По идее я начинал про методы, а скрипт по ссылке только для примера. Вроде как сам скрипт должен был быть примером, но что-то он разросся пока я дошел до поста :)
olecya писала:
27.11.2020 13:56
Еще мысль возникла. Судя по названию к слову "адаптивная" явно напрашивается плавное изменение яркости при сильных колебаниях освещенности. То есть перед установкой очередного уровня яркости сравниваем с предыдущим, если значение не изменилось ничего не далаем, а если изменилось но незначительно то отправляем в пайп на дальнейшую установку, а если например изменилось больше определенного порога то отправляем последовательно несколько увеличивающихся значений в пайп, а из пайпа(именованного канала) считываем уже через каждую секунду для установки. Тем самым размазываем изменение яркости по времени. А из за того, что мы не посылаем в пайп одинаковые значения то очередь всегда будет стремится вернутся к единице.
Проще забить в поиск чем гадать :) . Как я понимаю, адаптивная подсветка уже есть на кое-каких смартфонах и ноутбуках (разумеется, не с линуксами из коробки), возможно ТВ, плюс всякое умное/адаптивное освещение. Обычно под адаптивностью подразумевают просто способность приспосабливаться под условия, не важно с какой скоростью. В принципе банальное атухание экрана со временем или утилиты типа redshift, f.lux тоже можно считать адаптивным освещением.
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка (не концепт)

Сообщение olecya »

olecya писала:
27.11.2020 15:40
Да это меня понесло. В баше нет вместимости канала.

Shell

mkfifo test
exec 5<>test
for i in {1..5}; do echo $i; done >&5
while read -t.1 -u5; do echo $REPLY; done
1
2
3
4
5
Вот получили неблокирующую запись в канал
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка (не концепт)

Сообщение Bizdelnick »

olecya писала:
27.11.2020 17:50
Вот получили неблокирующую запись в канал
Где же она неблокирующая? У Вас просто объём записи маленький. Размер канала, что именованного, что неименованного, в linux сейчас — 16 страниц по умолчанию (см. man 7 pipe).
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка (не концепт)

Сообщение olecya »

@Bizdelnick, Я догадывалась, что размер буфера(вместимости) не безразмерный, ну и значит 16 страниц для данного случая будет более чем достаточно. Я несколько запуталась вначале между свойствами каналов в шел и на голанг.
Добавлено (19:03):

Shell

getconf PAGESIZE
4096
Вот сколько я могу поставить в очередь строк со значением 0.50

Shell

for i in {1..13104}; do echo 0.50; done >&5

Shell

echo $((4096 * 16 / 5))
13107
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение nick87720z »

Попробовал fswebcam. Похоже он RAW только для ввода поддерживает, вывод только в jpeg, png, webp. Режима видео нет - просто периодические снимки. Хотя с IM сочетается, можно через конвейер прямо в "display -".
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение olecya »

olecya писала:
27.11.2020 13:56
к слову "адаптивная" явно напрашивается плавное изменение яркости
Вот что я имела ввиду. Логику конечно можно реализовать на чем угодно, пример для краткости в однострочнике на dc с шагом в один процент:
Допустим программу только запустили и уровень серого определен как 6, ясное дело, переменная с предыдущим значением не определена

Код: Выделить всё

last=$current
current=$(convert ...)
echo $last $current | dc ...

Shell

echo 6 | dc -e '[lb1-pdsbla!=h]sh[lb1+pdsbla!=t]st[1-la]sm?dsaz1=m-dla+sbd0>td0<h'
6
Это то что будет перенаправлено в неблокирующий канал.
Меняем освещенность, естественно предыдущее значение равно 6:

Shell

echo 6 12 | dc -e '[lb1-pdsbla!=h]sh[lb1+pdsbla!=t]st[1-la]sm?dsaz1=m-dla+sbd0>td0<h'
7
8
9
10
11
12
Меняем освещенность в другую сторону:

Shell

echo 12 9 | dc -e '[lb1-pdsbla!=h]sh[lb1+pdsbla!=t]st[1-la]sm?dsaz1=m-dla+sbd0>td0<h'
11
10
9
Если значение не меняется, пропускаем вывод:

Shell

echo 9 9 | dc -e '[lb1-pdsbla!=h]sh[lb1+pdsbla!=t]st[1-la]sm?dsaz1=m-dla+sbd0>td0<h'
Чтобы не возникло скопления в канале при частой смене освещенности и не сбрасывать ставший бесполезным дамп(очередь) можно задержку для считывания на выходе из канала сократить в два и более раза по сравнению с циклом в записи.
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 2913
ОС: Gentoo

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение ormorph »

Идея не плохая, только некоторые драйверы не поддерживают гамма коррекцию.
Сейчас стало интересно, можно ли использовать ffmpeg как датчик движения используя камеру...
motion все таки нагружает систему.
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение olecya »

Накидаю макет(q - выход):

Код: Выделить всё

#!/bin/bash
[ -e ch ] || mkfifo ch
exec 5<> ch

while read -u5 d; do #убрала опцию -t20
        echo $d
        sleep 0.1 
done &

while read; do
        [ $REPLY = q ] && break
        echo $LAST $REPLY |
dc -e '[lb1-pdsbla!=h]sh[lb1+pdsbla!=t]st[1-la]sm?dsaz1=m-dla+sbd0>td0<h'
        LAST=$REPLY
done >&5
kill $!
#wait

Shell

./test
5 #<Enter>
5
10 #<Enter>
6
7
8
9
10
q #<Enter>
Все работает. Первый цикл я запускаю в фоне предварительно установив время ожидания read в 20 секунд и в конце скрипта wait. Теперь если ввожу q, происходит выход из главного цикла с ожиданием в 20 секунд для выхода из второго цикла и полностью из скрипта соответственно. На всякий случай проверяю пользуются ли моим каналом процессы

Shell

lsof +d ./
Но вот я что-то не пойму как правильно завершить работу фоновых процессов в скрипте?
Добавлено (19:58):
А, вспомнила kill $! Исправила.
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение nick87720z »

olecya писала:
27.11.2020 13:56
Судя по названию к слову "адаптивная" явно напрашивается плавное изменение яркости при сильных колебаниях освещенности.
Ну да, кстати. Тогда у меня получается скорее "реактивная" подсветка (отслова reactive) :) . Реально на 30fps моей вебки можно просто руками перед камерой шаманить и на каждую тень мгновенный отклик.

Можно было бы добавить этап после hexdump, который создавал бы свой поток цифр на максимальной частоте, возможно превышающий частоту от ffmpeg. Но как это сделать в awk - так и не нашел. Если ставить таймаут для getline, то первый фейл по таймауту фейлит весь поток, так что дальше из него уже ничего не прочитать. Удалось реализовать только отказавшись от фильтрации повторов (теперь ffmpeg - что-то вроде тактового генератора). Фильтрует повторы сам awk. Примерно так:

Код: Выделить всё

        $b hexdump -v -e '1/1 "%u\n"'                           |\
        $b awk \
        -v "ctl_file=${acpi_dir}/brightness"                        \
        -v "bl_cur=${maxbright}"                                    \
        -v "bl_step=$( awk_expr '('${maxbright}'/'${minbright}')^('${delay}'/'${fade_time}') - 1' )" \
        '{
                bl = $1 * '${maxbright}' / 255
                bl = bl > '${maxbright}' ? '${maxbright}' : bl < '${minbright}' ? '${minbright}' : bl
                if (bl == bl_cur) next

                if (bl > bl_cur ? (bl_cur *= 1 + bl_step) > bl : (bl_cur /= 1 + bl_step) < bl)
                        bl_cur = bl
                
                printf ("%u\n",bl_cur) > ctl_file
                fflush (ctl_file)
        }'
Наверно и правда нет смысла фильтровать повторы до awk при таком подходе. ffmpeg все-равно пашет все кадры, на выходе после него - жалкие байты.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение Bizdelnick »

nick87720z писал(а):
29.11.2020 22:46
Реально на 30fps моей вебки можно просто руками перед камерой шаманить и на каждую тень мгновенный отклик.
Тут ФНЧ напрашивается, а не просто задержка.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение nick87720z »

olecya писала:
29.11.2020 19:54
Накидаю макет(q - выход):

Код: Выделить всё

#!/bin/bash
while read; do
        [ $REPLY = q ] && break
        echo $LAST $REPLY |
dc -e '[lb1-pdsbla!=h]sh[lb1+pdsbla!=t]st[1-la]sm?dsaz1=m-dla+sbd0>td0<h'
        LAST=$REPLY
done >&5
Почему-то сразу захотелось вставить seq:

Shell

( LAST=5; REPLY=10; seq $LAST $(( REPLY > LAST ? 1 : -1 )) $REPLY )
А если на dc - мне кажется, он мог бы постоянно висеть, заменяя весь цикл и запоминая предыдущее значение. Конечно, если не путаю с bc (пробовал разобрать однострочник, даже до внутренностей h и t не дошел).
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение nick87720z »

Bizdelnick писал:
30.11.2020 00:06
nick87720z писал(а):
29.11.2020 22:46
Реально на 30fps моей вебки можно просто руками перед камерой шаманить и на каждую тень мгновенный отклик.
Тут ФНЧ напрашивается, а не просто задержка.
Интересно, мне одному пришла в голову идея старого апплета x-eyes, только реагирующего на тыкание пальцем в вебку :D

Update: Гениально! Всю голову сломал, пытаясь найти что-нибудь из coreutils, awk, sed и т.д. позволяющее держать буфер последних значений и выбирать любое (хотя бы из обоих концов буфера, чтоб как в kawase blur).
В общем, решается еще одним фильтром ffmpeg:

Код: Выделить всё

-vf ...,tmix=frames=128
Правда, изменение интенсивности при этом линейное, в моем подходе на awk такой же эффект достигается заменой умножения на сложение.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение Bizdelnick »

Bizdelnick писал:
30.11.2020 00:06
Тут ФНЧ напрашивается
Ну, то есть, примерно такой примитивный: awk 'BEGIN{ k = 0.1; getline; v = $1; }{ v = v + (k*($1 - v)); printf("%d\n", v); }' (для подбора подходящей плавности варьировать k).
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение Bizdelnick »

nick87720z писал(а):
30.11.2020 00:39
держать буфер последних значений и выбирать любое
А зачем? (Так-то кольцевой буфер в awk сделать не проблема.)
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение olecya »

nick87720z писал(а):
30.11.2020 00:29
А если на dc - мне кажется, он мог бы постоянно висеть, заменяя весь цикл и запоминая предыдущее значение.
В том что я там накидала в dc на скорую руку не стоит даже разбираться. Можно конечно засунуть ? в макрос, но лучше сделать на awk с нормальным сишным синтаксисом:

Код: Выделить всё

#!/bin/bash

awk '
!f      {f = $1-1}
$1 == f {next}
        {d = f>$1?-1:1
         while(f != $1) {
                 f+=d
                 print f
        }
         f = $1
}' -

Shell

/awk.sh
5 <Enter>
5
8 <Enter>
6
7
8
4 <Enter>
7
6
5
4
4 <Enter>
Спасибо сказали:
Аватара пользователя
olecya
Сообщения: 903
ОС: debian, fedora (i3-wm)

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение olecya »

nick87720z писал(а):
30.11.2020 00:29
dc - мне кажется, он мог бы постоянно висеть, заменяя весь цикл и запоминая предыдущее значение.
Ну вот практически тот же алгоритм что и в awk. Надо бы выдать вам за это сигару. У меня час пролетел как одна секунда :)

Shell

cat - | dc -e '[q]st1sc[_1sc]sn[lalc+pdsalb!=m]sm?psa[la?z2!=tdsb<nlalb!=mlbsa1sclhx]shlhx'
5 <Enter>
5
10 <Enter>
6
7
8
9
10
3 <Enter>
9
8
7
6
5
4
3
3 <Enter>
<Enter>
<Enter>
Не тестила, не успеваю...
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21001
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение Bizdelnick »

olecya писала:
30.11.2020 13:32

Код: Выделить всё

#!/bin/bash

awk '

Код: Выделить всё

#!/usr/bin/awk -f

# awk code goes here
(И с dc тоже так можно.)
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
nick87720z
Сообщения: 180
ОС: Gentoo / Calculate

Re: Адаптивная подсветка с датчиком из веб-камеры

Сообщение nick87720z »

Добрался до бенчмарков. Использовал сохраненный кусок /dev/urandom.

Shell

$ ls -lh
итого 28M
-rw-r--r-- 1 nick87720z nick87720z 28M дек 5 03:22 test

Shell

{ while :; do cat test; done; } | stdbuf -o0 ffmpeg -v verbose -f rawvideo -pix_fmt yuyv422 -s 1x1 -r 30 -i - -vcodec rawvideo -vf scale=flags=neighbor,format=gray16le -f rawvideo - | stdbuf -oL hexdump -v -e '1/2 "%u\n"'
Использовать сам /dev/urandom не стоит, т.к. внезапно он оказался не способен обеспечить нужную скорость данных.

Комбинация ffmpeg->hexdump->awk оказалась непобедимой при выполнении вычислений на awk. При этом переход с gray на gray16 только ускоряет обработку. Осталось разобраться с определениес старшинства байтов.

По деталям

Лучшим алгоритмом для сведения в пиксел оказался area (кто бы сомневался), а вот для преобразования форматов лучше neighbor (почему-то -sws_flags неработает).

Перевод ffmpeg с gray на gray16 не замедляет, а наоборот ускоряет fps (если цепочка преобразований не меняется). Вообще, из трех форматов (gray, gray16, grayf32) gray оказался самым медленным.

hexdump чуть быстрее od - время выполнения 16/19 в пользу hexdump, если использовать минимальный конвейер типа "cat | hexdump/od > /dev/null" (упрощенно). Хотя в составе с ffmpeg и др. разница почти не заметна.

По вычислениям

в ffmpeg я пробовал плагин geq, который позволяет устанавливать значения пикселов с помощью движка формул ffmpeg. Сам этот калькулятор оказался годным - есть переменные (точнее номера ячеек 0..9 с функциями ld,st), условия, циклы (и то и другое - функции) и объединение выражений в списки с помощью ';'. Символы [;,] обязательно экранировать, иначе интерпретируются как разделители фильтров -vf. Для 1x1 geq обгоняет curves за счет отсутствия лишних преобразований в/из rgb, которые медленнее чем yuyv->gray. Казалось бы, идеал достигнут... но тут пришла тявка и все погры..испортила.

На примерах ниже соотношение fps оказалось 51к/45к в пользу awk. Даже с выражениями для ленивой адаптации яркости скорость для awk держитсяв пределах 49..50к. Это при том, что пример с geq использует предварительный расчет для целого куска выражения (при '-s 1280x960' это повышало скорость в ~7/4 раза).

Shell

{ while :; do cat test; done;} \
| stdbuf -o0 ffmpeg -v verbose -f rawvideo -pix_fmt yuyv422 -s 1x1 -r 30 -i - -vcodec rawvideo -vf scale=flags=neighbor,format=gray16le -f rawvideo - \
| stdbuf -oL hexdump -v -e '1/2 "%u\n"' \
| stdbuf -oL awk -v bl_cur=4882 -v bl_step=1.02 '{
bl = $1 * 4882 / 65535;
bl = bl > 4882 ? 4882 : bl < 48 ? 48 : bl;
if (bl == bl_cur) next;

if (bl > bl_cur ? (bl_cur *= bl_step) > bl : (bl_cur /= bl_step) < bl)
bl_cur = bl;

printf ("light -S %s \n", bl_cur)
}' > /dev/null

Shell

{ while :; do cat test; echo >&2; done;} \
| stdbuf -o0 ffmpeg -v verbose -f rawvideo -pix_fmt yuyv422 -s 1x1 -r 30 -i - -vcodec rawvideo -f rawvideo -vf scale=flags=neighbor,format=gray16le,geq="lum=
if (eq (N\, 0)\,
st (0\, 255 * (1000-10) / 128 / 65535)
) \;
clip (10 + lum (0\,0) * ld(0)\, 10\, 1000 )" - \
| stdbuf -oL od -v -An -w2 -tu2 --endian=little \
| stdbuf -oL awk '{ print "light -S "$1 }' > /dev/null
Также "awk '{ printf "light -S %s\n" $1 }'" по скорости не уступает "sed 's|^|light -S |'".
Спасибо сказали: