Arduino e vídeo? Fácil


Sabe-se que um microcontrolador Arduino fraco não é capaz de transmitir um fluxo de vídeo por si mesmo.
E se você abordar esta tarefa de outro lado?

... e amplie o processo de filmagem a tempo.

Heh, muitos já imaginaram por si mesmos que essa técnica é chamada timelapse (filmagem em câmera única de câmera lenta). Ou seja, não é uma gravação de vídeo, mas uma gravação, como resultado da criação de um vídeo.

Eu admito, inicialmente eu não planejei fazer uma câmera lenta. Eu só queria fazer um registro de eventos para meus arduins, inclusive com fotos. Bem, então de vez em quando. Se meu leitor não estiver envolvido no desenvolvimento, ele poderá ver apenas o resultado (acesse Chrome).

Em que meu sistema consiste:
  • Arduino Mega Board
  • Módulo JPEG da câmera;
  • utilitário e banco de dados MongoDB;
  • Servidor WEB para hospedagem de arquivos HTML;


Quando o arduina envia seus dados para o servidor, seu próprio carimbo de data / hora é anexado a cada parâmetro.
O parâmetro foi enviado - um registro foi adicionado ao repositório, mais duas vezes foram enviadas - mais dois registros foram salvos.

Todo o trabalho com o repositório é realizado através de um programa utilitário (a seguir denominado intermediário), que é iniciado em um computador estacionário. Ao mesmo tempo, o próprio servidor WEB fornece apenas conteúdo estático. Ou seja, todos os clientes realizam trocas de informações por meio do programa utilitário do intermediário, semelhante ao protocolo MQTT popular. A principal diferença do MQTT será que esse intermediário trabalha diretamente com o data warehouse, fornecendo trabalho com dados históricos. Esse fato simplifica o esquema de interação e não requer tráfego de rede adicional para salvar dados.

Para a conveniência de desenvolver meus aplicativos Web, criei uma biblioteca javascript com a seguinte API:

Isso cria um cliente para trabalhar com armazenamento em rede:
var client = new MgtClient("localhost", "login", "password", onDebugLog);

Argumentos da função:
  1. o endereço de rede no qual o programa intermediário está sendo executado, você pode simplesmente especificar o IP, por exemplo, “127.0.0.1”;
  2. login de usuário;
  3. senha de usuário
  4. função de retorno de chamada, para depurar mensagens de string;


A função de retorno de chamada para mensagens de depuração pode ter esta aparência:
function onDebugLog(aStr) {
  //          
  console.log((new Date()).getTimeString() + ' ' + aStr + '\n'); 
}


Ainda não é difícil? Além disso, será difícil.

Estrutura de solicitação de armazenamento:
var request = {
  name: " 1", //   
  placeId: 1, //                         
  beginTime: 1458108472000, //      1  1970 
  endTime: 1458194872000, //      1  1970  ( )
  limit: 10000 //   ,    (   )
};


Ainda não está confuso?

Então aqui está a estrutura da resposta à solicitação:
var result = {
  times: [], //      (    1  1970 )
  values: [], //    
  position: 20, //         (   )
  status: "progress", //    ("progress", "abort", "done", "fail")
  progress: 91 //   ( )   
};


Sim, é mais complicado?

Status do campo "status":
  • “Concluído” - recebeu tudo o que foi solicitado (dados para todo o intervalo de tempo foram recebidos ou o limite do número de registros trabalhados);
  • "Progresso" - indica que este não é o último dado, o processo de download ainda não está concluído;
  • “Abortar” - o download dos dados foi interrompido (a restrição na quantidade total de dados sendo bombeados funcionou), você pode gerar imediatamente uma nova solicitação para receber os dados ausentes;
  • "Fail" - algo deu errado (talvez não haja corrente na tomada?)


Você acha que é tudo? Infelizmente não.

Os parâmetros solicitados podem ser de tipos diferentes.
  • Se o parâmetro for numérico, os números aparecerão na matriz de valores.
  • Se a string, na matriz de valores, haverá strings.
  • Se booleano, a matriz de valores será "true" ou "false".
  • Se for binário (por exemplo, uma imagem JPEG), as matrizes de bytes estarão na matriz de valores.
  • Se este for um evento, retorne matrizes formadas de uma maneira especial.

Um exemplo de um único registro de evento:
var event = [
  "  ", //   
  "", //   1
  27.5, //   1
  "", //   2
  true, //   2
  ...
  "", //   
  1458108472000 // !!!       ,
                //        .
];

Ou seja, cada registro de evento pode conter um conjunto arbitrário de parâmetros. Esse agrupamento é muito conveniente para analisar a imagem geral.

Uff, a parte mais difícil acabou.

E assim, a solicitação que se envia se parece:
// aRequest -  
// onReadArchive -     /
client.readArchive(aRequest, onReadArchive);                                                           


Função inversa para obter respostas:
// aResult -  
onReadArchive(aResult) {
  // TODO       

  //   "false",     (    )
  //   "true",      (    ) 
  return false; 
}


Finalmente, chegamos à edição de vídeo em si.

Para criar o vídeo, usei a biblioteca javascript do Whammy, mais detalhes aqui.

Função que cria o vídeo:

<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; //    
}


Infelizmente, você não pode criar vídeos em todos os navegadores. Por exemplo, meu Firefox favorito não sabe converter imagens para o formato WebP, com base no qual a conversão em vídeo ocorre. E embora eu tenha encontrado uma biblioteca javascript para essa conversão, ela foi convertida tão lentamente (e havia tantos quadros) que me recusei a usá-la. No entanto, em todos os navegadores com o mecanismo Chrome, isso funcionará.

Aqui você pode ver o que eu fiz.

Sem documentação completa, posso oferecer meus artigos anteriores.
Article 1
Article 2

Bem, isso é tudo, e não tenho mais nada a dizer.

Source: https://habr.com/ru/post/pt391773/


All Articles