Niñera RPi

De vez en cuando me siento tentado a hacer algo extraño. Evidentemente una cosa inútil que no se justifica en cuanto al monto de la inversión, y seis meses después de su creación, acumula polvo en la estantería. Pero, por otro lado, se justifica plenamente en términos de la cantidad de emociones, la experiencia adquirida y las nuevas historias. Incluso hay dos de mis artículos sobre Habré sobre tales experimentos: Alcoorgan y un comedero inteligente para pájaros .



Bien. Es hora de hablar de un nuevo experimento. Cómo lo recogió, qué salió de él y cómo repetirlo.







Un evento me impulsó a un nuevo proyecto, en cierto sentido, banal: nació un hijo. Arreglé las vacaciones de un mes por adelantado. Pero el niño resultó estar tranquilo, había tiempo libre. Y pon el durmiente a su lado.



Muchas casas diferenteshardware integrado para visión artificial. Como resultado, decidí hacer una niñera de video. Pero no tan aburrido como están llenas todas las tiendas. Y algo más inteligente e interesante.



El artículo se escribirá de manera narrativa para comprender cómo fue el desarrollo del juguete, hacia dónde llegó y hacia dónde se dirige a continuación.



El artículo tiene varias adiciones:



  1. Video donde muestro y cuento como funciona todo.
  2. Un pequeño artículo sobre VC, donde le digo por qué es muy probable que tales cosas no lleguen a la producción normal y sobre las limitaciones de los sistemas de ML de este tipo.
  3. Tipos de todo en github + imagen preparada para RPi. Al final del artículo, una descripción de cómo usarlo.


Elegir una idea



La funcionalidad más común de un monitor para bebés es ver lo que le sucede al niño en cualquier momento. Desafortunadamente, esto no siempre funciona. No verá la transmisión todo el tiempo, no es conveniente. Por lo general, se puede poner al bebé a dormir cerca en un capullo, ¿por qué grabar videos todo el tiempo? Como resultado, para empezar, se armó la siguiente colección:



  1. El sistema debe permitir ver un video o una foto en cualquier momento desde el teléfono.
  2. El sistema debe responder al despertar del niño y notificarlo
  3. El sistema debe detectar la cara faltante para prevenir SMSL


Selección de plataforma



Tenía un artículo extenso sobre Habré sobre la comparación de diferentes plataformas. Globalmente, para un prototipo como el que estoy haciendo, hay varias opciones:



  1. Jetson Nano. + ( Nano), , . . — TensorRT. . , , , TensorRT .
  2. VIM3. , . — .
  3. Raspberry PI + Movidius. . , , .
    1. , .
    2. . .
  4. Raspberry PI 4: cuando se trabaja a través de OpenCV, será bueno deshacerse de las redes abiertas, lo que debería ser suficiente. Pero, existía la sospecha de que no habrá suficiente rendimiento.
  5. Coral: lo tengo en mis manos, pasaría en términos de rendimiento, pero mi otro artículo dice por qué no me gusta :)


Entonces, elegí Rpi + movidius. Lo tengo a mano, puedo trabajar con él.



Planchar



La computadora es Raspberry Pi 3B, el neuroprocesador es Movidius Myriad X. Esto está claro.

El resto - raspado a lo largo de la parte inferior del barril, comprado además.







Cámara



Revisé tres diferentes que tenía:



  • Cámara de RaspberryPI. Cable ruidoso e inconveniente, sin conexión conveniente. Anotado.
  • Algún tipo de cámara IP. Muy útil porque no es necesario incluirlo en el RPI. La cámara está separada de la computadora. Mi celular incluso tenía dos modos, día y noche. Pero el que tenía no daba suficiente calidad de cara.
  • Cámara web de Genius. Lo he estado usando durante unos 5 años, pero algo se ha vuelto inestable últimamente, pero para RPI, está bien. Además, resultó que se puede desmontar trivialmente y quitar el filtro de infrarrojos de allí. Además, como resultó más tarde, esta era la única opción con un micrófono.






Y el filtro cambia así:







en general, está claro que esta no es una solución de producto. Pero funciona.



En todo caso, en el código verá las piezas restantes para cambiar a los otros dos tipos de cámaras. Quizás incluso algo funcione completamente si cambia 1-2 parámetros.



Encendiendo



Tenía un iluminador por ahí con uno de los viejos problemas.



Le soldé algún tipo de fuente de alimentación. Brilla bien.







Apunta hacia el techo: la habitación está iluminada.







Pantalla



Para algunos modos de funcionamiento, necesitaba un monitor. Paré en esto . Aunque no estoy seguro de si esta es la decisión correcta. Quizás debería haber tomado el de larga duración. Pero más sobre eso más adelante.







Nutrición



El niño duerme en lugares arbitrarios. Así que es más fácil cuando el sistema está alimentado por un banco de energía. Elegí este, simplemente porque se encuentra en casa para hacer senderismo:







OpenVino



Analicemos un poco OpenVino. Como dije anteriormente, una gran ventaja de OpenVino es la gran cantidad de redes pre-entrenadas. Lo que nos puede resultar útil.



Detección de rostro. Hay muchas redes de este tipo en OpenVino:



  1. 1
  2. 2
  3. 3


Reconocimiento de puntos clave en el rostro . Necesitamos esto para lanzar las siguientes redes de

orientación facial . Actividad del niño y hacia dónde mira.

Reconocimiento de la dirección del ojo : si intenta interactuar ¿

Análisis de profundidad ? Tal vez resulte

Análisis de esqueleto

Bueno, muchos otros interesantes ...



La principal desventaja de estas redes será su principal ventaja - su pre-entrenamiento ...



Esto se puede corregir, pero ahora estamos haciendo un prototipo rápido, nuestro objetivo no es trabajar en el 100% de los casos, sino trabajar en principio que traerá al menos algún beneficio.



Vamos. Versión lógica general 1



Dado que estamos desarrollando un dispositivo integrado, necesitamos interactuar de alguna manera con él. Recibe fotos / señales de alarma. Entonces decidí hacer lo mismo que cuando hice el comedero , vía telegramas. Pero recuerda.



Para la primera versión, decidí:



  • Inicie las redes designadas en RPi (me gustaría todo a la vez, de repente el rendimiento lo permitirá). Esto le permitirá ver más opciones para resolver el problema / formas probables de desarrollo.
  • Escribe una plantilla de programa general.
  • Crea un algoritmo que reconozca el despertar.
  • Hacer un algoritmo que envíe una notificación sobre la pérdida de la cara


Todo salió más o menos bien, salvo un montón de errores por todas partes. Esto es inherente a ComputerVision ... estoy acostumbrado.



Aquí hay un resumen rápido de lo que encontré:



  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…


Pero, así es como ... Estoy seguro de que si pasaba por TensorRT, habría más problemas, como siempre.



Entonces. Todo se junta, las redes están funcionando, obtenemos algo como esto (pasando la pila por la cabeza, orientación, puntos clave):







Se puede ver que la cara a menudo se pierde cuando el niño la cubre con las manos / gira la cabeza. y no todos los indicadores son estables.



¿Que sigue? ¿Cómo analizar el quedarse dormido?



Miro esas rejillas que son, y lo primero que me viene a la mente es reconocer las emociones. Cuando el niño está dormido y tranquilo, hay una expresión neutra en su rostro. Pero no es tan simple. Aquí hay un gráfico azul oscuro, esta es una expresión neutra de un niño dormido durante una hora:







El resto de los gráficos son triste / enojado / alegría / sorpresa. Ni siquiera realmente la esencia de lo que está en los colores. Desafortunadamente, los datos de la red son inestables, que es lo que vemos. La inestabilidad ocurre cuando:



  • Sombra excesiva en la cara (que no es infrecuente por la noche)
  • Las caras del niño no estaban en el conjunto de entrenamiento de OpenVino => cambio arbitrario a otras emociones
  • El niño hace muecas, incluso en un sueño.


En general, no me sorprendió. Me he encontrado con redes que reconocen las emociones antes y siempre son inestables, incluso debido a la inestabilidad de la transición entre emociones: no hay una frontera clara.



Ok, el despertar no se puede reconocer con la ayuda de las emociones. Hasta ahora, no quería enseñar algo yo mismo, así que decidí intentarlo sobre la base de las mismas redes, pero del otro lado. Una de las redes da el ángulo de rotación de la cabeza. Esto ya es mejor (desviación total de mirar a la cámara en el tiempo en grados). Últimos 5-10 minutos antes de despertar:







mejor. Pero ... El hijo puede comenzar a mover la cabeza mientras duerme. O viceversa, si establece un umbral grande, levántese y no mueva la cabeza después de eso. Para recibir una notificación cada vez ... Lamentablemente:





(hay aproximadamente una hora de tiempo de sueño)



Por lo que todavía necesitamos hacer un reconocimiento normal.



Problemas encontrados en la versión 1



Resumamos todo lo que no me gustó de la primera versión.



  1. Autoencendido. No es conveniente volver a iniciar este juguete cada vez, conectarse a través de SSH, ejecutar el script de monitoreo. En este caso, el script debería:

    • Verifique el estado de la cámara. Sucede que la cámara está apagada / no enchufada. El sistema debe esperar a que el usuario encienda la cámara.
    • Comprobando el estado del acelerador. Lo mismo que con la cámara.
    • Comprobando la red. Quiero usarlo tanto en casa como en el campo. O tal vez en otro lugar. Y de nuevo, no quiero iniciar sesión a través de ssh => Necesito crear un algoritmo para conectarme a wiFi si no hay Internet.
  2. Despertar, entrenamiento en red. No han aparecido enfoques simples, lo que significa que es necesario entrenar a la neurona para que reconozca los ojos abiertos.


Autoencendido



En general, el esquema de ejecución automática es el siguiente:



  • Lanzo mi programa al principio. Cómo lo hago: escribí un artículo aparte, por no decir que es trivial hacerlo en RPi. En breve:

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




No existe una red de reconocimiento ocular lista para usar en OpenVino.

Jajaja. La red ya apareció. Pero resultó que se lanzó solo después de que comencé a desarrollar. Y en el lanzamiento y la documentación, ya apareció cuando más o menos hice todo. Ahora estaba escribiendo un artículo y encontré una actualización .

Pero no lo volveré a hacer, así que escribo como lo hice.



Es muy fácil entrenar una red de este tipo. Arriba, dije que usé la selección de los ojos por fotograma. No queda nada: agregue el ahorro de todas las miradas que se encontraron en el marco. Resulta un conjunto de datos de este tipo:







queda marcarlo y entrenarlo. Describí el proceso de marcado con más detalle aquí (y un video del proceso durante 10 minutos aquí). Toloka se utilizó para marcar. Se necesitaron aproximadamente 2 horas para configurar la tarea, 5 minutos para marcar + 300 rublos del presupuesto.



Cuando aprendí, no quería pensar demasiado, así que tomé una red deliberadamente rápida, que tiene la calidad suficiente para resolver el problema: mobilenetv2. El código completo, incluida la carga del conjunto de datos, la inicialización y el guardado, tomó menos de 100 líneas (en su mayoría tomadas de fuentes abiertas, reescribió un par de docenas de líneas):



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')




Y un par de líneas más para guardar el modelo en 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)




Guardar el modelo en ONNX es necesario para seguir llamando al modelo en Open Vino. No me molesté en convertir a int8, dejé el modelo tal como estaba en formato de 32 bits.



Análisis de precisión, métricas de calidad ... ¿Por qué es en un proyecto amateur? Tales cosas tienen un precio diferente. Ninguna métrica le dirá "el sistema funciona". Si el sistema funciona o no, solo lo entenderá en la práctica. Incluso el 1% de los errores pueden hacer que el sistema sea desagradable de usar. Sucede que soy todo lo contrario. Como errores del 20%, pero el sistema está configurado para que no sean visibles.



Estas cosas son más fáciles de ver en la práctica, “funcionará o no”. Y habiendo entendido ya el criterio del trabajo: ingresar métricas, si son necesarias.



Problemas de la versión 2



La implementación actual es cualitativamente diferente, pero aún presenta una serie de problemas:



  • . , :

    • - ⅓ .


  • . . , , . , .
  • . ?


?



No volví a entrenar la detección de rostros. A diferencia del reconocimiento ocular, esto supone mucho más trabajo. Y con la recopilación de un conjunto de datos y con una formación de calidad.



Por supuesto, puede hacerlo en la cara de su hijo, probablemente funcionará incluso un poco mejor que la red actual. Pero para el resto de la gente, no. Y, quizás, para mi hijo en 2 meses, tampoco.

La recopilación de un conjunto de datos normal lleva mucho tiempo.



Sonido



Sería posible seguir el camino clásico del reconocimiento de sonido y entrenar la neurona. En general, no sería muy largo, como máximo varias veces más que el reconocimiento ocular. Pero no quería molestarme en recopilar el conjunto de datos, así que utilicé una forma más fácil. Puede utilizar herramientas WebRTC listas para usar . Todo resulta elegante y sencillo, en un par de líneas.



El inconveniente que encontré es que la calidad de la solución es diferente en diferentes micrófonos. En algún lugar se disparó con un chillido, y en algún lugar solo con un fuerte grito.



Adelante, que mas



En algún momento, realicé una prueba con un video en bucle de 5 segundos de mí mismo con mi esposa:







estaba claro que el hijo se pegaba a las caras de las personas en el campo de visión (el monitor lo colgó durante 30 minutos). Y nació la idea: hacer que el control de la expresión facial. Este no es solo un video estático, sino una opción de interacción. Resultó algo como esto (cuando la emoción del hijo cambia, la secuencia del video cambia):





"Papá, ¿estás jodiendo?"



Probablemente debería intentarlo con un monitor grande. Pero todavía no estoy listo.



Tal vez necesite reemplazar el video que se está reproduciendo. Afortunadamente, es simple: el video se reproduce desde imágenes separadas, donde el cambio de cuadro se ajusta al FPS.



Tal vez deba esperar (en el nivel actual, es posible que el niño simplemente no comprenda la conexión entre sus emociones y la pantalla)



¿Y entonces?



Una de las direcciones más prometedoras, me parece, es tratar de controlar algunos objetos físicos / luces / motores a través de la dirección de la vista / pose.



Pero hasta ahora no he reflexionado mucho sobre este tema. Más bien, por ahora, probaré el manejo de las emociones.



Cómo se ve al final, descripción, pensamientos.



Cómo funciona todo ahora (hay un video más grande al comienzo del artículo):



  • Todo el control pasa por Telegramm + a través de la cámara.
  • Si no necesita controlar el video con emociones, entonces todo el dispositivo se ve así:





  • Se inicia encendiendo la energía en el banco de energía.
  • Si hay una red conectada, entonces el dispositivo ya está listo para usarse
  • Si no hay red, debe mostrar el código QR con la red, el sistema se iniciará automáticamente
  • A través de Telegramm, puede seleccionar un conjunto de eventos para monitorear:





  • Cada vez que ocurre un evento interesante, se envía una notificación:





  • En cualquier momento, puede solicitar una foto desde el dispositivo para ver qué está sucediendo



En general, las reseñas de un ser querido:



  1. El detector facial no funciona muy bien. Esta es realmente una característica de cualquier detector que no esté sintonizado para niños. Por lo general, esto no interfiere con la detección del despertar (vendrán al menos un par de fotos normales con los ojos abiertos). No hay planes de reentrenamiento ahora.
  2. Sin pantalla, un lanzamiento ligeramente opaco (se haya leído o no el código QR). Y hay muchos cables con la pantalla. Creo que la opción más correcta sería poner diodos en GPIO. Y enciéndalos según el estado (hay conexión, la cámara no funciona, Movidius no funciona, no hay conexión con el telegrama, etc.). Pero aun no hecho
  3. A veces es difícil asegurar la cámara. Como tengo un par de trípodes, puedo arreglármelas de alguna manera. Y sin ellos, tal vez, nada hubiera funcionado.
  4. Realmente te permite liberar algo de tiempo y dar libertad de movimiento. ¿Más que un vigilabebés de streaming normal? Yo no sé. Quizás un poco más fácil.
  5. Cosas geniales para experimentos.


Cómo lanzar



Como dije anteriormente, traté de presentar todas las fuentes. El proyecto es grande y ramificado, así que tal vez olvidé algo o no di las herramientas detalladas. No dude en preguntar y aclarar.



Hay varias formas de expandirlo todo:



  1. Sors de github. Este es un método más complicado, tomará mucho tiempo configurar el RPi, tal vez olvidé algo. Pero tienes un control total sobre el proceso (incluida la configuración de RPi).
  2. Utilice una imagen ya hecha. Aquí podemos decir que no tiene gracia y es inseguro. Pero es mucho más fácil.


Github



El repositorio principal se encuentra aquí: github.com/ZlodeiBaal/BabyFaceAnalizer

Consta de dos archivos que debe ejecutar:



  1. El script para inicializar / verificar el estado / configuración de la red es QRCode.py (para este script, recuerde, hay una descripción más detallada ). Conecta WiFi y comprueba que haya configuraciones para el bot en Telegram.
  2. El guión de trabajo principal es face.py


Además. faltan dos cosas en Git:



  1. Archivo de credenciales WiFi - wpa_supplicant_auto.conf
  2. Archivo con credenciales de Telegram-bot - tg_creedential.txt


Puede dejar que el sistema los cree automáticamente en el próximo inicio. Puede utilizar lo siguiente completando los campos en blanco:



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 tuning silbidos y falsificaciones



Desafortunadamente, simplemente poner y ejecutar scripts en RPi no funcionará. Esto es lo que necesita para un trabajo estable:



  1. Instale l_openvino_toolkit_runtime_raspbian_p_2020.1.023.tgz de acuerdo con las instrucciones: docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_raspbian.html
  2. Instalar ejecución automática
  3. Eliminar el mensaje sobre la contraseña predeterminada (tal vez no sea necesario, pero me molestó) - sudo apt purge libpam-chksshpwd
  4. apagar el protector de pantalla - www.raspberrypi.org/forums/viewtopic.php?t=260355
  5. Para detección de audio:



    • pip3 instalar webrtcvad
    • sudo apt-get install python-dev
    • sudo apt-get install portaudio19-dev
    • sudo pip3 instalar pyaudio
  6. Descargue los modelos del repositorio de OpenVino utilizando el script "Get_models.py" en la carpeta "Modelos"


Formar



La imagen está publicada aquí (5 conciertos).



Un par de puntos:



  1. Se utiliza la contraseña de inicio de sesión estándar (pi, frambuesa)
  2. Acceso SSH habilitado
  3. Por defecto, WiFi no está conectado y la dirección del bot en el carrito que el sistema usará para monitorear no está configurada.


Cómo configurar WiFi en una imagen



La primera opción es mostrar el código QR con el texto después del lanzamiento:



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


Donde después de P es la contraseña de red, después de S es el identificador de red.



  1. Si tiene un teléfono con Android 10, dicho código QR se genera automáticamente cuando hace clic en "compartir red"
  2. Si no, puede generarlo en www.the-qrcode-generator.com


La segunda opción es SSH en el RPi (conectándolo a través del cable). O encienda el monitor y el teclado. Y pon el archivo



wpa_supplicant_auto.conf
network={

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

psk="*******"

proto=RSN

key_mgmt=WPA-PSK

pairwise=CCMP

auth_alg=OPEN

}



con su configuración de wi-fi a la carpeta "/ home / pi / face_detect".



Cómo configurar un bot de telegram en una imagen



La primera opción es mostrar el código QR con el texto después del lanzamiento:



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

socks5://… — ,

socks5 — ,

socks5 — ,



generándolo a través de www.the-qrcode-generator.com La

segunda opción es SSH en el RPi (conectado por cable). O encienda el monitor y el teclado. Y coloque el archivo tg_creedential.txt descrito anteriormente en la carpeta "/ home / pi / face_detect".



Comentario sobre la infancia



Ya cuando recogí la primera versión y se la mostré a mi madre, recibí una respuesta repentina:

"Ah, e hicimos casi lo mismo en tu infancia".

"?!"

"Bueno, te pusieron la carriola en el balcón, tiraron un micrófono por la ventana, que estaba incluido en el amplificador del departamento".


En general, de repente resultó que es hereditario.



Observación sobre el cónyuge



"¿Cómo reaccionó su esposa?"

"¿Y cómo te dejó experimentar con tu hijo?"

Preguntaron más de una vez.

Pero, arruiné bien a mi esposa. Aquí, ella incluso escribe artículos sobre Habré veces.



PS1



No soy un especialista en seguridad de la información. Por supuesto, traté de asegurarme de que no se mostraran contraseñas en ningún lugar, etc., y que todos pudieran configurarse por sí mismos, indicando toda la información de seguridad después del inicio.



Pero no excluyo que me perdí algo en alguna parte. Si ve errores obvios, intentaré solucionarlo.



PS2



Lo más probable es que hable sobre las actualizaciones de este proyecto en mi canal de telegramas o en el grupo VKontakte . Si acumulo muchas cosas interesantes, haré otra publicación aquí.



All Articles