Съемка панорам с квадракоптера 4 камерами Raspberry Pi и представление их в html 5 программой Pannellum

MultiWii

Последние годы основным направлением моей деятельности была автоматизация процесса съемки сферических панорам. Удачное решение с одной камерой, установленной на штативе, было найдено еще 4 года назад, и я до сих пор активно использую созданную тогда установку. Тогда же я нашел и полностью меня удовлетворяющий способ представления панорам в интернете с помощью программы SaladoPlayer. Однако, хотя я использовал штатив со штангой длиной более 2 метров (например, так снята эта панорама), для ряда задач это было неприемлемым ограничением. Поэтому я решил заменить штатив квадракоптером. Задача была решена, но оказалось, что вращение камеры за счет поворота летательного аппарата требует практически недоступного мне идеального пилотирования. Была создана конструкция с вращающейся относительно вертолета камерой. Зависнуть в точке существенно проще, чем развернуться на месте без смещения в сторону и потери высоты. Тем не менее сшивка такой панорамы оставалась трудоемким процессом без гарантии получения удовлетворительного результата. Решение, лежащее на поверхности,- это создание легкой многокамерной системы, снимающей все кадры панорамы одновременно. К счастью, появился проект Raspberry Pi, предоставляющий идеальные кубики для решения этой задачи.В результате была собрана Панорамная камера на 4-х Raspberry Pi. Вопросу адаптации этой камеры для полетов, за счет дополнения конструкции системой стабилизации и посвящена эта статья. Одновременно оказалось, что технология Flash не поддерживается многими современными устройствами и необходимо искать новый универсальный способ представления панорам. Панацеи я не нашел. HTML 5 решает проблему для ряда планшетов и телефонов, но не для всех. Для систем с Android 2.3.5 Flash остается единственно приемлемым по функциональным возможностям решением. Для настольных компьютеров и ноутбуков можно получить близкие результаты и с Flash и с HTML 5, хотя SaladoPlayer, сменивший название на OpenPano и практически прекративший развитие, остается для меня более гибким и удобным способом представления сферических панорам. Тем не менее надо быть готовым к тому, что устройств, поддерживающих Flash, будет все меньше. Во второй части статьи я рассмотрю вопрос представления панорам с помощью программы Pannellum.

Съемка панорам с квадракоптера 4 камерами Raspberry Pi

Для подвески к квадракоптеру наземная камера была существенно перекомпонована.

MultiWii

Были установлены две рулевые машинки и плата MultiWii 328P Flight Controller. Можно было бы использовать и плату управления коптером, но это усложнило бы подвес, который был реализован как свободно качающийся, что позволяло камерам при посадке складываться между опор. Дополнительный вес платы невелик, зато камера может использоваться автономно и не требует при подвеске точного выравнивания по осям. Для стабилизации использовалась прошивка MultiWii 2.3 без каких либо изменений и в файле config.h в разделе The type of multicopter был раскомментирован #define GIMBAL. Вес квадракоптера с камерой без аккумулятора 1290 г.

Программа для Raspberry Pi была упрощена до предела и сделана одинаковой для всех камер:

import RPi.GPIO as GPIO
import time
import picamera
fr=0
flag1=0
GPIO.setmode(GPIO.BCM)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
f = open('/home/pi/fotopicam/foto.txt', 'r')
fs = f.read()
f.close()
ffs = fs +'f'
f = open('/home/pi/fotopicam/foto.txt', 'w')
f.write(ffs)
f.close()
with picamera.PiCamera() as camera:
    camera.resolution = (2592, 1944)
    camera.framerate = 15
    camera.rotation = 180
    camera.awb_mode = "sunlight"
    camera.exif_tags['IFD0.Artist'] = "RWPBB"
    camera.exif_tags['EXIF.FocalLength'] = '9.5'
    camera.exif_tags['EXIF.FocalLengthIn35mmFilm'] = '16.5'
    camera.iso = 100
    camera.shutter_speed = 0
    camera.start_preview()
    start = time.time()
    def printFunction(channel):
        global start
        fin = time.time()
        if fin-start>14:
            start = time.time()
            global fr
            fr=fr+1 
            camera.shutter_speed = 0
            camera.capture("/home/pi/fotopicam/"+ffs+"pi195s1sn%03d.jpg" % fr)
            camera.shutter_speed = 500
            camera.capture("/home/pi/fotopicam/"+ffs+"pi195s2sn%03d.jpg" % fr)
            camera.shutter_speed = 2500
            camera.capture("/home/pi/fotopicam/"+ffs+"pi195s3sn%03d.jpg" % fr)
            camera.shutter_speed = 1000
            camera.capture("/home/pi/fotopicam/"+ffs+"pi195s4sn%03d.jpg" % fr)
            camera.shutter_speed = 0
   
   GPIO.add_event_detect(24, GPIO.FALLING, callback=printFunction, bouncetime=300)
   while True:
       a=1
   
GPIO.cleanup()

Для запуска съемки использовался канал управления рулевой машинкой, используемой для нажатия на кнопку камеры - #define CAMTRIG. Сигнал через оптопару подавался на GPIO всех 4-х плат. Поскольку это псевдоаналоговый сигнал, получаемый за счет изменения скважности ШИМ, то обязательно включить в цепь RC фильтр, иначе камера будет снимать непрерывно, реагируя на 5 В импульсы. Я использовал конденсатор 40 летней давности, поэтому его истинная емкость остается тайной, но полагаю, что сопротивления в 1 кОм и конденсатора в 5 мкФ должно хватить.

схема

Конечно, можно было получить с контроллера и чисто цифровой сигнал слегка изменив программу, но я здесь руководствовался принципом, работает - не трогай :-). Оптрон же все равно необходим поскольку Raspberry Pi работает при 3,3 В, а контроллер работает от 5 В. Делитель напряжения из двух сопротивлений ненамного легче оптрона, а риски сжечь по неосторожности возрастают. При получении сигнала все 4 камеры делают синхронно 4 снимка с выдержками 1/400, 1/1000, 1/2000 секунды и снимок в автоматическом режиме. Предварительный просмотр включен постоянно и с передней камеры выводится на ТВ передатчик через OSD. Здесь следует заметить, что разъем на B+ весьма специфический - 3,5 мм штекер имеет 4 контактных площадки, из которых видеосигнал - это самая ближняя к входному проводу, а следующая за ней - это земля.

tv 1-Видео
2-Земля
3-Аудио правый канал
4-Аудио левый канал

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

фото

Калибровку гироскопов можно провести и позже, если левую ручку отвести вниз и влево, а правую вниз. В рабочем состоянии камера свешивается ниже опор, и они не мешают снимать нижнюю полусферу с высоты более 20 м.

фото



фото

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

фото

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

Представление сферических панорам в html 5 программой Pannellum

Программа Pannellum это плагин, который использует HTML5, CSS3, JavaScript, и WebGL. Она может быть легко развернута в виде упаковки из одного файла pannellum.htm размером 46КБ, и кода <iframe> который вставляется в html страницу. Программа может быть загружена с сайта проекта, где будет предложено несколько вариантов. Pannellum 2.1.1, Pannellum 2.1.1(with tools and examples) и Pannellum Source который предлагается скачать с GitHub. Последний вариант на мой взгляд предпочтительней поскольку позволяет менять стили представления. Т.е. размер шрифтов иконки и другие мелочи.

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

1. Загрузите build/pannellum.htm и панораму в эквидистантной проекции на веб-сервер.
Из-за соображений безопасности браузера web сервер должен быть использован и для локального просмотра. С Python 2 можно использовать команду: python -m SimpleHTTPServer, а с Python 3: python -m http.server. Любой другой веб-сервер тоже будет работать. (Я использую Apache, ранее установленный на моей машине со Slackware, запустив его предварительно командой: bash-4.1# apachectl start).

2. Используйте прилагаемый генератор utils/multires/generate.py или веб=интерфейс utils/config/configuration.htm.

3. Вставьте генерированный <iframe> код в страницу.

Сферические панорамы получаются обычно довольно большими и наиболее удобный способ их представления это использование пирамиды из снимков с разным разрешением. Для разбивки панорамы на фрагменты с разным разрешением в полном комплекте программы Panntllum присутствует утилита generate.py. Для ее работы естественно необходим Python, а кроме того программа nona входящая в пакет hugin. Запускаем python generate.py pano_image.jpg в каталоге utils/multires и получаем в папке ./output фрагменты с разным разрешением и файл config.json.

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

фалы

В размере я конечно вдвое потерял, все файлы тянут аж на 100 КБ, но выиграл в гибкости и удобстве. Если же передавать работу заказчику, то ничего не мешает генерировать из них свой pannellum.htm, запустив утилиту build.sh.

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

pi4desna.html

<!DOCTYPE HTML>
     <html>
     <head>
 <title>Панорама р. Десна</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 </head>
 <body>
 <iframe title="pannellum panorama viewer" width="800" height="600" 
 webkitAllowFullScreen mozallowfullscreen allowFullScreen 
 style="border-style:none;" 
 src="../src/pannellum.htm?tour=../pano/pi4desna.json"></iframe>
 </body>
 </html>

pi4desna.json

{
   "default": {
   "author": "RWPBB",
   "autoLoad": true,
   "firstScene": "desna1"
     },
   
   "scenes": {
   "desna2": {
   "title": "р. Десна 2", 
   "type": "multires",
   "yaw": 50,
   "pitch": -10,
   "multiRes": {
   "basePath": "./pi4desna2",
   "path": "/%l/%s%y_%x",
   "fallbackPath": "/fallback/%s",
   "extension": "jpg",
   "tileResolution": 512,
   "maxLevel": 4,
   "cubeResolution": 2384 
     },
   "hotSpots": [
   
     {
   "pitch": 10,
   "yaw": -50,
   "type": "scene",
   "text": "Десна 1",
   "sceneId": "desna1"
     }
     ]
     }, 
   "desna1": {
   "title": "р. Десна 1",
   "type": "multires",
   
   "yaw": 80,
   "pitch": -10,
   "multiRes": {
   "basePath": "./pi4desna1",
   "path": "/%l/%s%y_%x",
   "fallbackPath": "/fallback/%s",
   "extension": "jpg",
   "tileResolution": 512,
   "maxLevel": 4,
   "cubeResolution": 2432 
     },
   "hotSpots": [
     {
   "pitch": 5,
   "yaw": -50,
   "type": "scene",
   "text": "Десна 2",
   "sceneId": "desna2"
     }
     ]
     }
     }
}
панорама
3.06.2015
Установите проигрыватель Flash

Облако тегов:
3D печать
Arduino
Raspberry Pi
Аэрофотосъемка
Байдарки
Геомеханика
История
Камеры
Макросъемка
Объективы
Освещение
Панорамы
Принадлежности
Принтеры
Программы
Сканеры
Стереосъемка
Фильтры
Фокусировка
Фотокубики
...
rss