[LINUX] Un mémo qui détecte le visage de l'image acquise à partir de la caméra Web avec OpenCV de Django et le renvoie.

Contexte

Je souhaite détecter des visages à partir d'images (vidéos) prises avec une caméra Web, avec React et Django

image.png Lorsque vous tenez l'appareil photo, le visage sort de l'endroit où vous le tenez Cela peut être utile pour quelque chose de sécurité

méthodologie

Dernière fois La pièce déposée est remplacée par la caméra Web Pour cette raison, certains paramètres de sécurité sont nécessaires. image.png

la mise en oeuvre

React

Dernière fois n'est pas différent J'ai ajouté le processus pour accéder à la caméra avec le constructeur Obtenir une image de la caméra? GetCameraImage est coupé Légèrement modifié le processus de réception de submitData

create-react-app user

index.js


import React from "react";
import ReactDOM from "react-dom";

const SERVER = "https://192.168.139.140:8000/image/"; //Poste de serveur

class App extends React.Component {
  /**
   * @param {json} props
   */
  constructor(props) {
    super(props);

    const canvas = document.createElement("canvas");
    const context = canvas.getContext("2d");
    this.state = {
      video: document.createElement("video"),
      canvas: canvas,
      context: context
    };
    if (navigator.mediaDevices){
      navigator.mediaDevices
        .getUserMedia({ video: true, audio: false })
        .then((stream) => {
          this.state.video.srcObject = stream;
          this.state.video.play();
          this.state.video.onloadedmetadata = (e) => {
            this.setState({width: this.state.video.videoWidth, height: this.state.video.videoHeight})
            this.state.canvas.width = this.state.width;
            this.state.canvas.height = this.state.height;
            this.submitData();
          };
        })
        .catch(function (error) {
          console.error(error);
          return;
        });
      }
  }

  /**
   *Obtenir des jetons CSRF à partir des cookies
   */
  getCSRFtoken() {
    for (const c of document.cookie.split(";")) {
      const cArray = c.split("=");
      if (cArray[0] === "csrftoken") return cArray[1];
    }
  }

  /**
   *Obtenez une image de la caméra et convertissez-la en une chaîne de caractères pour l'envoi et la réception
   * @return {str} base64
   */
  getCameraImage() {
    this.state.context.drawImage(
      this.state.video,
      0,
      0,
      this.state.width,
      this.state.height
    );
    return this.state.canvas.toDataURL();
  }

  /**
   *Envoyer des données au serveur
   */
  submitData() {
    this.setState({ image: this.getCameraImage() });
    this.render();
    // console.log("Envoyer", this.state);
    fetch(SERVER + "res/", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-CSRFToken": this.getCSRFtoken()
      },
      body: JSON.stringify({
        image: this.state.image //← Envoyer l'image
      })
    })
      .then((res) => res.json())
      .then((res) => {
        console.log("Recevoir", res);
        this.setState({ image: res.image, message: res.message }); //← Définir l'image
        this.render();
        setTimeout(() => this.submitData(), 1000); //Envoyer après 1 seconde
      });
  }

  /**
   *Bouton et envoyer / recevoir le rendu des données
   */
  render() {
    return (
      <div>
        <div className="image-element">
          {this.state.image ? <img src={this.state.image} alt="image" /> : ""}
        </div>
      </div>
    );
  }
}

ReactDOM.render(
  <React.StrictMode>
    <App message={"Image"} />
  </React.StrictMode>,
  document.getElementById("root")
);

Processus pour accéder à la webcam

Copiez et collez du JS que j'ai écrit il y a presque longtemps

index.js


  constructor(props) {
    super(props);

    const canvas = document.createElement("canvas");
    const context = canvas.getContext("2d");
    this.state = { //Définir des éléments de canevas (pour le dessin d'image) et vidéo (pour la vidéo)
      video: document.createElement("video"),
      canvas: canvas,
      context: context
    };
    if (navigator.mediaDevices){
      navigator.mediaDevices
        .getUserMedia({ video: true, audio: false })
        .then((stream) => {
          this.state.video.srcObject = stream; //Obtenez la vidéo de la caméra et mettez-la dans l'élément vidéo
          this.state.video.play(); //Régénération(?)
          this.state.video.onloadedmetadata = (e) => { //Une fois que les métadonnées peuvent être chargées
            this.setState({width: this.state.video.videoWidth, height: this.state.video.videoHeight}) //Kit d'acquisition de taille
            this.state.canvas.width = this.state.width; //Spécifiez la taille du canevas
            this.state.canvas.height = this.state.height;
            this.submitData(); //Envoyer au serveur
          };
        })
        .catch(function (error) {
          console.error(error);
          return;
        });
      }
  }

Si c'est lié à la vidéo, à la vidéo, aux métadonnées téléchargées ou à quelque chose qui sent la merde Je souffrais à mort en créant une application de visionnage de vidéos Si vous ne confirmez pas le chargement des métadonnées par ce processus, videoWidth etc. ne sera pas défini pour la vidéo Étonnamment, je suis toujours confus quant aux spécifications de taille ici la vidéo est video.videoWidth et canvas est canvas.width

Il semble y avoir attendre ces jours-ci

Fonction pour obtenir une image de la caméra

C'est aussi le même que celui que j'ai fait il y a longtemps

index.js


  getCameraImage() {
    this.state.context.drawImage(this.state.video, 0, 0, this.state.width, this.state.height);
    return this.state.canvas.toDataURL();
  }

Je pense que j'ai pu réduire de moitié la taille horizontale en faisant `` this.state.width / 2 '' (rappelez-vous) Ça n'avait pas de sens de le couper ici

Envoyer et recevoir

Je voulais vérifier l'image de réponse, j'ai donc effectué la transmission suivante 1 seconde après avoir dessiné l'image de détection de visage.

index.js


  submitData() {
    this.setState({ image: this.getCameraImage() });
    this.render();
    // console.log("Envoyer", this.state);
    fetch(SERVER + "res/", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-CSRFToken": this.getCSRFtoken()
      },
      body: JSON.stringify({
        image: this.state.image //← Envoyer l'image
      })
    })
      .then((res) => res.json())
      .then((res) => {
        console.log("Recevoir", res);
        this.setState({ image: res.image, message: res.message }); //← Définir l'image
        this.render();
        setTimeout(() => this.submitData(), 1000); //Envoyer après 1 seconde
      });
  }

J'ai pensé à envoyer en appuyant sur un bouton, mais je viens de rendre le bouton et de poster l'événement.

Construire

Construisez ceci et comme d'habitude

{% csrf_token %}
{% load static %}

Au début de ʻindex.html`` et remplacez " / `` par `` "{% static'image / '%} / Quand j'ai vérifié plus tard, il y avait `` "/ `dans le processus js dans index.html, donc je veux éviter cela

Quand je mets ceci dans le serveur de précédent, `` navigator.mediaDevices.getUserMedia '' se plaint. Pour des raisons de sécurité, les navigateurs actuels ne peuvent pas accéder à la caméra à moins que index.html ne soit fourni avec la communication cryptée. Il est donc nécessaire d'installer SSL côté serveur

Django Introduire le SSL de développement sur le serveur

Préparation

Ajout de pip django-sslserver à précédent

python -m venv test
cd test
source bin/activate
pip install -U pip
pip install django opencv-python django-sslserver

django-admin startproject server
cd server
python manage.py startapp image
python manage.py migrate

openssl genrsa -out foobar.key 2048
openssl req -new -key foobar.key -out foobar.csr
openssl x509 -req -days 365 -in foobar.csr -signkey foobar.key -out foobar.crt

Presque identique à References Changez le chemin car le chemin du dernier foobar.csr '' et foobar.key '' a été généré au même endroit que manage.py. De plus, au stade du développement, toutes les entrées après `ʻopenssl genrsa -out foobar.key 2048`` peuvent être effectuées avec Enter.

server/setting.py


ALLOWED_HOSTS = ["127.0.0.1"]

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'image.apps.ImageConfig',
    'sslserver', #Ajouter un serveur SSL
]
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

D'autres sont les mêmes que la dernière fois Je veux compléter cette page

server/urls.py


from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('image/', include('image.urls')),
]

image/urls.py


from django.urls import path

from . import views

app_name = 'urls'
urlpatterns = [
    path('', views.Index, name='index'),
    path('res/', views.Res, name='res'),
]

Mettez-vous dans `ʻimage / static`` haarcascade_frontalface_default.xml

views.py


from django.shortcuts import render
from django.http.response import JsonResponse
from django.http import HttpResponse

import json, base64
import numpy as np
import cv2

def Index(request):
    return render(request, 'image/index.html')

def Res(request):
    data = request.body.decode('utf-8')
    jsondata = json.loads(data)

    image_base64 = jsondata["image"]
    encoded_data = image_base64.split(',')[1]
    nparr = np.fromstring(base64.b64decode(encoded_data), np.uint8)
    image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

    face_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    face_cascade = cv2.CascadeClassifier("image/static/haarcascade_frontalface_default.xml")
    faces = face_cascade.detectMultiScale(face_gray)
    for x, y, w, h in faces: #Ecrire un rectangle dans la zone du visage
        cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)

    result, dst_data = cv2.imencode('.png', image)
    dst_base64 = base64.b64encode(dst_data).decode()
    return JsonResponse({"image": "data:image/png;base64,"+dst_base64, "message": "Django"})

résultat

image.png J'ai pu détecter mon visage maussade

Conclusion

La communication devient immédiatement gênante lorsque l'environnement du serveur entre

Il faudra du temps pour préparer le vrai serveur, alors commencez à jouer avec Heroku Je ne peux pas laisser React le faire, alors la prochaine fois, je veux créer quelque chose comme un babillard

Les références

@Syoitu, «Activez Django https en quelques lignes», 7 novembre 2019

Recommended Posts

Un mémo qui détecte le visage de l'image acquise à partir de la caméra Web avec OpenCV de Django et le renvoie.
Récupérer une image d'une page Web et la redimensionner
Un mémo qui lit les données de dashDB avec Python et Spark
Un serveur qui renvoie le nombre de personnes devant la caméra avec bottle.py et OpenCV
Créer une API qui renvoie les données d'un modèle à l'aide de turicreate
J'ai créé un robot Line qui devine le sexe et l'âge d'une personne à partir de l'image
Essayez d'extraire une chaîne de caractères d'une image avec Python3
Détection de visage à partir de plusieurs fichiers image avec openCV, découpez et enregistrez
Un programme python qui redimensionne une vidéo et la transforme en image
Un mémo contenant Python2.7 et Python3 dans CentOS
J'ai essayé d'extraire le dessin au trait de l'image avec Deep Learning
Mémo qui a fait un graphique pour animer avec intrigue
Développer une API Web qui renvoie les données stockées dans DB avec Django et SQLite
Convertir des images du SDK FlyCapture en un formulaire pouvant être utilisé avec openCV
Créer une image à plage dynamique élevée (HDR) avec OpenCV et Python (Mertens, Robertson, Debevec)
Remarque à l'aide de VSCode + Python avec le mode d'affichage inductif de type notebook Jupyter
Capture d'image / comparaison de la vitesse OpenCV avec et sans GPU
Un mémo que j'ai touché au magasin de données avec python
"Un livre qui comprend Flask à partir de zéro" Lecture d'un mémo
Comment prendre une image capturée à partir d'une vidéo (OpenCV)
[Python] Taille d'image de la caméra Web et paramètres FPS avec OpenCV
Feuille de route d'apprentissage qui vous permet de développer et de publier des services à partir de zéro avec Python
Un exemple de mécanisme qui renvoie une prédiction par HTTP à partir du résultat de l'apprentissage automatique
Procédure pour créer un Job qui extrait une image Docker et la teste avec des actions Github