Думаю у многих из нас, в шкафу пылился старый зеркальный фотоаппарат, типа Canon EOS 400D. Он как чемодан без ручки: выбросить жалко, продать смысла нет, и использовать вряд ли будешь. Достал его так одним вечером, и подумал: вещь хорошая и вполне годная для всяких опытов. И сразу загорелся применить его во всяких своих самоделках. А что, весьма хорошо фотографирует из коробки, достаточно широкий спектр всяких регулировок, осталось только научиться с ним работать. Всего-то подружить его с компьютером, да Linux, и дело в шляпе! В результате у нас получается просто непаханое поле для фотографических экспериментов и применения в своих придумках. Давайте же поглядим, как это можно сделать и что получилось из таких экспериментов.

▍ Исходники


Как я уже сказал, у меня достаточно давно лежит в шкафу фотоаппарат Canon EOS 400D, для своего времени неплохой фотик для семейного фотоальбома, но с появлением хороших телефонов, практически не используется. Когда в очередной раз я его достал, то понял, что из него нужно сотворить что-то прикольное. Для того чтобы отвязать фотоаппарат от аккумулятора, и чтобы он работал «вечно», ему нужен источник питания от сети. Для этого пришлось приобрести адаптер ACK-DC20. Умышленно даю марку, потому что поиск для конкретной модели фотоаппарата оказался тем ещё квестом. Но оказалось, что можно вполне купить «здесь и сейчас», а не ждать с Китая. Всё это можно провернуть и с другими фотоаппаратами, только надо подобрать подходящий блок питания.
Также рекомендую обзавестись штативом, стоит более-менее вменяемый штатив недорого (мой стоил всего 1500 рублей в известном интернет-магазине), зато позволяет делать хорошие фото.
В качестве ЭВМ для работы с фотоаппаратом можно использовать подходящий одноплатник, лично я использовал какой-то древний портативный ноутбук, который зависает при открытии браузера, но вполне сносно справился с задачей снимать фотографии.


Всё готово к экспериментам: фотоаппарат, источник питания, штатив и ЭВМ.

▍ Настройка ПО


На ноутбуке установлен Linux Mint 19, и я буду рассказывать об особенностях настройки именно этой системы. Всё, что далее будет описано, может подойти к Ubuntu. В качестве основного источника информации, я использовал статью "How to Use Your DSLR Camera as a Webcam in Linux". Мой фотоаппарат не умеет снимать видео, и в качестве вебкамеры выступать отказался, но в ней изложены основные нюансы настройки, которые я и применил.
Для начала поставим все необходимые пакеты.

sudo apt-get install gphoto2 v4l2loopback-utils v4l2loopback-dkms ffmpeg

ffmpeg нам понадобится чуточку позже, для монтирования видео.

В принципе, если вы хотите просто попробовать, работает ли у вас фотоаппарат, то можно модуль загрузить вручную.

sudo modprobe v4l2loopback exclusive_caps=1 max_buffers=2

Но после каждой перезагрузки, вспоминать, что надо загрузить модуль, мне было лень. Поэтому давайте это всё пропишем в системе/
Добавим в файл /etc/modules строку dslr-webcam:

$ sudo vi /etc/modules

  # /etc/modules: kernel modules to load at boot time.
  #
  # This file contains the names of kernel modules that should be loaded
  # at boot time, one per line. Lines beginning with "#" are ignored.

  dslr-webcam

Создадим новый файл /etc/modprobe.d/dslr-webcam.conf и запишем в него следующие строки:

alias dslr-webcam v4l2loopback
options v4l2loopback exclusive_caps=1 max_buffers=2

После всех проделанных манипуляций перезагружаемся. Подключаем камеру с помощью microUSB, и включаем её. В результате dmesg должно показать следующий выхлоп:

[474969.683623] usb 2-1.7.2: new full-speed USB device number 14 using ehci-pci
[474969.797751] usb 2-1.7.2: not running at top speed; connect to a high speed hub
[474969.820004] usb 2-1.7.2: New USB device found, idVendor=04a9, idProduct=3110
[474969.820008] usb 2-1.7.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[474969.820009] usb 2-1.7.2: Product: Canon Digital Camera
[474969.820011] usb 2-1.7.2: Manufacturer: Canon Inc.

Проверяем, что камера успешно определилась:

gphoto2 --auto-detect
Модель                   Порт                                                  
----------------------------------------------------------
Canon EOS 400D (PTP mode)      usb:002,014    

Радостно пытаемся сделать фото:

gphoto2 --capture-image-and-download

И вероятнее всего у вас на этом моменте (или ещё на этапе подключения камеры) вылезет окошко системы и спросит, что делать с фотографиями на камере. А в консоли выпадет следующая или аналогичная ошибка:

gphoto2 --capture-image-and-download
                                                                               
*** Ошибка ***              
An error occurred in the io-library ('Could not claim the USB device'): Could not claim interface 0 (Устройство или ресурс занято). Make sure no other program (gvfs-gphoto2-volume-monitor) or kernel module (such as sdc2xx, stv680, spca50x) is using the device and you have read/write access to the device.
ОШИБКА: Невозможно сделать снимок.
ОШИБКА: Невозможно сделать снимок.
*** Ошибка (-53: «Could not claim the USB device») ***       

Для получения отладочных сообщений воспользуйтесь параметром --debug.
Отладочные сообщения могут помочь найти решение вашей проблемы.
Если вы хотите какие-либо сообщения gphoto, список рассылки авторов
программы <gphoto-devel@lists.sourceforge.net>, то запускайте
gphoto2 со следующими параметрами:

    env LANG=C gphoto2 --debug --debug-logfile=my-logfile.txt --capture-image-and-download

Проверьте, что аргументы надёжно экранированы.

Честно говоря долго не мог понять, что с этим делать. У меня она прекрасно воспроизводилась на двух разных машинах с разными версиями linux mint, и заключалась она в том, что в системе работает демон gvfsd-metadata, который следит за тем, что подключается медиаустройство. И он после этого уже запускает собственные клиенты работы с фотоаппаратом. Это можно увидеть следующей командой:

ps ax | grep photo
16478 ?        Sl     0:00 /usr/lib/gvfs/gvfs-gphoto2-volume-monitor
21405 ?        Sl     0:00 /usr/lib/gvfs/gvfsd-gphoto2 --spawner :1.31 /org/gtk/gvfs/exec_spaw/7

Первое, что нужно сделать — это поубивать эти процессы. После этого, либо грубо выкорчевать из системы демона gvfsd-metadata:

systemctl --user mask gvfs-metadata.service

На ноуте я так и сделал, чтобы после каждой перезагрузки он меня не беспокоил. Вернуть всё обратно можно так:

systemctl --user unmask gvfs-metadata.service

Если вы хотите разово отключить сервис, то выполните:

systemctl --user stop gvfs-metadata.service

После этого всё это должно корректно заработать.

gphoto2 --capture-image-and-download
Новый файл находится в фотоаппарате в /capt0000.jpg                            
Файл сохраняется с именем capt0000.jpg
Удаляется файл /capt0000.jpg в фотоаппарате

Могу сказать сразу, что в разных системах этот демон может быть разным (у меня он отличается), и именно это может мешать корректно делать снимки.
На ноуте у меня всё корректно работало только под root, и пришлось все скрипты запускать только под sudo. Под обычным пользователем работало через раз, linux way, да-да. Так и не победил.

Скажу сразу, что на этом проблемы не заканчиваются, часто бывает, что возникает внутренняя ошибка фотоаппарата, которая решается только жёсткой перезагрузкой, со съёмкой аккумулятора. Например:

*** Ошибка ***              
Canon EOS Capture failed (0x02ff: PTP I/O Error)
ОШИБКА: Невозможно сделать снимок.
ОШИБКА: Невозможно сделать снимок.

Притом на фотоаппарате висит Busy, и он ни на что не реагирует. Как её победить, я так и не понял.

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

sudo sshfs -o allow_other,default_permissions user@ip:/home/user/canon ~/canon


▍ Настройки фотоаппарата


Для подобных съёмок фотоаппарат тоже стоит немного настроить. Первое, и очевидное — это сделать так, чтобы фотоаппарат не отключался самостоятельно. При работе от аккумулятора — это просто его разрядит, но при работе от сети — идеальный режим.


Убираем опцию «Автоотключение».

Следующая настройка — не такая очевидная. Для видео не требуется такого хорошего качества, даже самое низкое качество съёмки будет давать Full HD (1920x1080 точек). Поэтому снижаем качество съёмки.


Ставим самое «плохое» качество съёмки.

В результате будет кадр 1936х1288 пикселов, что тоже очень даже хорошо. Причина уменьшения качества съёмки банальна — это скорость передачи через USB. Если поставить больше, фотоаппарат просто не будет успевать передать полученную фотографию. Это тоже было выяснено эмпирическим путём.

▍ Немного программирования на bash


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

sudo apt install libgphoto2-dev
sudo pip3 install -v gphoto2

Но библиотека пайтона gphoto2 упорно не хотела вставать на мою систему, убив минут 40, в попытке разрулить ситуацию с установкой модуля, принял решение писать на баше. Мы люди не гордые, сделаем на том, что работает. Да, и код на python, даже в примере был слишком монструозен, чем моя реализация на bash. Тем более что в нашем блоге есть шикарная серия статей по программированию на bash.
В результате мозгового штурма (я тот ещё «программист» на bash), родился следующий код.

#!/bin/bash
END=600
SLEEPTIME=10
for i in `seq -w 0 $END`
do
  gphoto2 --capture-image-and-download --filename  "$i.jpg"
  sleep $SLEEPTIME
done

Где переменная END — это суммарное количество снимков, которое сделает фотоаппарат. SLEEPTIME — время между снимками. Опытным путём установлено, что время менее 10 секунд может приводить к ошибкам, особенно если снимать в ночное время в автоматическом режиме (когда выбирается автоматом время экспозиции).
Количество кадров, равное 2880 взято тоже не с потолка. Прикинул, что если сводить 24 кадра в секунду, сделать минутный ролик, то это получится 1440 кадров. Это как раз съёмка в течение 4-х часов, каждые 10 секунд. Если снимать 8 часов, то как раз значение будет больше. Но, увы, 8 часов мне снять так и не удалось, фотоаппарат зависал.
Полученные кадры необходимо свести в видео, чтобы можно было смотреть. Для этого воспользуемся ffmpeg.

ffmpeg -framerate 24 -i %04d.jpg -c:v libx264 -profile:v high -crf 20 -pix_fmt yuv420p output.mp4

Не буду детально разбирать данную команду, обращу внимания на два момента:

  • framerate 24 — это количество кадров в секунду, я выбрал 24, и мне кажется этого маловато. Можно выбрать 60, и будет абсолютная гладкость.
  • %04d.jpg тип входящего файла, число после нуля будет показывать сколько чисел в имени файла (оно будет у вас разное, подбирайте под конкретную задачу).

Если хочется потом наложить аудиодорожку на видео, то можно воспользоваться следующей командой:

ffmpeg -i output.mp4 -i audio.wav -map 0:v -map 1:a -c:v copy -shortest output_audio.mp4

Где соответственно:

  • output.mp4 — входной видеофайл
  • audio.wav — входной аудиофайл (любой формат)
  • output_audio.mp4 — выходной видеофайл

Выходной файл получится длинной, того файла кто короче по воспроизведению видео или аудио (опция -shortest).

▍ Даёшь съёмку и результаты!


Меньше слов, больше дела. Надо наконец попробовать, результат проделанной работы. Поскольку у меня из окна видна только помойка, то было принято решение поехать к хорошему приятелю с ночёвкой на окраину города. Там и просторы большие, рядом аэропорт, летает много самолётов, и просто более приятный вид из окна.

Первый опыт был просто в комнате, самое сложное было — это не включать свет, и не мелькать в окне, чтобы не было бликов на фотоаппарате. Но вроде всё получилось.


В процессе фотосъёмки.

Могу честно признаться, я тот ещё фотограф. Снимал просто в режиме «без вспышки», поэтому баланс белого, выдержка, ISO, диафрагма выбиралось автоматически каждый раз. Каждый кадр сделан с интервалом в 5 секунд. От этого получилась такая «ламповость», но, как по мне, для первого раза потрясающий результат:

Больше мы не выдержали, потому что сидеть впотьмах (свет включать нельзя) и «не дышать» (не ходить, чтобы не было бликов) просто невозможно, и съёмку было решено прервать, тут не спасли даже хорошие дружеские разговоры.

«Дефекты плёнки» на видео — это пролетающие птицы. Есть много вопросов к видео: мерцание, неестественные цвета и т.п. Есть куда расти и работать, но даже с этого можно отталкиваться.
Думаю, что если не полениться и настроить нормально фотоаппарат, и поставить на ночь, можно снять очень крутые перемигивания окнами.

Следующую съёмку было решено проводить на балконе, чтобы заснять рассвет.


Съёмочный стенд.

Но тут я совершил несколько роковых ошибок: не настроил фотоаппарат, пока было светло, при этом съёмку вёл в полностью мануальном режиме. В результате все фото получились размытыми. Другая ошибка чуть не стоила мне фотоаппарата: я забыл про Солнце. И фотоаппарат был направлен прямо точно по траектории нашего светила. Пока мы спали, фотоаппарат чудом не расплавился — его спасла дымка и то, что утром солнечные лучи не такие горячие. Поэтому, когда снимаете такие таймлапсы, обязательно помните про главное наше светило!

Поскольку восход не вышел, принято было волевое решение перед отъездом снять закат, и вот он уже получился. Дождался, когда солнечный диск уйдёт из объектива камеры (примерно 2 часа дня), и запустил съёмку. На первых кадрах ещё видны солнечные засветы линзы. Лично меня результат просто потряс, при совершенно незначительных трудозатратах.

Потрясающе: треки от самолётов, огни домов, закат, прямо-таки виден пульс засыпающего города. Мне после этого захотелось по всему городу расставить таких камер и снимать, снимать, снимать.

▍ Выводы


Не претендую, что открыл Америку, современные фотоаппараты умеют делать такое прямо из коробки, без всяких скриптов. Но, найти применение старой хорошей вещи — почему бы и нет? Например, можно поставить камеру во время какого-то действия, и сделать вот такой таймлапс. Кроме таймлапсов, можно использовать камеру, например, в фотоловушках. В общем, идей море, главное — успевать их реализовывать! Gphoto2 позволяют полностью управлять фотоаппаратом: балансом белого, выставлять диафрагму и т.д., что даёт просто неограниченные возможности. Главный плюс — это возможность вести удалённую фотосъёмку.
Выражаю благодарность своему другу Алексею, который двое выходных терпел меня, мои эксперименты, помогал и советовал, как лучше всё сделать.

▍ Полезные ссылки




Комментарии (95)


  1. Javian
    11.10.2021 12:17
    +3

    Логичнее было бы ... в процессе гугления вышел на Хабр. Собственно была мысль микроконтроллером нажимать спуск.


    1. dlinyj Автор
      11.10.2021 12:19
      +1

      В этом случае мы ограничены ёмкостью флешкарты, а тут мы ограничены ёмкостью жёсткого диска (которая может составлять несколько терабайт). На фотоаппарате кадры не сохраняются.


      1. Javian
        11.10.2021 12:32
        +4

        Таймлапс обычно предполагает разрешение видео FHD. Такого разрешения JPG будет килобайт 300. При емкости карты 8Gb это 27962 кадра.

        Такое решение нам дает мобильность - можно выйти на природу, в город, порт.


        1. dlinyj Автор
          11.10.2021 12:41
          +2

          На моём фотоаппарате, самый маленький размер файла всё равно занимает около мегабайта.
          На самом деле, если хочется делать по уму, надо брать просто более дорогую камеру, они умеют такое прямо из коробки, ещё и HDR сами сделают. В данном случае — это игрушки.


          1. Javian
            11.10.2021 13:13
            +10

            Инструмент зависит от область применения. Я бы не стал новую камеру использовать для таймлапс, длительностью несколько недель. А некоторые делают таймлапс, длительностью в год.


            1. dlinyj Автор
              11.10.2021 13:19

              Если длинною в год, то нужна розетка. Если нужна розетка, то мобильность сильно сужается. А если розетка есть, то что мешает рядом поставить маленький ноут?


              1. Javian
                11.10.2021 13:44
                +2

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

                Я бы больше боялся, что за год ноутбук зависнет.


                1. dlinyj Автор
                  11.10.2021 13:49

                  На самом деле, предмета спора нет. У меня фотоаппарат зависал чаще, чем ноутбук (4 раза против нуля), так что и фотик тоже может зависнуть, и МК отказать. В любом случае, любое решение имеет право на жизнь.


                  1. Javian
                    11.10.2021 16:21
                    +1

                    Интересная задача автономного таймлапс длиною в год. Может быть зависание фотоаппарата можно решить добавив включение/выключение фотоаппарата. Некое реле, якорем физически нажимающее кнопку включения (чтобы не разбирать фотоаппарат). Раз сутки включает и после снимка отключает - тут еще и огромная экономия заряда батареи.


                    1. dlinyj Автор
                      11.10.2021 16:24

                      Я тоже об этом думал. Вариант.


      1. Erop22
        12.10.2021 08:53
        +2

        Есть хорошая "новость" - Wi-Fi SDHC карты. Не самая популярная штука, но найти вполне реально. Пользуются даже во взрослых студиях (как раз, чтобы не привязываться шнурком к камере). Из минусов - нельзя ей сказать, чтобы она сама писала куда-то на сетевое хранилище, так бы можно было уменьшить связку до камера с картой + роутер с диском. Но если вам с ноута приятнее работать, можете поэкспериментировать. Ну и вы же наверняка знаете про CHDK и ему подобные проекты. Есть и под старые, и под новые тушки.. Сильно упрощает жизнь таймлапсера.. ))


        1. dlinyj Автор
          12.10.2021 10:48

          Да я знаю, обо всём этом. На деле мой вариант оказывается много удобнее и практичнее.


          1. man_of_letters
            13.10.2021 12:38

            Мне кажется, или у тебя была статья про использование Wi-Fi SDHC карты как одноплатника на линуксе?


            1. dlinyj Автор
              13.10.2021 12:41

              Была, но за давностью лет где-то эта карта потерялась. Проблема ещё в том, что она SD, а в фотоаппарате CF.


    1. iShrimp
      11.10.2021 18:04
      +7

      А ещё на Хабре есть статья про установку CHDK на EOS 400D (аж 2009 года), правда с другой целью, для расширения диапазона ISO... но в CHDK есть и возможность съёмки с интервалом, и интерпретатор скриптов.


      1. dlinyj Автор
        11.10.2021 18:15

        Ух, ты! Класс!


      1. ArtStea1th
        12.10.2021 19:25
        +2

        ставил как-то CHDK в 2013-ом ещё, как раз для интервальной съёмки, долгих выдержек (больше минуты) и возможножности сохранять в RAW, т.к. мыльница SX230 HS из коробки не умеет это вот всё, если повозиться - может получиться вполне удовлетворительный результат ;) (тоже у себя с балкона снимал)


        1. dlinyj Автор
          12.10.2021 19:54
          +1

          Монтаж потрясный, как и вид с балкона.


  1. engine9
    11.10.2021 12:31
    +7

    Клёво еще снимать как комнатные растения реагируют на полив и на освещение.


    1. dlinyj Автор
      11.10.2021 12:41

      Запросто, растений только нет.


      1. gresolio
        11.10.2021 13:53

        Может грибы зато есть? Очень впечатляет:
        How Mushroom Time-Lapses Are Filmed (Louie Schwartzberg) www.youtube.com/watch?v=5yq0_mqN97s


        1. dlinyj Автор
          11.10.2021 13:56
          +1

          Если только плесень. Но, кстати, тоже интересная идея.


  1. a2v
    11.10.2021 12:53
    +4

    Я на свой сони а6000 тоже как-то раз програмку для таймлапсов поставил (не ту, которая покупается, а бесплатную). Получается красиво:
    https://www.youtube.com/watch?v=nl7K6bmOkyc
    https://www.youtube.com/watch?v=8eIeKR9a9as


    1. dlinyj Автор
      11.10.2021 13:25
      +1

      Шикарно, Бар великолепен. Я бы хотел поснимать в Герцег Нови, там классные виды.


    1. Mnemone
      11.10.2021 18:06
      +1

      А что за бесплатная программка? Я знаю, что есть для винды, с помощью неё и ноутбука и снимал таймлапсы. (как и автор поста, многоэтажечки https://vk.com/video74130432_169636382

      https://vk.com/video74130432_171560312)

      Кстати, многим фотоаппаратам команду можно через ик пульт давать (просто установив приложение на смартфон с ик-портом, там и таймлапс и что угодно будет)


      1. a2v
        11.10.2021 19:51
        +1

        уже не помню точно, но вроде отсюда: https://www.playmemoriescameraapps.com/portal/


      1. a2v
        12.10.2021 11:19

        хе-хе, я на платный магаз ссылку-то дал не разобравшись (: В общем, вроде вот этот реверс инжиниринг проект https://github.com/ma1co/Sony-PMCA-RE


  1. philfreeeu
    11.10.2021 13:26
    +1

    Мерцание получается от того, что объектив с каждым кадром не идеально повторяемо выставляет диафрагму. Есть способ, закрыв диафрагму, чуть-чуть повернуть объектив на байонете, он тогда отключается от камеры и диафрагма останется стабильной.


    1. dlinyj Автор
      11.10.2021 13:38
      +1

      Проще всё настроить в мануальном режиме и снимать уже в нём.


      1. wormball
        11.10.2021 14:34
        +1

        Только ежели солнце взойдёт/зайдёт/скроется за облаками, будет не айс. Я так полагаю, надо снимать в режиме приоритета диафрагмы и выставив предварительно фокус (и переключив на ручной фокус) и ручной баланс белого, а яркость уже на этапе обработки выравнивать. Как именно — не знаю, я не настоящий сварщик. Но по идее не должно быть сложно ручками программу написать, которая бы это делала.


      1. Alexmaru
        11.10.2021 15:03
        +3

        не, даже полностью с ручными настройками мерцание будет (проверял на своём Никоне в специальном таймлапс-режиме). И блокировать нужно ещё баланс белого, он его каждый раз тоже выбирает заново, при фиксированной выдержке/диафрагме.


      1. stranger169
        11.10.2021 15:54
        +2

        Плохо, что нет возможности плавно изменять экспозицию в течении таймлапса. Имея предварительные замеры в начале и конце можно было бы получить хороший результат с плавным переходом по экспозиции.
        Всё равно некоторой ступенчатости не избежать из-за градаций в 1/3 ступени, но в сочетании с равом, я думаю, можно было бы добиться достойного результата.


      1. alexleo
        12.10.2021 17:31
        +1

        Штатив за 1500, да ещё на большой высоте, — это, скорее, не штатив, а девайс для собственного успокоения. У меня когда-то было подобное "устройство" не за 1500, а за 5000, им даже тест на бэк-фронт фокус невозможно было снять, т.к. камера тряслась при спуске на таком "штативе", и изображение получалось размытым, если выдержка больше 1/500. На таких штативах нужно отойти от камеры метра на три, чтобы даже ваши случайные движения не трясли штатив, и включать предварительный подъём зеркала, но я не знаю, есть ли такое на вашей камере. Современные камеры ещё умеют электронный затвор эмулировать, когда поднимается зеркало, открывается затвор, выжидается пауза, затем матрица сбрасывается, и затвор закрывается обычным образом, в таком режиме тряски от затвора на кадре не будет. Я не знаю, насколько глубоко можно управлять камерой удалённо, и доступны ли такие режимы снаружи, но если доступны, то большую часть трясучки вы уберёте.
        Чтобы огрехи в закрытии диафрагмы не давали мерцание, проще всего накрутить серый фильтр нужной плотности, а диафрагму оставить полностью открытой. Тут возникнет вопрос с резкостью и глубиной резкости, но для кадров как у вас это меньшее из зол.
        И обязательно отключать всю автоматику. Тут есть засада: даже в режиме M многие камеры радостно пытаются управлять чувствительностью ISO, не забывайте им это запрещать. Всё-таки снимать таймлапс сцены, у которой освещённость за секунды меняется в разы, с включенной автоматикой — это гарантия непредсказуемого результата :)


        1. dlinyj Автор
          12.10.2021 18:30

          Я не настоящий сварщик. В данном случае была просто проба пера.


          1. jryj
            14.10.2021 13:30
            +1

            Обычно на камерах есть кнопки блокировки экспозиции и фокуса. Настроил экспо тройку, сфокусировался и всё залочил.


    1. wormball
      11.10.2021 14:36
      +1

      Там ещё картинка меняется, и фотоаппарат каждый раз думает, какую экспозицию выставить. Так что даже с неподвижной диафрагмой яркость может прыгать. Вот ежели в комнате что-либо снимать — то это да.


  1. Earthsea
    11.10.2021 13:32
    +3

    Думаю у многих из нас, в шкафу пылился старый зеркальный фотоаппарат, типа Canon EOS 400D. Он как чемодан без ручки: выбросить жалко, продать смысла нет, и использовать вряд ли будешь.

    Даже немного странно это читать. Сейчас думаю, зачем я когда-то покупал аналогичный SONY, который теперь точно так же пылится. Хотя нет, не пылится, он в чехле.

    Кстати, несколько лет назад все крупные пылинки с матрицы сами отвалились, не пришлось ее чистить.


    1. dlinyj Автор
      11.10.2021 13:35
      +1

      Теперь вы знаете, что с ним делать :)


  1. wormball
    11.10.2021 13:48
    +1

    Для канонов вроде есть magic lantern, а с ним вроде как можно без внешнего управления таймлапсы снимать. У меня как раз на днях 1100д образовался, так что проверю.


    1. dlinyj Автор
      11.10.2021 13:49

      Да, есть. Но на 400D не удалось поставить (официально не поддерживается).


      1. wormball
        11.10.2021 14:26
        +1

        И действительно. Ну ничего, зато 1100д поддерживается!: Ь


      1. Erop22
        12.10.2021 10:13
        +1

        ML для диджиков >= 4. Для 400D есть 400plus. Для 300D была от Васи. CHDK ещё есть для кучи камер, я тч и не зеркальных.


    1. Kriminalist
      11.10.2021 14:34
      +3

      Для кенонов не-зеркалок, которых точно в шкафу можно найти, есть еще замечательный CHDK https://chdk.clan.su/faq/1-1.


  1. Igor_omsk
    11.10.2021 15:34
    +2

    Это все конечно круто. Но есть одно "но". Таймлапсы лучше снимать на беззеркалки. Большое количество снятых кадров быстро убьет механический затвор и систему поднятия зеркала. На зеркалках тоже есть системы электронного затвора, но не на всех. На D400 его нет.


    1. dlinyj Автор
      11.10.2021 15:34
      +1

      С учётом того, что фотоаппарат на выброс, то ну и ладно.


      1. stranger169
        11.10.2021 16:22
        +3

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


      1. wormball
        12.10.2021 17:34

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

        Сейчас ещё одна мысль пришла — а что если легендарный белый цвет растений в ближнем ИК — это на самом деле не отражение, а флуоресценция? Хотя бы частично. ИК-мыльница валяется, осталось красный светофильтр найти.


        1. alliumnsk
          13.10.2021 16:12
          +1

          >что если легендарный белый цвет растений в ближнем ИК — это на самом деле не отражение, а флуоресценция?

          Да, это и то и другое. Флуоресцирует хлорофилл (который в хлоропастах).
          Еще и одновременно через ИК фильтр и поляризационный интересно смотреть.


          1. wormball
            13.10.2021 16:59

            Ну понятно, что и то, и другое, но интересно, насколько.

            > Еще и одновременно через ИК фильтр и поляризационный интересно смотреть.

            И что там видно?



    1. wormball
      11.10.2021 17:01
      +1

      Зато затвор/матрицу беззеркалки ещё более успешно убьёт солнце в объектив.


      1. stranger169
        11.10.2021 19:39
        +1

        Надо крайне постараться, чтобы фотографируя убить солнцем матрицу. На практике подобного не встречал. UV фильтр на объектив, конечно, не помешает всё же, он защитит матрицу от деградации от ультрафиолета.

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

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


  1. sland
    11.10.2021 15:34
    +3

    Я в своё время для таймлапсов использовал CHDK https://chdk.fandom.com/wiki/CHDK - позволяет расширить функциональность практически любой Canon-овской "мыльницы". Но фотографии сначала на карту памяти, а потом только извлекать и монтировать. Неудобно, когда фотоаппарат на штативе, хочется продолжить съёмку в том же положении, а крышечка карты памяти снизу.

    Правда, камера была не зеркалка, а Canon SX20. У зеркалок, как я понимаю, есть проблема ресурса механического затвора и он совсем не безграничный - что-то вроде 30-100 тысяч кадров, если верить интернетам.


  1. berez
    11.10.2021 15:38
    +1

    Ну не зна-а-а-аю… Я до сих пор старый фотоаппарат таскаю с собой на всякие мероприятия и в отпуска. А таймлапс снимал дешманской вебкамерой — снимаем кадр в минуту, воспроизводим со скоростью 24 кадра в секунду и получается вполне бодрый ролик.
    Правда, вебкамера ярким днем слепнет и показывает белый кадр.


    1. sland
      11.10.2021 16:31
      +1

      Да и ночью поснимать полярные сияния или вращение млечного пути едва ли получится


  1. clawham
    11.10.2021 15:41
    +3

    EOS 400D старый фотик? нуок...а чем вам Magic lantern не угодил? там тоже можно писать скрипты а то что делали вы - там уже сделано с удобными настройками - просто подключаете вместо батареи блок питания и всё! Но конечно круто...сохранил в закладки хотя даже и не знаю зачем


    1. dlinyj Автор
      11.10.2021 15:44
      +1

      нуок… а чем вам Magic lantern не угодил?

      Хотя бы тем, что на этот фотоаппарат его нет.
      Плюс, вы не совсем уловили мысль статьи. Цель — удалённое управление фотоаппаратом, а таймлапсы — приятный результат.


  1. VLT
    11.10.2021 17:21
    +1

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


    1. dlinyj Автор
      11.10.2021 17:29

      Всё именно так, а если прикрутить ssh, то можно и самому делать фотки, когда душа пожелает.


  1. guliverza
    11.10.2021 17:27

    Глупый вопрос - без карты памяти этот 400D не будет работать в таком режиме?
    У меня тоже валяется такой фотик, но у него ещё до кучи погнуты контакты для подключения карты памяти...


    1. dlinyj Автор
      11.10.2021 17:29
      +2

      Глупый вопрос — без карты памяти этот 400D не будет работать в таком режиме?

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


    1. SergeyNovak
      23.10.2021 11:16
      +1

      Стоит попробовать разобрать, подсветить фонарем и попробовать выгнуть взад подходящим ножичком. На AMD процессорах это регулярная процедура. На своем Canon 50D приходилось тоже поправлять даже не разбирая после суетливого запихивания флэшки... но тогда лишь немного скривил, не успел утоптать от души.


  1. dlinyj Автор
    11.10.2021 17:28

    .


  1. WortexLinux
    11.10.2021 19:43
    +3

    Тоже некоторое время назад кинул старую камеру Sony на подоконник, подключил ее к малинке, которая раз в минуту делает снимок. А потом ночью они собираются в видео и заливаются на сервак http://video.orevo.net/


    1. slarionoff
      21.10.2021 16:08
      +1

      Если был бы формат названия файла год-месяц-день, удобнее была бы сортировка.


      1. WortexLinux
        21.10.2021 16:47
        +1

        Да.

        Но я сортирую по Last Modified, а не по Name, так что переделывать не стал. Думал приделать фронт какой-то, но особого смысла не вижу.


  1. sergun_74rus
    11.10.2021 19:43
    +3

    Собираю кадры с камер интерсвязи с 2016 года - кадр/день. Таймлапсы на пикабу выкладывал. Видео получаются дерганные в плане яркости и автомобилей, но интересные. Хочу поколдовать как-нибудь ближе к пенсии чтоб мусор в виде птиц/машин убрать. Может есть готовое решение?


    1. stranger169
      11.10.2021 20:36
      +2

      В фотошопе есть инструмент File > Scripts > Statistics.
      Там есть много разных методов, можно поэксперементировать. Если вы возьмете 20-30 кадров с интервалом в 5 секунд, например, то таким методом можно убрать все движущиеся объекты.
      Таким методом можно, например, со штатива снять серию кадров на людной площади и обработкой получить пустую площадь на кадре.


  1. K_Chicago
    11.10.2021 21:52
    +6

    Очень хорошая статья.

    Я сделал примерно то же самое для Canon PowerShot G5, 2000-кудрявого года.

    По тем временам это была очень удачная камера, даже со встроенным Time-Lapse но только 100 (???) кадров.

    Сделал всё на 3-й малинке в комбинации с адафрутовским LCD с пятью кнопками управления.

    Использовал разумеется тоже gphoto2 для установки параметров камеры и производства съемки.

    Для управления задействовал систему LCD-меню от Alan Aufderheide

    Меню позволяет выбрать количество снимков, интервал между снимками в минутах или в секундах, зум в интервале от 0 до 18, размер файла и режим макро.

    Получилось компактненько.

    код приложения на питоне:

    #!/usr/bin/python
    #
    # https://github.com/aufder/RaspberryPiLcdMenu
    # https://forums.adafruit.com/viewtopic.php?f=47&t=37191
    # https://blog.adafruit.com/2013/02/22/raspberry-pi-lcd-menu-piday-raspberrypi-raspberry_pi/
    # This provides a menu driven application using the LCD Plates
    # from Adafruit Electronics.
    
    import commands
    import os
    import sys
    import gphoto2 as gp
    from string import split
    from time import sleep, strftime, localtime
    from datetime import datetime, timedelta
    from xml.dom.minidom import *
    from Adafruit_I2C import Adafruit_I2C
    #from Adafruit_MCP230xx import Adafruit_MCP230XX
    from Adafruit_CharLCD import Adafruit_CharLCDPlate
    import Adafruit_CharLCD as LCD
    from ListSelector import ListSelector
    
    import smbus
    
    configfile = '/home/pi/canon_menu.xml'
    # set DEBUG=1 for print debug statements
    DEBUG = 0
    DISPLAY_ROWS = 2
    DISPLAY_COLS = 16
    
    # set to 0 if you want the LCD to stay on, 1 to turn off and on auto
    AUTO_OFF_LCD = 0
    
    # set busnum param to the correct value for your pi
    lcd = Adafruit_CharLCDPlate(busnum = 1)
    # in case you add custom logic to lcd to check if it is connected (useful)
    #if lcd.connected == 0:
    #    quit()
    
    lcd.set_color(0.0, 0.0, 1.0)
    #lcd.backlight(lcd.OFF)
    v_frames=0
    v_seconds=20
    v_frames_done=0
    s_frames='Auto'
    s_iso="Auto"
    v_zoom=0
    s_imsize='Medium 1'
    s_macro='Auto'
    
    # commands
    def f_start():
        global v_frames
        global v_seconds
        global v_frames_done
        global s_frames   
        global s_iso
        global v_zoom
        global s_imsize
        global s_macro
        
        lcd.clear()
        camera = gp.Camera()
        error = gp.gp_camera_init(camera)
        if error < gp.GP_OK:
    	lcd.message('No Camera')
    	while 1:
    	    if lcd.is_pressed(LCD.LEFT):
    		break
    		sleep(0.25) 	   
        else:
    	f_show_settings("Select to Start")
    	try:  #apply camera settings
    	   file_path = gp.check_result(gp.gp_camera_capture_preview(camera))
    	   cfg=camera.get_config()
    	   cfg_zoom=cfg.get_child_by_name('zoom')
    	   gp.check_result(gp.gp_widget_set_value(cfg_zoom, v_zoom))
    	   err=10
    	   cfg_iso=cfg.get_child_by_name('iso')
    	   gp.check_result(gp.gp_widget_set_value(cfg_iso, str(s_iso)))
    	   cfg_size=cfg.get_child_by_name('imagesize')
    	   gp.check_result(gp.gp_widget_set_value(cfg_size, s_imsize))
    	   err=20
    	   cfg_macro=cfg.get_child_by_name('afdistance')
    	   gp.check_result(gp.gp_widget_set_value(cfg_macro, s_macro))
    	   err=30
    	   gp.check_result(gp.gp_camera_set_config(camera, cfg))	   	   
    	except gp.GPhoto2Error as ex:
    	    print(str(err))
    	    f_exit_on_key(ex.string)
    #!	
    	lcd.message('Started')
    	v_frames_done=0
    	if v_frames==0:
    	    while True:
    		try:
    		    file_path = gp.check_result(gp.gp_camera_capture(camera, gp.GP_CAPTURE_IMAGE))
    		    v_frames_done+=1
    		    lcd.clear()
    		    lcd.message('Frame '+str(v_frames_done)+'\ncompleted')
    		    sleep(v_seconds)		    
    		except gp.GPhoto2Error as ex:
        		    lcd.clear()
    		    lcd.message(ex.string)
    		    while 1:
    			if lcd.is_pressed(LCD.LEFT) \
    			or lcd.is_pressed(LCD.RIGHT)\
    			or lcd.is_pressed(LCD.UP)\
    			or lcd.is_pressed(LCD.DOWN)\
    			or lcd.is_pressed(LCD.SELECT):
    			    break
    		    lcd.clear()
    		    return    	   	    
    	else:    
    	    while True:
    		file_path = gp.check_result(gp.gp_camera_capture(camera, gp.GP_CAPTURE_IMAGE))
    		v_frames_done+=1
    		lcd.clear()
    		lcd.message('Frame '+str(v_frames_done)+ ' of '+str(v_frames)+'\ncompleted')
    		if v_frames_done==v_frames:
    		    break
    		sleep(v_seconds)
    	    lcd.clear()
    	    lcd.message('Completed\nPress for Exit')
    	while 1:
    	    if lcd.is_pressed(LCD.LEFT) \
    	    or lcd.is_pressed(LCD.RIGHT)\
    	    or lcd.is_pressed(LCD.UP)\
    	    or lcd.is_pressed(LCD.DOWN)\
    	    or lcd.is_pressed(LCD.SELECT):
    		break
    	lcd.clear()    	
    	camera.exit()  
    	
    def f_exit_on_key(s_arg):
        lcd.clear()
        lcd.message(s_arg+'\nPress for Exit')
        while 1:
    	if lcd.is_pressed(LCD.LEFT) \
    	or lcd.is_pressed(LCD.RIGHT)\
    	or lcd.is_pressed(LCD.UP)\
    	or lcd.is_pressed(LCD.DOWN)\
    	or lcd.is_pressed(LCD.SELECT):
    	    break
        lcd.clear()
        
    def f_scroll_lines(l_lines):
        list_length=len(l_lines)
        lcd.clear()
        idx1=0
        idx2=1
        if list_length==1:
    	lcd.message(l_lines)
    	return
        lcd.message(l_lines[idx1]+'\n'+l_lines[idx2])
        while not (lcd.is_pressed(LCD.LEFT) or lcd.is_pressed(LCD.SELECT)):
    	if lcd.is_pressed(LCD.DOWN):
    	    if idx2<list_length-1:
    		idx1+=1
    		idx2+=1
    		lcd.clear()
    		lcd.message(l_lines[idx1]+'\n'+l_lines[idx2])
    	elif lcd.is_pressed(LCD.UP):
    	    if idx1>0:
    		idx1-=1
    		idx2-=1
    		lcd.clear()
    		lcd.message(l_lines[idx1]+'\n'+l_lines[idx2])
        lcd.clear()
        
    def f_test():
        global v_frames
        global v_seconds
        global v_frames_done
        global s_iso
        global v_zoom
        global s_imsize
        global s_macro
        err=0
        
        lcd.clear()
        camera = gp.Camera()
        error = gp.gp_camera_init(camera)
        if error < gp.GP_OK:
    	f_exit_on_key('No Camera')	   
        else:
    	f_show_settings("Sel to Start")
    	try:
    	   file_path = gp.check_result(gp.gp_camera_capture_preview(camera))
    	   cfg=camera.get_config()
    	   cfg_zoom=cfg.get_child_by_name('zoom')
    	   gp.check_result(gp.gp_widget_set_value(cfg_zoom, v_zoom))
    	   err=1
    	   cfg_iso=cfg.get_child_by_name('iso')
    	   gp.check_result(gp.gp_widget_set_value(cfg_iso, str(s_iso)))
    	   cfg_size=cfg.get_child_by_name('imagesize')
    	   gp.check_result(gp.gp_widget_set_value(cfg_size, s_imsize))
    	   err=2
    	   cfg_macro=cfg.get_child_by_name('afdistance')
    	   gp.check_result(gp.gp_widget_set_value(cfg_macro, s_macro))
    	   err=3
    	   gp.check_result(gp.gp_camera_set_config(camera, cfg))	   	   
    	   err=4
    	   file_path = gp.check_result(gp.gp_camera_capture(camera, gp.GP_CAPTURE_IMAGE))
    	   err=5		    
    	except gp.GPhoto2Error as ex:
    	    print(str(err))
    	    f_exit_on_key(ex.string)
    	camera.exit()  
    	    
    def f_show_settings(*args):
    	global s_frames
    	global v_seconds
    	global s_iso
    	global v_zoom
    	global s_imsize
    	global s_macro
    	if s_imsize=='Medium 1':
    	    l_size='Med1'
    	elif s_imsize=='Medium 2':
    	    l_size='Med2'
    	elif s_imsize=='Large':
    	    l_size='Lrg'
    	elif s_imsize=='Small':    
    	    l_size='Sml'
    	lcd.clear()
    	if bool(args):
    	    s_msg=[args[0],s_frames+'/'+str(v_seconds)+' ISO:'+str(s_iso),'Zoom:'+str(v_zoom)+' Size:'+l_size,'Macro: '+s_macro]
    	else:    
    	    s_msg=[s_frames+'/'+str(v_seconds)+' ISO:'+str(s_iso),'Zoom:'+str(v_zoom)+' Size:'+l_size,'Macro: '+s_macro]
            f_scroll_lines(s_msg)
    	
    def f_auto(v_Arg):
    	global v_frames
    	global s_frames
    	v_frames=v_Arg
    	s_frames='Auto'
    	f_show_settings()
    	display.left()
    	display.up()
    	
    def f_set_frames(v_Arg):
    	global v_frames
    	global s_frames
    	v_frames=v_Arg
    	s_frames=str(v_frames)
    	f_show_settings()
    	display.left()
    	display.up()
    	
    def f_set_seconds(v_Arg):
    	global v_seconds	
    	v_seconds=v_Arg
    	f_show_settings()
    	display.left()
    	display.up()
    	display.up()			
    	
    def f_set_minutes(v_Arg):
    	global v_seconds	
    	v_seconds=v_Arg
    	f_show_settings()
    	display.left()
    	display.up()
    	display.up()
    	display.up()			
    
    def f_set_zoom(v_Arg):
    	global v_zoom	
    	v_zoom=v_Arg
    	f_show_settings()
    	display.left()
    	display.up()
    	display.up()
    	display.up()
    	display.up()	
    	
    def f_set_imsize(v_Arg):
    	global s_imsize	
    	d_imsize={
    	    0: "Large",
    	    1: "Medium 1",
    	    2: "Medium 2",
    	    3: "Small"	
    	}	
    	s_imsize=d_imsize[v_Arg]
    	f_show_settings()
    	display.left()
    	display.up()
    	display.up()
    	display.up()
    	display.up()	
    	display.up()	
    	display.up()
    	
    def f_set_macro(v_Arg):
    	global s_macro
    	d_macro={
    	    0: "Auto",
    	    1: "Zone Focus (Close-up)"
    	}	
    	s_macro=d_macro[v_Arg]
    	f_show_settings()
    	display.left()
    	display.up()
    	display.up()
    	display.up()
    	display.up()	
    	display.up()	
    	display.up()
    	display.up()	
    
    def DoQuit():
        sleep(1)
        lcd.clear()
        lcd.message('Are you sure?\nPress Sel for Y')
        while 1:
            if lcd.is_pressed(LCD.LEFT):
                break
            if lcd.is_pressed(LCD.SELECT):
                lcd.clear()
                lcd.set_backlight(False)
                sys.exit()
    
    def f_shutdown():
        lcd.clear()
        lcd.message('Are you sure?\nPress Sel for Y')
        while 1:
            if lcd.is_pressed(LCD.LEFT):
                break
            if lcd.is_pressed(LCD.SELECT):
                lcd.clear()
                lcd.set_backlight(False)
                commands.getoutput("sudo shutdown -h now")
                quit()
            sleep(0.25)
    
    def LcdOff():
        #global currentLcd
        #currentLcd = lcd.OFF
        lcd.set_backlight(False)
    
    def LcdOn():
        #global currentLcd
        #currentLcd = lcd.ON
        lcd.set_backlight(True)
    
    
       
    class CommandToRun:
        def __init__(self, myName, theCommand):
            self.text = myName
            self.commandToRun = theCommand
        def Run(self):
            self.clist = split(commands.getoutput(self.commandToRun), '\n')
            if len(self.clist) > 0:
                lcd.clear()
                lcd.message(self.clist[0])
                for i in range(1, len(self.clist)):
                    while 1:
                        if lcd.is_pressed(LCD.DOWN):
                            break
                        sleep(0.25)
                    lcd.clear()
                    lcd.message(self.clist[i-1]+'\n'+self.clist[i])          
                    sleep(0.5)
            while 1:
                if lcd.is_pressed(LCD.LEFT):
                    break
    
    class Widget:
        def __init__(self, myName, myFunction, myArg):
            self.text = myName
            self.function = myFunction
            self.arg=myArg
            
    class Folder:
        def __init__(self, myName, myParent):
            self.text = myName
            self.items = []
            self.parent = myParent
    
    def HandleSettings(node):
        global lcd
        if node.getAttribute('lcdColor').lower() == 'red':
            LcdRed()
        elif node.getAttribute('lcdColor').lower() == 'green':
            LcdGreen()
        elif node.getAttribute('lcdColor').lower() == 'blue':
            LcdBlue()
        elif node.getAttribute('lcdColor').lower() == 'yellow':
            LcdYellow()
        elif node.getAttribute('lcdColor').lower() == 'teal':
            LcdTeal()
        elif node.getAttribute('lcdColor').lower() == 'violet':
            LcdViolet()
        elif node.getAttribute('lcdColor').lower() == 'white':
            LcdOn()
        if node.getAttribute('lcdBacklight').lower() == 'on':
            LcdOn()
        elif node.getAttribute('lcdBacklight').lower() == 'off':
            LcdOff()
    
    def ProcessNode(currentNode, currentItem):
        children = currentNode.childNodes
    
        for child in children:
            if isinstance(child, xml.dom.minidom.Element):
                if child.tagName == 'settings':
                    HandleSettings(child)
                elif child.tagName == 'folder':
                    thisFolder = Folder(child.getAttribute('text'), currentItem)
                    currentItem.items.append(thisFolder)
                    ProcessNode(child, thisFolder)
                elif child.tagName == 'widget':
                    thisWidget = Widget(child.getAttribute('text'), child.getAttribute('function'), child.getAttribute('arg'))
                    currentItem.items.append(thisWidget)
                elif child.tagName == 'run':
                    thisCommand = CommandToRun(child.getAttribute('text'), child.firstChild.data)
                    currentItem.items.append(thisCommand)
    
    class Display:
        def __init__(self, folder):
            self.curFolder = folder
            self.curTopItem = 0
            self.curSelectedItem = 0
        def display(self):
            if self.curTopItem > len(self.curFolder.items) - DISPLAY_ROWS:
                self.curTopItem = len(self.curFolder.items) - DISPLAY_ROWS
            if self.curTopItem < 0:
                self.curTopItem = 0
            if DEBUG:
                print('------------------')
            str = ''
            for row in range(self.curTopItem, self.curTopItem+DISPLAY_ROWS):
                if row > self.curTopItem:
                    str += '\n'
                if row < len(self.curFolder.items):
                    if row == self.curSelectedItem:
                        cmd = '-'+self.curFolder.items[row].text
                        if len(cmd) < 16:
                            for row in range(len(cmd), 16):
                                cmd += ' '
                        if DEBUG:
                            print('|'+cmd+'|')
                        str += cmd
                    else:
                        cmd = ' '+self.curFolder.items[row].text
                        if len(cmd) < 16:
                            for row in range(len(cmd), 16):
                                cmd += ' '
                        if DEBUG:
                            print('|'+cmd+'|')
                        str += cmd
            if DEBUG:
                print('------------------')
            lcd.home()
            lcd.message(str)
    
        def update(self, command):
            #global currentLcd
            global lcdstart
            lcd.set_backlight(True)
            lcdstart = datetime.now()
            if DEBUG:
                print('do',command)
            if command == 'u':
                self.up()
            elif command == 'd':
                self.down()
            elif command == 'r':
                self.right()
            elif command == 'l':
                self.left()
            elif command == 's':
                self.select()
        def up(self):
            if self.curSelectedItem == 0:
                self.curTopItem=len(self.curFolder.items) 
                self.curSelectedItem=len(self.curFolder.items)-1
            elif self.curSelectedItem > self.curTopItem:
                self.curSelectedItem -= 1
            else:
                self.curTopItem -= 1
                self.curSelectedItem -= 1
        def down(self):
            if self.curSelectedItem+1 == len(self.curFolder.items):
                self.curTopItem=0 
                self.curSelectedItem=0
            elif self.curSelectedItem < self.curTopItem+DISPLAY_ROWS-1:
                self.curSelectedItem += 1
            else:
                self.curTopItem += 1
                self.curSelectedItem += 1
        def left(self):
            if isinstance(self.curFolder.parent, Folder):
                # find the current in the parent
                itemno = 0
                index = 0
                for item in self.curFolder.parent.items:
                    if self.curFolder == item:
                        if DEBUG:
                            print('foundit')
                        index = itemno
                    else:
                        itemno += 1
                if index < len(self.curFolder.parent.items):
                    self.curFolder = self.curFolder.parent
                    self.curTopItem = index
                    self.curSelectedItem = index
                else:
                    self.curFolder = self.curFolder.parent
                    self.curTopItem = 0
                    self.curSelectedItem = 0
        def right(self):
            if isinstance(self.curFolder.items[self.curSelectedItem], Folder):
                self.curFolder = self.curFolder.items[self.curSelectedItem]
                self.curTopItem = 0
                self.curSelectedItem = 0
            elif isinstance(self.curFolder.items[self.curSelectedItem], Widget):
                if DEBUG:
                    print('eval', self.curFolder.items[self.curSelectedItem].function)
                #eval(self.curFolder.items[self.curSelectedItem].function+'()')
            elif isinstance(self.curFolder.items[self.curSelectedItem], CommandToRun):
                self.curFolder.items[self.curSelectedItem].Run()
    
        def select(self):
            if DEBUG:
                print('check widget')
            if isinstance(self.curFolder.items[self.curSelectedItem], Widget):
                if DEBUG:
                    print('eval', self.curFolder.items[self.curSelectedItem].function)
                eval(self.curFolder.items[self.curSelectedItem].function+'('+self.curFolder.items[self.curSelectedItem].arg+')')
                
    
    # now start things up
    uiItems = Folder('root','')
    
    dom = parse(configfile) # parse an XML file by name
    
    top = dom.documentElement
    
    #currentLcd = lcd.OFF
    LcdOff()
    ProcessNode(top, uiItems)
    
    display = Display(uiItems)
    display.display()
    
    lcdstart = datetime.now()
    while 1:
        if (lcd.is_pressed(LCD.LEFT)):
           	display.update('l')
            display.display()
            sleep(0.25)
    
        if (lcd.is_pressed(LCD.UP)):
            display.update('u')
            display.display()
            sleep(0.25)
    
        if (lcd.is_pressed(LCD.DOWN)):
            display.update('d')
            display.display()
            sleep(0.25)
    
        if (lcd.is_pressed(LCD.RIGHT)):
            display.update('r')
            display.display()
            sleep(0.25)
    
        if (lcd.is_pressed(LCD.SELECT)):
            display.update('s')
            display.display()
            sleep(0.25)
    
        if AUTO_OFF_LCD:
            lcdtmp = lcdstart + timedelta(seconds=5)
            if (datetime.now() > lcdtmp):
                lcd.backlight(lcd.OFF)
    
    

    файл управления системой меню:

    <application>
      <settings lcdColor="White" lcdBackground="On" />
      <widget text="START" function="f_start" arg=""/>
      <folder text="FRAMES">
        <widget text="AUTO" function="f_auto" arg="0" />
        <widget text="3" function="f_set_frames" arg="3"/>
        <widget text="200" function="f_set_frames" arg="200"/>
        <widget text="400" function="f_set_frames" arg="400"/>
        <widget text="600" function="f_set_frames" arg="600"/>
        <widget text="800" function="f_set_frames" arg="800"/>
        <widget text="1000" function="f_set_frames" arg="1000"/>
      </folder>    
      <folder text="SECONDS">
        <widget text="10" function="f_set_seconds" arg="10"/>      
        <widget text="15" function="f_set_seconds" arg="15"/>      
        <widget text="20" function="f_set_seconds" arg="20"/>
        <widget text="30" function="f_set_seconds" arg="30"/>
        <widget text="40" function="f_set_seconds" arg="40"/>
        <widget text="50" function="f_set_seconds" arg="50"/>
      </folder>    
      <folder text="MINUTES">
        <widget text="1 Min" function="f_set_minutes" arg="60"/>
        <widget text="2 Min" function="f_set_minutes" arg="120"/>
        <widget text="3 Min" function="f_set_minutes" arg="180"/>
        <widget text="5 Min" function="f_set_minutes" arg="300"/>
        <widget text="8 Min" function="f_set_minutes" arg="480"/>
        <widget text="10 Min" function="f_set_minutes" arg="600"/>
        <widget text="15 Min" function="f_set_minutes" arg="900"/>
        <widget text="20 Min" function="f_set_minutes" arg="1200"/>
        <widget text="30 Min" function="f_set_minutes" arg="1800"/>
        <widget text="40 Min" function="f_set_minutes" arg="2400"/>    
        <widget text="50 Min" function="f_set_minutes" arg="3000"/>
        <widget text="60 Min" function="f_set_minutes" arg="3600"/>
      </folder> 
      <folder text="ZOOM">
        <widget text="Range 0-18: 0" function="f_set_zoom" arg="0"/>
        <widget text="Range 0-18: 4" function="f_set_zoom" arg="4"/>
        <widget text="Range 0-18: 8" function="f_set_zoom" arg="8"/>
        <widget text="Range 0-18: 12" function="f_set_zoom" arg="12"/>
        <widget text="Range 0-18: 15" function="f_set_zoom" arg="15"/>
        <widget text="Range 0-18: 18" function="f_set_zoom" arg="18"/>  
      </folder>
      <folder text="IMAGESIZE">
        <widget text="LARGE" function="f_set_imsize" arg="0"/>
        <widget text="MEDIUM 1" function="f_set_imsize" arg="1"/>
        <widget text="MEDIUM 2" function="f_set_imsize" arg="2"/>
        <widget text="SMALL" function="f_set_imsize" arg="3"/>
      </folder>      
      <folder text="MACRO">
        <widget text="AUTO" function="f_set_macro" arg="0"/>
        <widget text="CLOSE-UP" function="f_set_macro" arg="1"/>
       </folder>         
        <widget text="TURN OFF" function="f_shutdown" arg=""/>
        <widget text="EXIT" function="DoQuit" arg=""/> 
        <widget text="TEST" function="f_test" arg=""/> 
    </application>
    
    


    1. dlinyj Автор
      12.10.2021 00:33

      Тянет на ещё одну классную статью :). Спасибо за комментарий. Это очень круто!!!


  1. Vsevo10d
    11.10.2021 22:03

    Спасибо. А вы не проводили попутный ресерч на тему "делалось ли что-то подобное"? Просто интересно было бы попробовать как раз на венду и с петоном ;) может есть какие-то библиотеки или что-то выложено на гит - не попадалось?

    Насчет презрения к 400-ке удивился конечно - у самого валяется EOS-1D Mark II, купленный у Зеленого Кота году в 14-м - и то, недавно дрэг-рейсинг снимал, дает вполне достойные кадры.

    А, и да, Ясенево узнаю с первого кадра таймлапса, поностальгировал.


    1. dlinyj Автор
      12.10.2021 10:51

      А вы не проводили попутный ресерч на тему «делалось ли что-то подобное»?

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

      Насчет презрения к 400-ке удивился конечно

      Никакого презрения нет. Буквально месяц назад делал ей фотографии для статьи.


  1. Avokados
    12.10.2021 08:12

    Ночного эксперимента не было? Звёздное небо должно хорошо получиться;)


    1. dlinyj Автор
      12.10.2021 10:52

      У меня дома небо практически не видать, ну и в Москве звёзд почти не видно. В последнем видео видны несколько звёздочек, вот примерно так выглядит небо в Москве.


  1. DS28
    12.10.2021 09:11
    +1

    фотоаппарат Canon EOS 400D, для своего времени неплохой фотик для семейного фотоальбома, но с появлением хороших телефонов, практически не используется.
    Если к нему купить телевик, то любой хороший телефон ему проиграет)) У меня NIkon D3000 (чуть новее Canon EOS 400D), до сих пор активно используется именно с телевиком (самолёты, птицы и т.п.)


    1. dlinyj Автор
      12.10.2021 10:52

      Я просто разжился чуть другой камерой, 550D, и ощущаю разницу.


  1. stanislav_mikov
    12.10.2021 16:25
    +1

    А если не стоит задача непременно изобретать колесо, то можно купить на алишке за 800 рублей пульт https://aliexpress.ru/item/32795400211.html?sku_id=63933485406&spm=a2g2w.productlist.0.0.3ef24109j3p6PK — и снимать им. Размер фотки S крошечный, можно взять флешку побольше, и этого хватит для любого разумного времени продолжительности съёмки.

    А чтобы таймлапсы не мерцали, есть плагин "DeFlicker Timelapse" из набора "Re:Vision Plugins" (я использую в Adobe Premiere). Конечно, он занимает довольно много процессорного времени, но видео получается практически идеальное, без мерцания.

    Ну и про мысль вывернуть немного объектив из байонета тут уже писали — лепестки диафрагмы имеют тенденцию срабатывать нечётко по времени.


    1. dlinyj Автор
      12.10.2021 17:11

      Классный пультец, за ссылку спасибо, записал.

      А чтобы таймлапсы не мерцали, есть плагин «DeFlicker Timelapse» из набора «Re:Vision Plugins» (я использую в Adobe Premiere). Конечно, он занимает довольно много процессорного времени, но видео получается практически идеальное, без мерцания.


      Жаль в linux всё это не применимо.

      Уже немного устал объяснять, что таймлапсы — это просто побочный результат обучения работы с камерой с помощью программ.


    1. dlinyj Автор
      12.10.2021 17:14

      Посмотрел пультец:

      4. Количество экспозиции (N)
      Эта настройка позволяет установить время воздействия, которое будет снято, в общей сложности до 399 раз. Например,
      Если вы установите его в 30 раз, то воздействие будет занимать всего 30 раз.


      Ну вот первое видео у меня всего 600 кадров, 399 кадров — это вообще не о чём.


      1. stanislav_mikov
        12.10.2021 17:24

        Я на этом пульте никогда ограничение не использовал, потому что оно действительно маленькое — использую без ограничений, останавливая вручную. Когда-то колхозил умный пульт на ардуино, который через ик нажимал спуск на фотике, но в итоге оказалось проще и удобнее вручную останавливать пульт. А запуск по таймеру у него, кстати, есть. Это тоже удобно — управление по проводу пульта позволяет разбудить фотик, который пребывал в спящем режиме


        1. dlinyj Автор
          12.10.2021 18:27

          Крутая тема, правда.


      1. wormball
        12.10.2021 17:42

        > 4. Количество снимков: от 1 до 399,-- (без ограничений)

        Я так понял, что — (без ограничений) — это бесконечность.


        1. stanislav_mikov
          12.10.2021 19:03
          +1

          да, верно


  1. MicrofCorp
    12.10.2021 17:11
    +1

    Я тоже снимал таймлапсы, но у меня 550d и установлен magic lantern


    1. dlinyj Автор
      12.10.2021 17:12

      А он умеет снимать таймлапсы? Просто тоже есть такая камера, расскажите как это сделать?


      1. MicrofCorp
        13.10.2021 22:12
        +1

        Там и таймлапсы, и raw видео, и hdr видео, и звук съемка, и детекторы движения и интервалометры и выдержка вплоть до часов. В интернете полно гайдов на эту тему


  1. pocket_hitler
    13.10.2021 10:41
    +1

    Снимаю шляпу за настойчивость и за проявленный умения в изобретении велосипеда. Но для кэнонов давно есть Canon Hack Development Kit, который открывает всё то, чего нет в старом фотике из коробки. Там и скрипты для таймлапсов, и съемка в рав, и спуск затвора по изменению яркости (фоткать молнии, например). Я распечатал на принтере заглушку батареи, вставил внутрь DC-DC повышайку и теперь старый кэнон g9 с авито за 2 тысячи работает от usb и снимает таймлапсы в рав. Самый длинный таймлапс, что я снимал - 2 недели с интервалом в 45 сек. Но старые фотики для этого не очень тема, плохо переносят долгую работу без перерыва - уже носил его в ремонт, и сейчас вот у него опять проблемы, фигово фокусируется


    1. dlinyj Автор
      13.10.2021 10:42

      Снимаю шляпу за настойчивость и за проявленный умения в изобретении велосипеда. Но для кэнонов давно есть Canon Hack Development Kit

      На самом деле классная штука. Но, я уже устал говорить, что это был побочный эксперимент, который оказался таким классным, что о нём можно даже написать.


      1. pocket_hitler
        13.10.2021 12:30
        +3

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

        приложу пару своих видосов:

        https://youtu.be/_BjesantyQ8

        https://youtu.be/7BxzH8xgchc


        1. dlinyj Автор
          13.10.2021 12:38
          +1

          Просто потрясающе! Это реально выглядит невероятно. Ещё аудиодорожку наложить и будет бомба!


  1. SergeyNovak
    23.10.2021 11:19
    +1

    Для дневной съемки достаточно и обычной видеокамеры. Вот снимал лет так десяток назад выбрав для съемок день поинтересней:

    https://www.youtube.com/watch?v=VQBP7iSC-t8

    А вот ночью для хорошей выдержки фотоаппарат, конечно-же, получше будет.

    Еще практиковал захват кадров с камер видеонаблюдения из того-же баша:

    https://www.youtube.com/watch?v=RhP9Cnc3eKk


    1. dlinyj Автор
      24.10.2021 12:30

      Очень круто, правда!


  1. discipuli
    04.11.2021 22:52
    +1

    Более совершенный вариант вашего скрипта, можно скопировать в папку ~/.local/bin(или в нормальный /usr/local/bin) и запускать из нужной директории, пользователя неплохо было бы добавить в группы tty и usb.

    #!/bin/bash
    set -e
    if [ -z $END ]; then
        END=100
    fi
    if [ -z $SLEEPTIME ]; then
        SLEEPTIME=10
    fi
    gphoto2 --auto-detect
    gphoto2 --set-config=/main/imgsettings/imageformat=4
    for i in `seq -w 0 $END`
    do
      gphoto2 --capture-image-and-download --filename  "$i.jpg"
      sleep $SLEEPTIME
    done
    gphoto2 --set-config=/main/imgsettings/imageformat=7

    Запускать при моём способе установки так:

    $ END=600 SLEEPTIME=10 timelaps.sh


    1. dlinyj Автор
      05.11.2021 12:53

      очень годно, спасибо!


      1. discipuli
        05.11.2021 15:51
        +1

        Тут можно покопаться в настройках через флаг help и команду man, много чего интересного, однако хочу добавить, что флаг bulb почему то не описан в man-е

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