Babá RPi

De vez em quando, sou tentado a fazer algo estranho. Obviamente uma coisa inútil que não se justifica pelo valor do investimento e, seis meses após a sua criação, junta pó na prateleira. Mas, por outro lado, justifica-se plenamente em termos da quantidade de emoções, da experiência adquirida e das novas histórias. Há até dois dos meus artigos sobre Habré sobre esses experimentos: Alcoorgan e um alimentador inteligente de pássaros .



Bem. É hora de falar sobre um novo experimento. Como ele o coletou, o que resultou e como repeti-lo.







Fui estimulado a um novo projeto por um evento, em certo sentido, banal - um filho nasceu. Arrumei para mim uma licença com um mês de antecedência. Mas a criança acabou ficando quieta - havia tempo livre. E coloque o dormindo ao lado dele.



Muitas casas diferentesHardware embarcado para visão computacional. Como resultado, decidi fazer uma babá de vídeo. Mas não tão enfadonho quanto todas as lojas estão cheias. E algo mais inteligente e interessante.



O artigo será escrito em uma veia narrativa para entender como foi o desenvolvimento do brinquedo, de onde veio e para onde vai.



O artigo tem vários acréscimos:



  1. Vídeo onde mostro e conto como tudo funciona.
  2. Um pequeno artigo sobre VC, onde eu digo por que essas coisas provavelmente não chegarão à produção normal e sobre as limitações dos sistemas de ML desse tipo.
  3. Os tipos de tudo no ready-made github + imagem para RPI. No final do artigo, uma descrição de como usá-lo.


Escolhendo uma ideia



A funcionalidade mais comum de um monitor de bebê é ver o que está acontecendo com a criança a qualquer momento. Infelizmente, isso nem sempre funciona. Você não vai assistir à transmissão o tempo todo, não é conveniente. O bebê geralmente pode ser colocado para dormir próximo a um casulo, por que assistir a vídeos o tempo todo? Como resultado, a seguinte coleção foi montada para começar:



  1. O sistema deve possibilitar a visualização de um vídeo ou foto a qualquer momento do telefone
  2. O sistema deve responder ao acordar da criança e notificar sobre isso
  3. O sistema deve detectar rosto ausente para evitar SIDS


Seleção de plataforma



Eu tive um longo artigo sobre Habré sobre como comparar diferentes plataformas. Globalmente, para um protótipo como o que estou fazendo, existem várias opções:



  1. Jetson Nano. + ( Nano), , . . — TensorRT. . , , , TensorRT .
  2. VIM3. , . — .
  3. Raspberry PI + Movidius. . , , .
    1. , .
    2. . .
  4. Raspberry PI 4 - ao trabalhar através do OpenCV é bom descartar redes abertas, que devem ser suficientes. Porém, havia a suspeita de que não haveria desempenho suficiente.
  5. Coral - Eu tenho em mãos, passaria em termos de performance, mas meu outro artigo diz porque eu não gosto :)


Então, eu escolhi Rpi + movidius. Eu tenho em mãos, posso trabalhar com ele.



Ferro



O computador é Raspberry Pi 3B, o neuroprocessador é Movidius Myriad X. Isso está claro.

O resto - raspado ao longo do fundo do barril, comprado em adição.







Câmera



Eu verifiquei três diferentes que eu tinha:



  • Câmera da RaspberryPI. Cabo barulhento e inconveniente, nenhum acessório conveniente. Marcado.
  • Algum tipo de câmera IP. Muito útil porque não precisa ser incluído no RPI. A câmera está separada do computador. Meu celular tinha até dois modos, dia e noite. Mas o que eu tinha não dava uma qualidade de rosto suficiente.
  • Webcam da Genius. Eu tenho usado por cerca de 5 anos já. Mas algo ficou instável recentemente. Mas para RPI, apenas certo. Além disso, descobriu-se que ele pode ser desmontado trivialmente e o filtro IR removido de lá. Além disso, como descobrimos mais tarde, essa era a única opção com microfone.






E o filtro muda assim:







Em geral, está claro que esta não é uma solução de produto. Mas funciona.



Se houver alguma coisa, no código você verá as peças restantes para alternar para os outros dois tipos de câmeras. Talvez até algo funcione totalmente se você alterar 1-2 parâmetros.



Iluminação



Eu tinha um iluminador por perto com um dos velhos quebra-cabeças.



Soldei algum tipo de fonte de alimentação nele. Ele brilha bem.







Aponte para o teto - a sala está iluminada.







Tela



Para alguns modos de operação, eu precisava de um monitor. Parado nisso . Embora eu não tenha certeza se esta é a decisão certa. Talvez eu devesse ter pego o de corpo inteiro. Mas mais sobre isso mais tarde.







Nutrição



A criança dorme em lugares arbitrários. Portanto, é mais fácil quando o sistema é alimentado por um banco de energia. Eu escolhi este, simplesmente porque é em casa para caminhadas:







OpenVino



Vamos percorrer um pouco o OpenVino. Como disse acima, uma grande vantagem do OpenVino é a grande quantidade de redes pré-treinadas. O que pode ser útil para nós.



Detecção de rosto. Existem muitas redes no OpenVino:



  1. 1
  2. 2
  3. 3


Reconhecimento de pontos-chave no rosto . Precisamos disso para lançar as seguintes redes de

orientação facial . Atividade da criança e para onde ela olha.

Reconhecimento da direção do olho - se você tentar interagir com a

análise de profundidade ? Talvez

acabe a análise do esqueleto

Bem, existem muitos outros interessantes ...



A principal desvantagem dessas redes será sua principal vantagem - seu pré-treinamento ...



Isso pode ser corrigido, mas agora estamos fazendo um protótipo rápido, nosso objetivo não é trabalhar em 100% dos casos, mas um trabalho fundamental que trará pelo menos algum benefício.



Ir. Lógica geral versão 1



Como estamos desenvolvendo um dispositivo embarcado, precisamos interagir de alguma forma com ele. Receba sinais de foto / alarme. Resolvi então fazer o mesmo de quando fiz a cocho , via telegramas. Mas lembre-se.



Para a primeira versão, decidi:



  • Inicie as redes designadas no RPi (gostaria de tudo de uma vez, de repente o desempenho permitirá). Isso permitirá que você veja mais opções para resolver o problema / prováveis ​​formas de desenvolvimento
  • Escreva um modelo geral de programa.
  • Crie um algoritmo que reconheça o despertar.
  • Faça um algoritmo que envie uma notificação na perda de face


Tudo correu mais ou menos bem, exceto por um monte de bugs ao redor. Isso é inerente ao ComputerVision ... Estou acostumado com isso.



Aqui está um rápido resumo do que descobri:



  1. OpenVino RPi ( 2020) - from openvino.inference_engine import IECore. OpenVino ( OpenCV ), , .
  2. OpenVino , -generate_deprecated_IR_V7
  3. OpenVino ( , ) Movidius int 8 . int32 . RPi int8 . , .
  4. OpenVino . , OpenVino . , — .
  5. OpenVino , Intel ( , ).
  6. PyTorch 1.5 onnx, 1.4…


Mas, veja como ... Tenho certeza de que se eu passasse pelo TensorRT, haveria mais problemas, como sempre.



Então. Tudo se junta, as redes funcionam, a gente consegue algo assim (passando a pilha na cabeça, orientação, pontos-chave):







Percebe-se que muitas vezes o rosto se perde quando a criança o cobre com as mãos / vira a cabeça. e nem todos os indicadores são estáveis.



Qual é o próximo? Como analisar o adormecimento?



Eu olho para aquelas grades que existem, e a primeira coisa que vem à mente é reconhecer as emoções. Quando a criança está dormindo e quieta, há uma expressão neutra em seu rosto. Mas não é tão simples. Aqui está um gráfico azul escuro, esta é uma expressão neutra de uma criança dormindo por uma hora:







O resto dos gráficos são tristes / zangados / alegres / surpresos. Nem mesmo a essência do que está nas cores. Infelizmente, os dados da rede são instáveis, que é o que vemos. A instabilidade ocorre quando:



  • Sombra excessiva no rosto (o que não é incomum à noite)
  • Os rostos da criança não estavam no conjunto de treinamento OpenVino => mudança arbitrária para outras emoções
  • A criança realmente faz caretas, inclusive em um sonho


No geral, não fiquei surpreso. Já encontrei redes que reconhecem emoções antes, e elas são sempre instáveis, inclusive devido à instabilidade da transição entre emoções - não há limites claros.



Ok, o despertar não pode ser reconhecido com a ajuda de emoções. Até agora, eu não queria ensinar algo sozinho, então decidi tentar com base nas mesmas redes, mas do outro lado. Uma das redes fornece o ângulo de rotação da cabeça. Isso já é melhor (desvio total de olhar para a câmera no tempo em graus). Últimos 5-10 minutos antes de acordar:







Melhor. Mas ... O filho pode começar a balançar a cabeça durante o sono. Ou vice-versa, se você definir um limite grande - acorde e não balance a cabeça depois disso. Para receber uma notificação todas as vezes ... Infelizmente:





(há cerca de uma hora de sono)



Portanto, ainda precisamos fazer o reconhecimento normal.



Problemas encontrados na versão 1



Vamos resumir tudo o que não gostei na primeira versão.



  1. Começo automático. Não é conveniente reiniciar este brinquedo toda vez, conectar via SSH, executar o script de monitoramento. Nesse caso, o script deve:

    • Verifique o status da câmera. Acontece que a câmera está desligada / não conectada. O sistema deve esperar que o usuário ligue a câmera.
    • Verificando o status do acelerador. O mesmo que acontece com a câmera.
    • Verificando a rede. Quero usar a coisa tanto em casa quanto no campo. Ou talvez em outro lugar. E, novamente, não quero fazer login via ssh => Preciso fazer um algoritmo para me conectar ao wiFi se não houver Internet.
  2. Acordando, treinamento em rede. Não surgiram abordagens simples, o que significa que é necessário treinar o neurônio para reconhecer olhos abertos.


Começo automático



Em geral, o esquema de execução automática é o seguinte:



  • Eu lanço meu programa no início. Como faço - escrevi um artigo separado, para não dizer que é trivial fazer no RPi. Em resumo:

    • OpenVino
    • , —
  • Movidius-
    • — QR- wifi
  • telegram . — QR-




Não existe uma rede de reconhecimento de olhos pronta no OpenVino.

Hahaha. A rede já apareceu. Mas, como se viu, ele só foi lançado depois que comecei a desenvolver. E no lançamento e na documentação, já apareceu quando eu mais ou menos fiz tudo. Agora eu estava escrevendo um artigo e encontrei uma atualização .

Mas não vou refazer, então escrevo como escrevi.



É muito fácil treinar essa rede. Acima, eu disse que usei a seleção dos olhos por quadro. Não há mais nada: adicione o salvamento de todos os olhos encontrados no quadro. Acontece um conjunto de dados:







Resta marcá-lo e treiná-lo. Descrevi o processo de marcação com mais detalhes aqui (e um vídeo do processo de 10 minutos aqui) Toloka foi usado para marcação. Demorou cerca de 2 horas para configurar a tarefa e 5 minutos para marcar + 300 rublos do orçamento.



Ao aprender, eu realmente não queria pensar, então peguei uma rede obviamente rápida e de qualidade suficiente para resolver o problema - mobilenetv2. Todo o código, incluindo o carregamento do conjunto de dados, a inicialização e o salvamento, levou menos de 100 linhas (a maioria tirada de fontes abertas, reescreveu algumas dezenas de linhas):



Texto oculto
import numpy as np
import torch
from torch import nn
from torch import optim
from torchvision import datasets, transforms, models



data_dir = 'F:/Senya/Dataset'
def load_split_train_test(datadir, valid_size = .1):
    train_transforms = transforms.Compose([transforms.Resize(64),
                                           transforms.RandomHorizontalFlip(),
                                           transforms.ToTensor(),
                                       ])
    test_transforms = transforms.Compose([transforms.Resize(64),
                                      transforms.ToTensor(),
                                      ])
    train_data = datasets.ImageFolder(datadir,
                    transform=train_transforms)
    test_data = datasets.ImageFolder(datadir,
                    transform=test_transforms)
    num_train = len(train_data)
    indices = list(range(num_train))
    split = int(np.floor(valid_size * num_train))
    np.random.shuffle(indices)
    from torch.utils.data.sampler import SubsetRandomSampler
    train_idx, test_idx = indices[split:], indices[:split]
    train_sampler = SubsetRandomSampler(train_idx)
    test_sampler = SubsetRandomSampler(test_idx)
    trainloader = torch.utils.data.DataLoader(train_data,
                   sampler=train_sampler, batch_size=64)
    testloader = torch.utils.data.DataLoader(test_data,
                   sampler=test_sampler, batch_size=64)
    return trainloader, testloader

trainloader, testloader = load_split_train_test(data_dir, .1)
print(trainloader.dataset.classes)

device = torch.device("cuda" if torch.cuda.is_available()
                                  else "cpu")
model = models.mobilenet_v2(pretrained=True)
model.classifier = nn.Sequential(nn.Linear(1280, 3),
                                 nn.LogSoftmax(dim=1))
print(model)
criterion = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.003)
model.to(device)
epochs = 5
steps = 0
running_loss = 0
print_every = 10
train_losses, test_losses = [], []
for epoch in range(epochs):
    for inputs, labels in trainloader:
        steps += 1
        inputs, labels = inputs.to(device), labels.to(device)
        optimizer.zero_grad()
        logps = model.forward(inputs)
        loss = criterion(logps, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        if steps % print_every == 0:
            test_loss = 0
            accuracy = 0
            model.eval()
            with torch.no_grad():
                for inputs, labels in testloader:
                    inputs, labels = inputs.to(device), labels.to(device)
                    logps = model.forward(inputs)
                    batch_loss = criterion(logps, labels)
                    test_loss += batch_loss.item()

                    ps = torch.exp(logps)
                    top_p, top_class = ps.topk(1, dim=1)
                    equals = top_class == labels.view(*top_class.shape)
                    accuracy += torch.mean(equals.type(torch.FloatTensor)).item()
            train_losses.append(running_loss / len(trainloader))
            test_losses.append(test_loss / len(testloader))
            print(f"Epoch {epoch + 1}/{epochs}.. "
                  f"Train loss: {running_loss / print_every:.3f}.. "
                  f"Test loss: {test_loss / len(testloader):.3f}.. "
                  f"Test accuracy: {accuracy / len(testloader):.3f}")
            running_loss = 0
            model.train()
torch.save(model, 'EyeDetector.pth')




E mais algumas linhas para salvar o modelo no ONNX:



Texto oculto
from torchvision import transforms
import torch
from PIL import Image

use_cuda=1
mobilenet = torch.load("EyeDetector.pth")
mobilenet.classifier = mobilenet.classifier[:-1]
mobilenet.cuda()
img = Image.open('E:/OpenProject/OpenVinoTest/face_detect/EyeDataset/krnwapzu_left.jpg')
mobilenet.eval()
transform = transforms.Compose([transforms.Resize(64),
                                      transforms.ToTensor(),
                                      ])

img = transform(img)
img = torch.unsqueeze(img, 0)
if use_cuda:
    img = img.cuda()
img = torch.autograd.Variable(img)
list_features = mobilenet(img)

ps = torch.exp(list_features.data.cpu())
top_p, top_class = ps.topk(1, dim=1)

list_features_numpy = []
for feature in list_features:
    list_features_numpy.append(feature.data.cpu().numpy())
mobilenet.cpu()
x = torch.randn(1, 3, 64, 64, requires_grad=True)
torch_out = mobilenet(x)

torch.onnx.export(mobilenet, x,"mobilnet.onnx", export_params=True, opset_version=10, do_constant_folding=True,
input_names = ['input'],output_names = ['output'])
print(list_features_numpy)




Salvar o modelo no ONNX é necessário para continuar a chamar o modelo no Open Vino. Não me preocupei em converter para int8, deixei o modelo como estava no formato de 32 bits.



Análise de precisão, métricas de qualidade? .. Por que é um projeto amador. Essas coisas têm preços diferentes. Nenhuma métrica dirá a você “o sistema funciona”. Quer o sistema funcione ou não, você só entenderá na prática. Mesmo 1% dos erros pode tornar o sistema desagradável de usar. Acontece que eu sou o oposto. Como erros de 20%, mas o sistema está configurado de forma que eles não sejam visíveis.



Essas coisas são mais fáceis de ver na prática, "vai funcionar ou não". E já tendo entendido o critério de trabalho - inserir métricas, se necessário.



Problemas da versão 2



A implementação atual é qualitativamente diferente, mas ainda tem uma série de problemas:



  • . , :

    • - ⅓ .


  • . . , , . , .
  • . ?


?



Não retreinei a detecção de rosto. Ao contrário do reconhecimento de olho, isso dá muito mais trabalho. E com a coleta de um conjunto de dados e com treinamento de qualidade.



Claro, você pode fazer isso na cara do seu filho, provavelmente até um pouco melhor funcionará do que a rede atual. Mas para o resto do povo, não. E, talvez, para meu filho em 2 meses - também não.

A coleta de um conjunto de dados normal leva muito tempo.



Som



Seria possível seguir o caminho clássico de reconhecimento de som e treinar o neurônio. Em geral, não seria muito longo, no máximo várias vezes mais longo do que o reconhecimento visual. Mas eu não queria mexer na coleta do conjunto de dados, então usei uma maneira mais fácil. Você pode usar ferramentas WebRTC prontas . Tudo acaba sendo elegante e simples, em algumas linhas.



A desvantagem que descobri é que a qualidade da solução é diferente em microfones diferentes. Em algum lugar disparou com um guincho, e em algum lugar apenas com um grito alto.



Vá em frente, o que mais



Em algum momento, conduzi um teste rodando um vídeo em loop de 5 segundos de mim mesmo com minha esposa: Ficou







claro que o filho estava grudando nos rostos das pessoas no campo de visão (o monitor o pendurou por 30 minutos). E nasceu a ideia: fazer o controle da expressão facial. Este não é apenas um vídeo estático, mas uma opção de interação. Aconteceu algo assim (quando a emoção do filho muda, a sequência do vídeo muda):





“Pai, você está fodendo?!”



Provavelmente deveria tentar com um monitor grande. Mas ainda não estou pronto.



Talvez você precise substituir o vídeo que está sendo reproduzido. Felizmente, é simples - o vídeo é reproduzido a partir de imagens separadas, onde a mudança de quadro é ajustada para FPS.



Talvez você precise esperar (no nível atual, a criança pode simplesmente não entender a conexão entre suas emoções e a tela)



E depois?



Uma das direções mais promissoras, me parece, é tentar fazer o controle de alguns objetos / luzes / motores físicos através da direção de visão / pose.



Mas até agora não pensei profundamente sobre este assunto. Em vez disso, por enquanto, testarei o gerenciamento de emoções.



Como fica no final, descrição, pensamentos



Como tudo funciona agora (há um vídeo maior no início do artigo):



  • Todo o controle passa pelo Telegramm + pela câmera.
  • Se você não precisa controlar o vídeo com emoções, todo o dispositivo se parece com isto:





  • Ele é iniciado ligando o banco de energia.
  • Se houver uma rede conectada, o dispositivo já está pronto para uso
  • Se não houver rede, então você precisa mostrar o código QR com a rede, o sistema irá iniciar automaticamente
  • Por meio do Telegramm, você pode selecionar um conjunto de eventos para monitorar:





  • Cada vez que ocorre um evento interessante, uma notificação é enviada:





  • A qualquer momento, você pode solicitar uma foto do dispositivo para ver o que está acontecendo



Em geral, comentários de um ente querido:



  1. O detector facial não funciona muito bem. Esta é realmente uma característica de qualquer detector que não seja ajustado para crianças. Normalmente, isso não interfere na detecção de despertar (pelo menos algumas fotos normais com os olhos abertos virão). Não há planos de retreinar agora.
  2. Sem tela, um lançamento ligeiramente opaco (se o código QR foi lido ou não). E há muitos fios com a tela. Acho que a opção mais correta seria colocar diodos no GPIO. E acendê-los dependendo do estado (há conexão, a câmera não funciona, Movidius não funciona, não há conexão com o telegrama, etc.). Mas ainda não feito
  3. Às vezes é difícil proteger a câmera. Como tenho um par de tripés, posso me controlar de alguma forma. E sem eles, talvez, nada teria funcionado.
  4. Realmente permite que você libere algum tempo e dê liberdade de movimento. É mais do que um monitor de bebê / monitor de vídeo normal com streaming? Eu não sei. Talvez um pouco mais fácil.
  5. Coisas legais para experimentar.


Como lançar



Como eu disse acima - tentei estabelecer todas as fontes. O projeto é grande e ramificado, então talvez eu tenha esquecido algo ou não tenha fornecido ferramentas detalhadas. Sinta-se à vontade para perguntar e esclarecer.



Existem várias maneiras de expandir tudo:



  1. Sors do github. Esse é um método mais complicado, vai demorar muito para configurar o RPi, talvez eu tenha esquecido de algo. Mas você tem controle total sobre o processo (incluindo as configurações RPi).
  2. Use uma imagem pronta. Aqui podemos dizer que é sem graça e inseguro. Mas é muito mais fácil.


Github



O repositório principal está localizado aqui - github.com/ZlodeiBaal/BabyFaceAnalizer

Ele consiste em dois arquivos que você precisa para executar:



  1. O script para inicializar / verificação do status / configuração da rede é QRCode.py (para este script, lembre-se, há uma mais detalhada descrição ). Ele conecta o WiFi e verifica se há configurações para o bot no Telegram.
  2. O principal script de trabalho é face.py


Além disso. há duas coisas faltando no Git:



  1. Arquivo de credenciais de WiFi - wpa_supplicant_auto.conf
  2. Arquivo com credenciais do Telegram-bot - tg_creedential.txt


Você pode permitir que o sistema os crie automaticamente na próxima inicialização. Você pode usar o seguinte preenchendo os campos em branco:



tg_creedential.txt
token to access the HTTP API — , @BotFather telegram "/newbot"

socks5://… — ,

socks5 — ,

socks5 — ,



wpa_supplicant_auto.conf
network={

ssid="******"

psk="*******"

proto=RSN

key_mgmt=WPA-PSK

pairwise=CCMP

auth_alg=OPEN

}



RPi afinando assobios e falsificações



Infelizmente, apenas colocar e executar scripts no RPi não funcionará. Aqui está o que mais você precisa para um trabalho estável:



  1. Instale l_openvino_toolkit_runtime_raspbian_p_2020.1.023.tgz de acordo com as instruções - docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_raspbian.html
  2. Instalar autorun
  3. Exclua a mensagem sobre a senha padrão (talvez não seja necessário, mas me incomodou) - sudo apt purge libpam-chksshpwd
  4. desligar protetor de tela - www.raspberrypi.org/forums/viewtopic.php?t=260355
  5. Para detecção de áudio:



    • pip3 install webrtcvad
    • sudo apt-get install python-dev
    • sudo apt-get install portaudio19-dev
    • sudo pip3 install pyaudio
  6. Baixe modelos do repositório OpenVino usando o script “Get_models.py” na pasta “Modelos”


Formato



A imagem está postada aqui (5 shows).



Alguns pontos:



  1. A senha de login padrão é usada (pi, framboesa)
  2. Acesso SSH ativado
  3. Por padrão, o WiFi não está conectado e o endereço do bot no carrinho que o sistema usará para monitoramento não está configurado.


Como configurar o WiFi em uma imagem



A primeira opção é mostrar o código QR com o texto após o lançamento:



WIFI:T:WPA;P:qwerty123456;S:TestNet;;


Onde depois de P é a senha de rede, depois de S é o identificador de rede.



  1. Se você tem um telefone com Android 10, esse código QR é gerado automaticamente quando você clica em "compartilhar rede"
  2. Caso contrário, você pode gerá-lo em www.the-qrcode-generator.com


A segunda opção é fazer o SSH no RPi (conectando pelo fio). Ou ligue o monitor e o teclado. E colocar o arquivo



wpa_supplicant_auto.conf
network={

ssid="*********"

psk="*******"

proto=RSN

key_mgmt=WPA-PSK

pairwise=CCMP

auth_alg=OPEN

}



com suas configurações de wi-fi para a pasta "/ home / pi / face_detect".



Como configurar um bot de telegrama em uma imagem



A primeira opção é mostrar o código QR com o texto após o lançamento:



tg_creedential.txt
token to access the HTTP API — , @BotFather telegram "/newbot"

socks5://… — ,

socks5 — ,

socks5 — ,



gerando-o via www.the-qrcode-generator.com A

segunda opção é fazer SSH no RPi (conectando via fio). Ou ligue o monitor e o teclado. E coloque o arquivo tg_creedential.txt descrito acima na pasta "/ home / pi / face_detect".



Comentário sobre a infância



Já quando coletei a primeira versão e mostrei para minha mãe, recebi uma resposta repentina:

“Ah, e nós fizemos quase o mesmo na sua infância”.

"?!"

“Bem, eles colocaram o carrinho com você na varanda, jogaram o microfone pela janela, que estava incluído no amplificador do apartamento.”


Em geral, de repente descobriu-se que é hereditário.



Comentário sobre o cônjuge



"Como sua esposa reagiu?"

"Como ela deixou você experimentar em seu filho?!"

Eles perguntaram mais de uma vez.

Mas, eu arruinei minha esposa também. Aqui, ela até escreve artigos sobre Habré às vezes.



PS1



Não sou um especialista em segurança da informação. Claro, tentei ter certeza de que nenhuma senha seria mostrada em qualquer lugar, etc., e todos pudessem configurar por si mesmos, indicando todas as informações de segurança após o início.



Mas não excluo que perdi algo em algum lugar. Se você vir erros óbvios, tentarei corrigi-los.



PS2



Muito provavelmente, irei falar sobre atualizações para este projeto em meu canal de telegrama , ou no grupo VKontakte . Se eu acumular muitas coisas interessantes, farei outra publicação aqui.



All Articles