- PVSM.RU - https://www.pvsm.ru -
Известно, что слабый микроконтроллер ардуино не способен пропустить через себя видеопоток.
А если подойти к этой задаче с другого бока?
… и растянуть процесс съёмки во времени.
Хе, многие уже и сами догадались, эта техника съёмки называется timelapse (замедленная покадровая съёмка). То есть это никакая не видеосъёмка, а фотосъёмка, в результате которой создаётся видео.
Признаюсь, изначально я не планировал делать замедленную съёмку. Просто хотел сделать для своей ардуины регистрацию событий, в том числе и с фотографиями. Ну а потом пошло-поехало. Если мой читатель не занимается разработкой, то может просто посмотреть полученный результат [1] (зайти из под Chrome).
Из чего состоит моя система:
Когда ардуина посылает свои данные на сервер, то к каждому параметру прикрепляется своя метка времени.
Отправили параметр — добавилась запись в хранилище, ещё два раза отправили — сохранились ещё две записи.
Вся работа с хранилищем ведётся через служебную программу (далее посредник), которая запускается на стационарном компьютере. При этом, сам WEB сервер отдаёт только статичный контент. То есть, все клиенты ведут информационный обмен через служебную программу посредника, аналогично популярному протоколу MQTT. Основное отличие от MQTT будет в том, что этот посредник напрямую работает с хранилищем данных, обеспечивая работу с историческими данными. Этот факт упрощает схему взаимодействия, и не требует дополнительного сетевого трафика для сохранение данных.
Для удобства разработки своих веб приложений, я создал javascript библиотеку с таким API:
Так создаётся клиент для работы с сетевым хранилищем:
var client = new MgtClient("localhost", "login", "password", onDebugLog);
Аргументы функции:
Функция обратного вызова для отладочных сообщений может выглядеть так:
function onDebugLog(aStr) {
// метка времени и сообщение будут выводиться в отладочную консоль браузера
console.log((new Date()).getTimeString() + ' ' + aStr + 'n');
}
Пока не сложно? Дальше будет потрудней.
Структура запроса к хранилищу:
var request = {
name: "параметр 1", // имя запрашиваемого параметра
placeId: 1, // идентификатор вашего объекта
beginTime: 1458108472000, // начальное время в миллисекундах от 1 Января 1970 года
endTime: 1458194872000, // конечное время в миллисекундах от 1 Января 1970 года (не включительно)
limit: 10000 // максимальное количество записей, не обязательный параметр (по умолчанию без ограничения)
};
Ещё не запутались?
Тогда вот структура ответа на запрос:
var result = {
times: [], // массив временных меток полученных записей (время в миллисекундах от 1 Января 1970 года)
values: [], // массив значений полученных записей
position: 20, // порядковый номер указывающий на новые данные в массиве (данные могут поступать порциями)
status: "progress", // состояние запущенного процесса ("progress", "abort", "done", "fail")
progress: 91 // индикатор выполнения (в процентах)
};
Ага, уже сложней?
Состояние поля «status»:
Вы думаете это всё? К сожалению, нет.
Запрашиваемые параметры могут быть разного типа.
Пример одной записи события:
var event = [
"сработал датчик движения", // заголовок произошедшего события
"термометр", // имя параметра 1
27.5, // значение параметра 1
"светодиод", // имя параметра 2
true, // значение параметра 2
...
"фото", // имя последнего параметра
1458108472000 // сюрприз!!! это всего лишь временная метка сохранённого изображения,
// нужно сформировать дополнительный запрос для выкачивания этого изображения.
];
То есть, каждая запись события может содержать произвольный набор параметров. Такая группировка очень удобна для анализа общей картины.
Уфф, самое сложное уже позади.
А так выглядит сама отправка запроса:
// aRequest - структура запроса
// onReadArchive - обратная функция для получения ответа/ответов
client.readArchive(aRequest, onReadArchive);
Обратная функция для получения ответов:
// aResult - структура ответа
onReadArchive(aResult) {
// TODO вставьте свой код обработки пришедших данных
// если вернём "false", то продолжим принимать ответы (если процесс приёма не завершён)
// если вернём "true", то обрываем получение остальных ответов (если процесс приёма не завершён)
return false;
}
Наконец мы подошли к самому монтажу видео.
Для создания видео я использовал javascript библиотеку Whammy, здесь подробнее. [2]
Функция, которая создаёт видео:
<script src="whammy.js"></script>
<canvas id="canvas" style="display:none"></canvas>
<video id="player" controls autoplay loop></video>
function createVideo() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = '640'; // это ширина фоток в пикселях
canvas.height = '480'; // это высота фоток в пикселях
var framerate = 10; // устанавливаем количество кадров в секунду
var quality = 0.8; // устанавливаем качество видео
var video = new Whammy.Video(framerate, quality); // объект для создания видео в формате WebM
for (var i = 0; i < images.length; i++) { // пройдёмся по всем изображениям
var image = images[i];
context.globalAlpha = 1;
context.drawImage(image, 0, 0, 640, 480); // сначала размещаем изображение на канву
video.add(context); // добавляем новый кадр
}
var output = video.compile(); // создаём видео из кадров
var url = URL.createObjectURL(output); // конвертируем в нужный формат
document.getElementById('player').src = url; // подсовываем результат нашему проигрывателю
}
К сожалению, создать видео можно не во всех браузерах. Например, мой любимый Firefox не умеет преобразовывать изображения в формат WebP, на основе которого и происходит конвертация в видео. И хотя я нашёл javascript библиотеку для такого преобразования, но конвертировала она так медленно (а кадров было так много), что я отказался от её применения. Впрочем, во всех браузерах с «хромовским» движком эта штука работать будет.
Здесь вы можете посмотреть что у меня получилось. [1]
Не имея цельной документации, могу предложить мои предыдущие статьи.
Статья 1 [3]
Статья 2 [4]
Ну вот и всё, и сказать то мне больше нечего.
Автор: valeraba
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/umny-j-dom/115419
Ссылки в тексте:
[1] полученный результат: http://samde.ru/ru/history.html
[2] здесь подробнее.: http://techslides.com/convert-images-to-video-with-javascript
[3] Статья 1: https://geektimes.ru/post/255018/
[4] Статья 2: https://geektimes.ru/post/255412/
[5] Источник: https://geektimes.ru/post/272694/
Нажмите здесь для печати.