Flask Live-Stream Not working with host attribute - python

I want to classify a video using opencv methods by using flask, the video to be classified is live-stream that is from the user.
I googled a lot, then finally I found some code and did this:-
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import time
import io
from PIL import Image
import base64,cv2
import numpy as np
# import pyshine as ps
from flask_cors import CORS,cross_origin
import imutils
# import dlib
from engineio.payload import Payload
# detector = dlib.get_frontal_face_detector()
# predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
Payload.max_decode_packets = 2048
app = Flask(__name__)
socketio = SocketIO(app,cors_allowed_origins='*' )
CORS(app)
#app.route('/', methods=['POST', 'GET'])
def index():
return render_template('index.html')
def readb64(base64_string):
idx = base64_string.find('base64,')
base64_string = base64_string[idx+7:]
sbuf = io.BytesIO()
sbuf.write(base64.b64decode(base64_string, ' /'))
pimg = Image.open(sbuf)
return cv2.cvtColor(np.array(pimg), cv2.COLOR_RGB2BGR)
def moving_average(x):
return np.mean(x)
#socketio.on('catch-frame')
def catch_frame(data):
emit('response_back', data)
global fps,prev_recv_time,cnt,fps_array
fps=30
prev_recv_time = 0
cnt=0
fps_array=[0]
#socketio.on('image')
def image(data_image):
global fps,cnt, prev_recv_time,fps_array
recv_time = time.time()
text = 'FPS: '+str(fps)
frame = (readb64(data_image))
# frame = changeLipstick(frame,[255,0,0])
# frame = ps.putBText(frame,text,text_offset_x=20,text_offset_y=30,vspace=20,hspace=10, font_scale=1.0,background_RGB=(10,20,222),text_RGB=(255,255,255))
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
imgencode = cv2.imencode('.jpeg', frame,[cv2.IMWRITE_JPEG_QUALITY,40])[1]
# base64 encode
stringData = base64.b64encode(imgencode).decode('utf-8')
b64_src = 'data:image/jpeg;base64,'
stringData = b64_src + stringData
# emit the frame back
emit('response_back', stringData)
fps = 1/(recv_time - prev_recv_time)
fps_array.append(fps)
fps = round(moving_average(np.array(fps_array)),1)
prev_recv_time = recv_time
#print(fps_array)
cnt+=1
if cnt==30:
fps_array=[fps]
cnt=0
def getMaskOfLips(img,points):
""" This function will input the lips points and the image
It will return the mask of lips region containing white pixels
"""
mask = np.zeros_like(img)
mask = cv2.fillPoly(mask,[points],(255,255,255))
return mask
def changeLipstick(img,value):
""" This funciton will take img image and lipstick color RGB
Out the image with a changed lip color of the image
"""
img = cv2.resize(img,(0,0),None,1,1)
imgOriginal = img.copy()
imgColorLips=imgOriginal
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = detector(imgGray)
for face in faces:
x1,y1 = face.left(),face.top()
x2,y2 = face.right(),face.bottom()
facial_landmarks = predictor(imgGray,face)
points =[]
for i in range(68):
x = facial_landmarks.part(i).x
y = facial_landmarks.part(i).y
points.append([x,y])
points = np.array(points)
imgLips = getMaskOfLips(img,points[48:61])
imgColorLips = np.zeros_like(imgLips)
imgColorLips[:] =value[2],value[1],value[0]
imgColorLips = cv2.bitwise_and(imgLips,imgColorLips)
value = 1
value=value//10
if value%2==0:
value+=1
kernel_size = (6+value,6+value) # +1 is to avoid 0
weight = 1
weight = 0.4 + (weight)/400
imgColorLips = cv2.GaussianBlur(imgColorLips,kernel_size,10)
imgColorLips = cv2.addWeighted(imgOriginal,1,imgColorLips,weight,0)
return imgColorLips
if __name__ == '__main__':
socketio.run(app,port=9990 ,debug=True)
This is in main.py of flask
In the templates folder I have made index.html with
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</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.0/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">
<h1>video</h1>
</div>
<script type="text/javascript" charset="utf-8">
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 = 6;
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('response_back', function(image){
photo.setAttribute('src', image );
});
</script>
</body>
</html>
The problem is: I need to make sure that it works on the user's device, so when I change socketio.run() and add host='0.0.0.0' It stops having access to my webcam
How can I solve this?
also I am unable to show back the video :(
The Error in Console
polling-xhr.js:264 GET http://localhost:9990/socket.io/?EIO=3&transport=polling&t=N_GnQuZ 400 (BAD REQUEST)

Hey,
First you are using a very old socketio client version.
https://cdn.socket.io/4.4.1/socket.io.min.js
use a newer version of socketio client, thats the reason for 400 Error, if you are going to the preview window of the request on dev tools (chrome) you have notice that there are a not supported version message.
Why you dont see the webcam!? is because you have no security context, when you go away from localhost like 0.0.0.0 you need a security context on chrome based browser it means you need HTTPS otherwise "navigator.mediaDevices.getUserMedia" will return undefined.
See this post

Related

Send image from nodejs app to python app(and vice versa)

I am attempting to send images from nodejs to python, use those images for a function, then return a different image back to nodejs. However, I'm having issues with this and getting errors:
Error: aborted
at connResetException (node:internal/errors:692:14)
at TLSSocket.socketCloseListener (node:_http_client:414:19)
at TLSSocket.emit (node:events:539:35)
at TLSSocket.emit (node:domain:475:12)
at node:net:709:12 {
code: 'ECONNRESET'
}
I know it is an issue sending an image itself, because I tried sending text and that worked. To solve it, I used pure trial and error without any luck. Here is the nodejs Code(uses express) currently:
const options = {
method: 'POST',
url: 'pathToPythonstufff',
formData: {
image1: {
value: image1v2,
options: {
filename: 'falsified2.jpg',
contentType: 'image/jpeg'
}
},
image2: {
value: image2v2,
options: {
filename: 'jeff.jpg',
contentType: 'image/jpeg'
}
}
}
};
const pleaseF = request(options, (err, res, body) => {
console.log('sent')
if (err) {
console.log(err);
console.log('err here')
}
console.log(body)
console.log(res.body)
console.log(res.image)
console.log(res.img)
//console.log(res)
/*let img_str = body.img;
// Decode the image
let img_buffer = new Buffer.from(img_str, 'base64');
fs.writeFileSync('difference3.png', img_buffer);*/
});
pleaseF.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
And the python code(commented out is the goal, but I commented it out to test and there is no change in nodejs error with or without it commented):
import cv2
import numpy as np
from flask import Flask, request, jsonify, after_this_request
import base64
app = Flask(__name__)
print('hello')
#app.route('/difference', methods=['POST'])
def difference():
# print('hello2')
# # Retrieve image data from the request
# image1 = request.files.get('image1').read()
# image2 = request.files.get('image2').read()
# print('hello again')
# # Decode image data into OpenCV format
# image1 = cv2.imdecode(np.frombuffer(image1, np.uint8), cv2.IMREAD_COLOR)
# image2 = cv2.imdecode(np.frombuffer(image2, np.uint8), cv2.IMREAD_COLOR)
# # Resize images to a common size
# image1 = cv2.resize(image1, (500, 500))
# image2 = cv2.resize(image2, (500, 500))
# # Convert images to grayscale
# image1_gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
# image2_gray = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
# # Extract differences between the images
# diff = cv2.absdiff(image1_gray, image2_gray)
# thresh = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)[1]
# # Find contours in the thresholded image
# contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# # Draw green boxes around the contours
# for cnt in contours:
# x, y, w, h = cv2.boundingRect(cnt)
# cv2.rectangle(image1, (x, y), (x+w, y+h), (0, 255, 0), 2)
# # Encode the image in PNG format
# _, buffer = cv2.imencode('.png', image1)
# # Create a response object with the image data
# # response = jsonify(img_data=buffer.tobytes())
# # response.headers.set('Content-Type', 'image/png')
# # response2 = jsonify(img_data=buffer)
# # response.headers.set('Content-Type', 'image/png')
# # imageNew = cv2.imdecode(buffer, cv2.IMREAD_COLOR)
# # response = jsonify(img_data=imageNew)
# # response.headers.set('Content-Type', 'image/png')
# # _, buffer = cv2.imencode('.png', image1)
# # Create a response object with the image data
# #response = jsonify(img_data=buffer.tobytes())
# # response.headers.set('Content-Type', 'image/png')
# # return response
# img_str = base64.b64encode(buffer.tobytes()).decode()
# response = jsonify(img_data=img_str)
# response.headers.set('Content-Type', 'image/png')
# return jsonify({'image': response})
#_, welp = cv2.imencode('.jpg', difference)
return "please goddamitt"
if __name__ == '__main__':
app.run(debug=True)
```
And if it isn't that above node error, its a different node error in the form of html(cant seem to reproduce it right now but I got it before with no difference in code). But I do know for sure it has something to do with the images I'm sending.

Failed to load resource: the server responded with a status of 422 (unprocessable entity) in reactjs with python api

I am working on reactjs with python api and openCV which after uploading photo returns result with green rectangle around the face. So working on it, on clicking upload photo it returns 422(unprocessable entity). I have three main part Upload.js for frontend uploading part, main.py image api and face_detector.py for opencv part.
Upload.js
import React, { useState } from 'react'
import './Upload.css'
import axios from 'axios';
const Upload = () => {
const [file, setFile] = useState();
const handleChange = (event) => {
setFile(URL.createObjectURL(event.target.files[0]))
}
const submitForm = () => {
const formData = new FormData();
formData.append('file', file);
axios
.post('http://127.0.0.1:8000/images', formData, {
headers: {
accept: 'multipart/form-data',
}
})
.then(() => {
alert('file upload succcess');
})
.catch(() => alert("File Upload Error"))
return formData
}
return (
<>
<input className='img_choose' type="file" onChange={handleChange} />
<img src={file} className='prev_img' alt='img' />
<button className='btn_upload' onClick={submitForm}>Upload</button>
</>
);
}
export default Upload
main.py
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import Response
from random import randint
from starlette.requests import Request
import uuid
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
db = []
origins = [
"http://localhost:3000",
"http://127.0.0.1:8000/"
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
#app.get("/main")
def main():
return{"message":"Welcome"}
#app.post("/images/")
async def create_upload_file(file: UploadFile = File(...)):
file.filename = f"{uuid.uuid4()}.jpg"
contents = await file.read() # <-- Important!
db.append(contents)
return {"filename": file.filename}
#app.get("/images/")
async def read_random_file():
# get a random file from the image db
random_index = randint(0, len(db) - 1)
response = Response(content=db[random_index])
return response
Face_detector.py
import cv2
import urllib.request
import numpy as np
url = [
"http://127.0.0.1:8000/images/"
]
def url_to_image(url):
# download the image, convert it to a NumPy array, and then read
# it into OpenCV format
resp = urllib.request.urlopen(url)
image = np.asarray(bytearray(resp.read()), dtype="uint8")
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
# return the image
return image
for url in url:
trained_face_data = cv2.CascadeClassifier(
'haarcascade_frontalface_default.xml')
x = y = w = h = int
image = url_to_image(url)
face_coordinates = trained_face_data.detectMultiScale(image,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE)
for (x, y, w, h) in face_coordinates:
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.imshow("Image", image)
cv2.waitKey(0)
This is where you are doing it wrong.
setFile(URL.createObjectURL(event.target.files[0]))
You are attaching the file URL in the formData instead of the file.
use this instead
setFile(event.target.files[0])

Why is socket io client side is not working?

I am trying to make a video streamer to stream client camera using socket.io and flask, but my socket io seems not responding at all as it is not returning log on my console Connected..! What is the cause of this please help thanks.
Here is my app.py
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
socketio = SocketIO(app)
#app.route('/', methods=['POST', 'GET'])
def index():
return render_template('index.html')
#socketio.on('image')
def image(data_image):
sbuf = StringIO()
sbuf.write(data_image)
# decode and convert into image
b = io.BytesIO(base64.b64decode(data_image))
pimg = Image.open(b)
## converting RGB to BGR, as opencv standards
frame = cv2.cvtColor(np.array(pimg), cv2.COLOR_RGB2BGR)
# Process the image frame
frame = imutils.resize(frame, width=700)
frame = cv2.flip(frame, 1)
imgencode = cv2.imencode('.jpg', frame)[1]
# base64 encode
stringData = base64.b64encode(imgencode).decode('utf-8')
b64_src = 'data:image/jpg;base64,'
stringData = b64_src + stringData
# emit the frame back
emit('response_back', stringData)
if __name__ == "__main__":
socketio.run(app, host='127.0.0.1')
and here is my index.html. I plan to have the response to be put on img with id image by using javascript socket io in my client side.
<div class = 'video'>
<img id="image">
</div>
<script>
var socket = io('http://localhost:5000');
socket.on('connect', function(){
console.log("Connected...!", socket.connected)
});
const video = document.querySelector("#videoElement");
video.width = 500;
video.height = 375; ;
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true })
.then(function (stream) {
video.srcObject = stream;
video.play();
})
.catch(function (err0r) {
console.log(err0r)
console.log("Something went wrong!");
});
}
let src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let dst = new cv.Mat(video.height, video.width, cv.CV_8UC1);
let cap = new cv.VideoCapture(video);
const FPS = 22;
setInterval(() => {
cap.read(src);
var type = "image/png"
var data = document.getElementById("canvasOutput").toDataURL(type);
data = data.replace('data:' + type + ';base64,', ''); //split off junk
at the beginning
socket.emit('image', data);
}, 10000/FPS);
socket.on('response_back', function(image){
const image_id = document.getElementById('image');
image_id.src = image;
});
</script>
This is the only response that my flask server give. It is strange that my flask server completely stop after that get. What I expected is for the server to emit back the response but nothing happen
* Serving Flask app "app.py" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 268-223-757
127.0.0.1 - - [25/Mar/2021 09:41:49] "GET / HTTP/1.1" 200 -

Can't access Wifi-Cam From OpenCV-Python

Im using a Wifi-Cam called Esp32-Cam and trying to connect to it with openCv. The Node server.js code makes it possible to connect to the module by it's IP address. The code for server.js is given below:
SERVER.JS:
const path = require('path');
const express = require('express');
const WebSocket = require('ws');
const app = express();
const WS_PORT = 8888;
const HTTP_PORT = 8000;
const wsServer = new WebSocket.Server({port: WS_PORT}, ()=> console.log(`WS Server is listening at
${WS_PORT}`));
let connectedClients = [];
wsServer.on('connection', (ws, req)=>{
console.log('Connected');
connectedClients.push(ws);
ws.on('message', data => {
connectedClients.forEach((ws,i)=>{
if(ws.readyState === ws.OPEN){
ws.send(data);
}else{
connectedClients.splice(i ,1);
}
})
});
});
app.get('/client',(req,res)=>res.sendFile(path.resolve(__dirname, './client.html')));
app.listen(HTTP_PORT, ()=> console.log(`HTTP server listening at ${HTTP_PORT}`));
CLÄ°ENT.HTML:
<html>
<head>
<title>Client</title>
</head>
<body>
<img src="">
<script>
const img = document.querySelector('img');
const WS_URL = 'ws:///192.168.1.33:8888';
const ws = new WebSocket(WS_URL);
let urlObject;
ws.onopen = () => console.log(`Connected to ${WS_URL}`);
ws.onmessage = message => {
const arrayBuffer = message.data;
if(urlObject){
URL.revokeObjectURL(urlObject);
}
urlObject = URL.createObjectURL(new Blob([arrayBuffer]));
img.src = urlObject;
}
</script>
</body>
I can access the streaming video on the address "http://192.168.1.33:8000/client" with my browser but not on opencv. Here's the code in OpenCv python trying to reach the camera.
OPENCV CODE:
cap = cv2.VideoCapture('http://192.168.1.33:8000/client')
print(cap.isOpened()) //it prints FALSE
while(True):
ret, frame = cap.read()
cv2.imshow('framee',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
I dont understand why i can't access the camera since this esp32 module is just like an IP camera? I would appreciate any help.
Thank you.

I am not able to obtain data from process.stdout.on globally

I am trying to obtain the value of category variable using a machine learning code in python. Although when i execute the code the category variable isn't changed at all and database stores the category as "A" which is defined outside globally. As far as i know, it is due to some asynchronous behavior but i don't know the actual solution.
var category = "A";
if (type == "lost") {
var spawn = require("child_process").spawn;
var process = spawn('python', ["./evaluate_lost.py", req.body.image]);
process.stdout.on('data', function(data) {
category += data.toString();
});
var newLost = {
name: name,
date: date,
time: time,
location: location,
phone: phone,
image: image,
description: desc,
category: category,
author: author
};
// Create a new lost and save to DB
Lost.create(newLost, function(err, newlyCreated) {
if (err) {
console.log(err);
} else {
//redirect back to items page
res.redirect("/items");
}
});
}
Well i am editing the question with the evaluate_lost.py script and the directory structure.
import sys
from keras import backend as K
import inception_v4
import numpy as np
import cv2
import os
import argparse
image=sys.argv[1]
# If you want to use a GPU set its index here
os.environ['CUDA_VISIBLE_DEVICES'] = ''
# This function comes from Google's ImageNet Preprocessing Script
def central_crop(image, central_fraction):
if central_fraction <= 0.0 or central_fraction > 1.0:
raise ValueError('central_fraction must be within (0, 1]')
if central_fraction == 1.0:
return image
img_shape = image.shape
depth = img_shape[2]
fraction_offset = int(1 / ((1 - central_fraction) / 2.0))
bbox_h_start = int(np.divide(img_shape[0], fraction_offset))
bbox_w_start = int(np.divide(img_shape[1], fraction_offset))
bbox_h_size = int(img_shape[0] - bbox_h_start * 2)
bbox_w_size = int(img_shape[1] - bbox_w_start * 2)
image = image[bbox_h_start:bbox_h_start+bbox_h_size, bbox_w_start:bbox_w_start+bbox_w_size]
return image
def get_processed_image(img_path):
# Load image and convert from BGR to RGB
im = np.asarray(cv2.imread(img_path))[:,:,::-1]
im = central_crop(im, 0.875)
im = cv2.resize(im, (299, 299))
im = inception_v4.preprocess_input(im)
if K.image_data_format() == "channels_first":
im = np.transpose(im, (2,0,1))
im = im.reshape(-1,3,299,299)
else:
im = im.reshape(-1,299,299,3)
return im
if __name__ == "__main__":
# Create model and load pre-trained weights
model = inception_v4.create_model(weights='imagenet', include_top=True)
# Open Class labels dictionary. (human readable label given ID)
classes = eval(open('validation_utils/class_names.txt', 'r').read())
# Load test image!
img_path = "../public/files/lost/" + image
img = get_processed_image(img_path)
# Run prediction on test image
preds = model.predict(img)
print("Class is: " + classes[np.argmax(preds)-1])
print("Certainty is: " + str(preds[0][np.argmax(preds)]))
sys.stdout.flush()
This is the directory structure which evaluates the python script on watch.jpg which is input through HTML form
I expect the category to be as returned from python machine learning code rather than what is already defined.
The data event handler runs asynchronously, you're not waiting for all the output to be consumed.
Use the end event to detect the end of the output, and run the code that saves the new Lost object there.
var category = "A";
if (type == "lost") {
var spawn = require("child_process").spawn;
var process = spawn('python', ["./evaluate_lost.py", req.body.image]);
process.stdout.on('data', function(data) {
category += data.toString();
});
process.stdout.on('end', function() {
var newLost = {
name: name,
date: date,
time: time,
location: location,
phone: phone,
image: image,
description: desc,
category: category,
author: author
};
// Create a new lost and save to DB
Lost.create(newLost, function(err, newlyCreated) {
if (err) {
console.log(err);
} else {
//redirect back to items page
res.redirect("/items");
}
});
});
}

Categories