Sitemap
Python in Plain English

New Python content every day. Follow to join our 3.5M+ monthly readers.

Follow publication

Real-Time Image Processing using WebSockets and Flask in Python and JavaScript

8 min readFeb 23, 2023

--

Press enter or click to view image in full size
Photo by Pankaj Patel on Unsplash

Introduction

Prerequisites

# Create Virtual Environment
python -m venv env

# Activate Virtual Environment
# Linux
source env/bin/activate
# Windows
source env\Scripts\activate
# requirements.txt

Flask-SocketIO==4.3.1
python-engineio==3.13.2
python-socketio==4.6.0
Flask==2.0.3
Werkzeug==2.0.3
opencv_python==4.7.0.68
numpy==1.24.2

Understanding the Code

HTML

JavaScript

Python

Building the Application

Step 1: Setting Up Flask and Socket.IO

from flask import Flask, render_template, send_from_directory
from flask_socketio import SocketIO, emit

app = Flask(__name__, static_folder="./templates/static")
app.config["SECRET_KEY"] = "secret!"
socketio = SocketIO(app)

Step 2: Setting up the Index Route

@app.route("/")
def index():
return render_template("index.html")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask Client Camera Web App</title>

<style>
#video {
transform: rotateY(180deg);
-webkit-transform:rotateY(180deg); /* Safari and Chrome */
-moz-transform:rotateY(180deg); /* Firefox */

}
</style>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js">
</script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js">
</script>
</head>

<body>

<div id="container">
<video autoplay playsinline id="videoElement"></video>
<canvas id="canvas" width="400" height="300"></canvas>
</div>

<div class= 'video'>
<img id="photo" width="400" height="300">
</div>
<script src="{{ url_for('static',filename='script.js') }}"></script>
</body>

</html>

Step 3: Capturing Video from the User’s Camera

var socket = io.connect(window.location.protocol + '//' + document.domain + ':' + location.port);
socket.on('connect', function () {
console.log("Connected...!", socket.connected)
});

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
const video = document.querySelector("#videoElement");

video.width = 400;
video.height = 300;

if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({
video: true
})
.then(function (stream) {
video.srcObject = stream;
video.play();
})
.catch(function (err0r) {

});
}
const FPS = 10;
setInterval(() => {
width = video.width;
height = video.height;
context.drawImage(video, 0, 0, width, height);
var data = canvas.toDataURL('image/jpeg', 0.5);
context.clearRect(0, 0, width, height);
socket.emit('image', data);
}, 1000 / FPS);

socket.on('processed_image', function (image) {
photo.setAttribute('src', image);

});

Step 4: Processing Client Webcam Stream

import base64
import os
import cv2
import numpy as np
from flask import Flask, render_template, send_from_directory
from flask_socketio import SocketIO, emit
app = Flask(__name__, static_folder="./templates/static")
app.config["SECRET_KEY"] = "secret!"
socketio = SocketIO(app)
def base64_to_image(base64_string):
# Extract the base64 encoded binary data from the input string
base64_data = base64_string.split(",")[1]
# Decode the base64 data to bytes
image_bytes = base64.b64decode(base64_data)
# Convert the bytes to numpy array
image_array = np.frombuffer(image_bytes, dtype=np.uint8)
# Decode the numpy array as an image using OpenCV
image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
return image
@socketio.on("connect")
def test_connect():
print("Connected")
emit("my response", {"data": "Connected"})
@socketio.on("image")
def receive_image(image):
# Decode the base64-encoded image data
image = base64_to_image(image)

# Perform image processing using OpenCV
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
frame_resized = cv2.resize(gray, (640, 360))

# Encode the processed image as a JPEG-encoded base64 string
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
result, frame_encoded = cv2.imencode(".jpg", frame_resized, encode_param)
processed_img_data = base64.b64encode(frame_encoded).decode()

# Prepend the base64-encoded string with the data URL prefix
b64_src = "data:image/jpg;base64,"
processed_img_data = b64_src + processed_img_data

# Send the processed image back to the client
emit("processed_image", processed_img_data)
if __name__ == "__main__":
socketio.run(app, debug=True, port=5000, host='0.0.0.0')
import base64
import os

import cv2
import numpy as np
from flask import Flask, render_template, send_from_directory
from flask_socketio import SocketIO, emit

app = Flask(__name__, static_folder="./templates/static")
app.config["SECRET_KEY"] = "secret!"
socketio = SocketIO(app)


@app.route("/favicon.ico")
def favicon():
return send_from_directory(
os.path.join(app.root_path, "static"),
"favicon.ico",
mimetype="image/vnd.microsoft.icon",
)


def base64_to_image(base64_string):
# Extract the base64 encoded binary data from the input string
base64_data = base64_string.split(",")[1]
# Decode the base64 data to bytes
image_bytes = base64.b64decode(base64_data)
# Convert the bytes to numpy array
image_array = np.frombuffer(image_bytes, dtype=np.uint8)
# Decode the numpy array as an image using OpenCV
image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
return image


@socketio.on("connect")
def test_connect():
print("Connected")
emit("my response", {"data": "Connected"})


@socketio.on("image")
def receive_image(image):
# Decode the base64-encoded image data
image = base64_to_image(image)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

frame_resized = cv2.resize(gray, (640, 360))

encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]

result, frame_encoded = cv2.imencode(".jpg", frame_resized, encode_param)

processed_img_data = base64.b64encode(frame_encoded).decode()

b64_src = "data:image/jpg;base64,"
processed_img_data = b64_src + processed_img_data

emit("processed_image", processed_img_data)


@app.route("/")
def index():
return render_template("index.html")


if __name__ == "__main__":
socketio.run(app, debug=True, port=5000, host='0.0.0.0')

Conclusion

References

--

--

Python in Plain English
Python in Plain English

Published in Python in Plain English

New Python content every day. Follow to join our 3.5M+ monthly readers.

Ifeanyi Nneji
Ifeanyi Nneji

Written by Ifeanyi Nneji

Aspiring Data Scientist and Machine Learning Enthusiast

No responses yet

Write a response