I want to detect faces from images (videos) taken with a webcam, with React and Django
When you hold the camera over it, you can see your face It might be useful for something security
Last time The dropped part is replaced with the webcam Due to this, some security settings are required.
React
Last time is no different I added the process to access the camera with the constructor Get an image from the camera? GetCameraImage is cut out Slightly changed the receiving process of 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/"; //Server post
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;
});
}
}
/**
*Get CSRF tokens from cookies
*/
getCSRFtoken() {
for (const c of document.cookie.split(";")) {
const cArray = c.split("=");
if (cArray[0] === "csrftoken") return cArray[1];
}
}
/**
*Get an image from the camera and convert it to a character string for sending and receiving
* @return {str} base64
*/
getCameraImage() {
this.state.context.drawImage(
this.state.video,
0,
0,
this.state.width,
this.state.height
);
return this.state.canvas.toDataURL();
}
/**
*Send data to the server
*/
submitData() {
this.setState({ image: this.getCameraImage() });
this.render();
// console.log("Send", this.state);
fetch(SERVER + "res/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": this.getCSRFtoken()
},
body: JSON.stringify({
image: this.state.image //← Send image
})
})
.then((res) => res.json())
.then((res) => {
console.log("Receive", res);
this.setState({ image: res.image, message: res.message }); //← Set image
this.render();
setTimeout(() => this.submitData(), 1000); //Send after 1 second
});
}
/**
*Button and send / receive data rendering
*/
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")
);
Copy and paste of JS that I wrote almost a long time ago
index.js
constructor(props) {
super(props);
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
this.state = { //Set canvas (for image drawing) and video (for video) elements
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; //Get the video from the camera and put it in the video element
this.state.video.play(); //Regeneration(?)
this.state.video.onloadedmetadata = (e) => { //Once the metadata can be loaded
this.setState({width: this.state.video.videoWidth, height: this.state.video.videoHeight}) //Size acquisition set
this.state.canvas.width = this.state.width; //Specify the size of the canvas
this.state.canvas.height = this.state.height;
this.submitData(); //Send to server
};
})
.catch(function (error) {
console.error(error);
return;
});
}
}
If it's related to video, video.onloadedmetadata or a guy who smells like crap I was suffering to death when I was making a video viewing app VideoWidth is not set for video unless the metadata load is confirmed by this process. Surprisingly, I'm always confused about the size specification here video is video.videoWidth and canvas is canvas.width
There seems to be await these days
This is also the same as the one I made a long time ago
index.js
getCameraImage() {
this.state.context.drawImage(this.state.video, 0, 0, this.state.width, this.state.height);
return this.state.canvas.toDataURL();
}
I feel that I was able to halve the horizontal size by doing this.state.width / 2
(remember)
It didn't make sense to cut it out here
I wanted to check the response image, so I made the next transmission 1 second after drawing the face detection image.
index.js
submitData() {
this.setState({ image: this.getCameraImage() });
this.render();
// console.log("Send", this.state);
fetch(SERVER + "res/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": this.getCSRFtoken()
},
body: JSON.stringify({
image: this.state.image //← Send image
})
})
.then((res) => res.json())
.then((res) => {
console.log("Receive", res);
this.setState({ image: res.image, message: res.message }); //← Set image
this.render();
setTimeout(() => this.submitData(), 1000); //Send after 1 second
});
}
I thought about sending by pressing a button, but I just render the button and post the event.
Build this and as usual
{% csrf_token %}
{% load static %}
At the beginning of `ʻindex.htmland replace
" / with
"{% static'image /'%} / When I checked later, there was
"/ `` in the js process in index.html, so I want to avoid that
When I thrust this into the server of previous, navigator.mediaDevices.getUserMedia
is complaining.
Today's browsers cannot access the camera unless index.html is provided with encrypted communication for security reasons.
So it is necessary to install SSL on the server side
Django Introduce development SSL to the server
Added pip django-sslserver
to previous
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
Almost the same as References
Change the path of the last foobar.csr
and foobar.key
because it was generated in the same place as manage.py
Also, at the development stage, all input after `ʻopenssl genrsa -out foobar.key 2048`` could be done with 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', #Add SSL server
]
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Others are the same as last time I want to complete this one 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'),
]
Put you in `ʻ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: #Write a rectangle in the face area
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"})
I was able to detect my moody face
Communication becomes troublesome at once when the server surroundings enter
It will take time to prepare the real server, so start playing with Heroku I can't let React do it, so next time I want to make something like a bulletin board
@Syoitu, “Enable Django https in a few lines,” November 07, 2019
Recommended Posts