how can I display flask selected video display - python

I want to display the selected video using a flask.
I select a video using HTML
<input id = "video_re" name = "video_select" accept = "video/*" type = "file" >
<input type="submit" value="testing" id="button_click" >
and then get the file name
#app.route('/testing', methods=['POST'])
def test():
f = request.files['video_select']
video_name = f.filename
return video_name
and display
def video_gray(selected):
camera = cv2.VideoCapture(selected)
while True:
success, frame = camera.read()
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # video grayscale
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', grayFrame)
grayFrame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + grayFrame + b'\r\n')
#app.route('/video_feed')
def video_feed():
return Response(video_gray(), mimetype='multipart/x-mixed-replace; boundary=frame')
html
<img src="{{url_for('video_feed')}}">
selected video name is video_name how can i how can i this value send to video_gray(selected) ?
or another way to display the selected video?

You can use the global variable, declare the video_name as global and you can use it anywhere you like
or try these, maybe this will help,
Just send the post data directly to the video_gray function
#app.route('/testing', methods=['POST'])
def video_gray():
f = request.files['video_select']
selected = f.filename
camera = cv2.VideoCapture(selected) ...
or you can just call your function in the test() function
#app.route('/testing', methods=['POST'])
def test():
f = request.files['video_select']
video_name = f.filename
video_gray(video_name)

Related

Flask: can't get redirection to work when using openCV

I am using opencv and pyzbar to make a barcode scanner that can work in a flask app.
There is a while True loop which constantly outputs the current camera frame to 127.0.0.1:5000/scanner, whilst simultaneously attempting to decode a barcode from the image. If it decodes a barcode, the loop breaks and the program redirects to 127.0.0.1:5000/output/, where the barcode number is displayed - except it doesn't for some reason. 127.0.0.1:5000/output/ displays correctly if it is entered manually.
Python:
from flask import Flask, render_template, Response, redirect, url_for
import io
import cv2
import sys
from pyzbar import pyzbar
app = Flask(__name__)
#app.route('/output/')
def output():
return str(output)
#app.route('/scanner')
def index():
return render_template('scanner.html')
def gen():
vc = cv2.VideoCapture(0)
while True:
read_return_code, frame = vc.read()
og = frame
cv2.rectangle(frame,(200,170),(450,330),(0,255,100),7)
frame = cv2.flip(frame, 1)
decode = pyzbar.decode(og)
if len(str(decode)) > 10:
global output
output = str(decode).split("'")
output = output[1]
vc.release()
return redirect('/output/') #THE PROBLEM
break
if cv2.waitKey(1) & 0xFF == ord('q'):
break
encode_return_code, image_buffer = cv2.imencode('.jpg', frame)
io_buf = io.BytesIO(image_buffer)
print("a", file=sys.stderr)
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + io_buf.read() + b'\r\n')
#app.route('/video_feed')
def video_feed():
return Response(
gen(),
mimetype='multipart/x-mixed-replace; boundary=frame'
)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, threaded=False)
HTML:
<html>
<head>
<style>
body{
font-family: Verdana, sans-serif;
}
</style>
<title>Scanner</title>
</head>
<body>
<h1>Scanner</h1>
<img src="{{ url_for('video_feed') }}">
</body>
</html>
you return redirect without parameters, this is equal to just requesting it via URL.
your 'output' route doesn't take any input params.
You should change your code to something like this, where 'data' is the output of your cv:
app.route('/output/<data>')
def output(data):
return str(data)
app.route('/scanner')
def index():
data='whatever'
return redirect(url_for('output', data=data))

How to stream .webm or .mjpeg from Python Django server?

I have a .webm feed from a 3rd party camera source. I would like to redistribute this to my web clients. I can open the stream in OpenCV then redistribute the .jpg images which works perfectly with img tags. However, I would like to convert this into a .webm or .mjpeg stream for use with video.js or other video tag. I don't have enough experience with HTTP protocol or video formatting and all my research only shows this .jpg streaming method.
models.py
streamManagerLock = threading.Lock()
streamManagers = {}
class StreamManager:
active = True
lastTime = time.time()
image = None
def __init__(self, cameraObj):
self.camera = cameraObj
url = "https://" + str(cameraObj.system.systemID) + ".relay-la.vmsproxy.com"
self.stream = cv.VideoCapture("{url}/web/media/{camID}.webm?auth={auth}".format(url=url,
camID=cameraObj.cam_id,
auth=cameraObj.system.getAuth()))
self.stream.set(cv.CAP_PROP_BUFFERSIZE, 5)
self.killThread = threading.Thread(target=self.selfTerminate, daemon=True)
self.lastTime = time.time()
self.killThread.start()
self.updateThread = threading.Thread(target=self.update_frame, daemon=True)
self.updateThread.start()
def selfTerminate(self):
while True:
if time.time() - self.lastTime > 3:
break
time.sleep(1)
self.terminate()
def terminate(self):
with streamManagerLock:
streamManagers.pop(str(self.camera.cam_id))
self.active = False
self.stream.release()
def update_frame(self):
while self.active:
ret, image = self.stream.read()
if ret:
ret, jpeg = cv.imencode('.jpg', image)
self.image = jpeg.tobytes()
else:
ret, img = cv.imencode('.jpg', np.zeros([100, 100, 3], dtype=np.uint8))
return img.tobytes()
time.sleep(1/30)
def get_frame(self):
self.lastTime = time.time()
if self.image is None:
ret, img = cv.imencode('.jpg', np.zeros([100, 100, 3], dtype=np.uint8))
return img.tobytes()
return self.image
def getCameraStream(cameraObj):
with streamManagerLock:
if str(cameraObj.cam_id) in streamManagers.keys():
return streamManagers[str(cameraObj.cam_id)]
else:
r = StreamManager(cameraObj)
streamManagers.update({str(cameraObj.cam_id): r})
return r
class Camera(models.Model):
cam_id = models.UUIDField()
label = models.CharField(max_length=100)
visible = models.ManyToManyField(CompanyModel, blank=True)
system = models.ForeignKey(DWCloudSystem, verbose_name="System", on_delete=models.CASCADE)
profile = models.ManyToManyField(UserProfile, blank=True)
isPublic = models.BooleanField(default=False)
def getStream(self):
def gen():
stream = getCameraStream(self)
while True:
frame = stream.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
try:
return StreamingHttpResponse(gen(), content_type="multipart/x-mixed-replace;boundary=frame")
except HttpResponseServerError as e:
return HttpResponseServerError()
def getThumbnail(self, height):
url = "ec2/cameraThumbnail"
params = {"cameraId": str(self.cam_id), "time": "LATEST", "height": 300, "ignoreExternalArchive": None}
response = self.system.proxyRequest(url, params=params)
if response is None:
time.sleep(3)
response = self.system.proxyRequest(url, params=params)
if response is None:
return HttpResponseServerError()
return HttpResponse(
content=response.content,
status=response.status_code,
content_type=response.headers['Content-Type']
)
def __str__(self):
return "{}: {}".format(str(self.system.company_key), str(self.label))
views.py
stream/{uuid:camID}
#handleAPIAuth
def getStream(request, camID):
cameras = getAllCameras(request)
cameras = cameras.filter(cam_id=camID)
if len(cameras) != 1:
return HttpResponseForbidden()
camera = cameras[0]
return camera.getStream()
template.html
video tag
<video
id="cam-stream"
class="video-js"
controls
preload="auto"
width="640"
height="264"
data-setup="{}"
>
<source id="stream-source" src="stream/49289ede-a66e-c436-839c-6141fd7f8f87" type="application/x-mpegURL" />
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
supports HTML5 video
</p>
</video>
When a thumbnail gets clicked:
<script type="text/javascript">
function changeImage(img){
document.getElementById("stream-source").src = "stream/"+img.getAttribute("camID");
}
</script>

Stream Realtime video frames from user/client side(Android App, iPhone App, python), to Flask API(server), and back to Client

I am working on an object detection API in Flask and I want to get a real-time video stream from the client which might be from an Android phone, an iPhone, or just from a python script running on windows/Linux.
at first I tried following:
def processFrames():
print('[DEBUG] call cv2.VideoCapture(0) from PID', os.getpid())
camera = cv2.VideoCapture(0)
while camera.isOpened():
ret, frame = camera.read()
if not ret:
break
else:
frame = DetectObject(frame)
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
#endpoints.route('/RealTime', methods=['GET','POST'])
def RealTime():
return Response(processFrames(), mimetype='multipart/x-mixed-replace; boundary=frame')
But it kept on giving the error:
[ WARN:1] global
/tmp/pip-req-build-13uokl4r/opencv/modules/videoio/src/cap_v4l.cpp
(890) open VIDEOIO(V4L2:/dev/video0): can't open camera by index
Which I realized was because OpenCV was trying to open the Camera on the server.
Then I came to this solution:
https://stackoverflow.com/a/59998983/16396308
but I don't know how to receive the response from:
emit('response_back', stringData)
[EDIT]
Please Help, because when I used the solution from above, sent an Image using through postman and this is I have on the server:
frame = secure_filename(file.filename)
sbuf = StringIO()
sbuf.write(frame)
b = BytesIO(pybase64.b64decode(frame))
pimg = Image.open(b)
to receive the image as file(for now), but for one image I get the following error:
binascii.Error binascii.
Error: Incorrect padding
And for a different image I get the following Error:
PIL.UnidentifiedImageError
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO
object at 0x7f3d9bbcf5e0>
[EDIT 2]
I was able to stream video from a python script to a remote machine.
client.py
def RT_Rec():
camera = cv2.VideoCapture(0)
try:
while True:
ret, frame = camera.read()
content_type = 'image/jpeg'
headers = {'content-type': content_type}
url = "https://[REMOTEMACHINEIP]/RealTime"
_, img_encoded = cv2.imencode('.jpg', frame)
response = requests.post(url, data=img_encoded.tobytes(), headers= headers)
if b"[SUCCESS]" in response.content or b"[ERROR]" in response.content :
print(response.content.decode('utf-8'))
break
else:
nparr = np.frombuffer(response.content,np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# print(type(img))
cv2.imshow("camera", img)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except Exception as e:
print(e)
finally:
camera.release()
cv2.destroyAllWindows()
SERVER.py
#endpoints.route("/RealTime",methods=["GET","POST"])
def realTime():
if request.method == "POST":
img = request.data
nparr = np.fromstring(img,np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
det,outImg = processFrame(img)
if det:
msg = "[SUCCESS] Processed"
return msg
_, img_encoded = cv2.imencode('.jpg', outImg)
return img_encoded.tobytes()
else:
return "[ERROR] Invalid Request", 500
Now I want to know how can I send frames from the Android/iPhone App so that the server receives them without any error.?
You can use SocketIO to get the user feed,
from flask import Flask, render_template, request
...
#socketio.on('connect', namespace='/web')
def connect_web():
print('[INFO] Web client connected: {}'.format(request.sid))
#socketio.on('disconnect', namespace='/web')
def disconnect_web():
print('[INFO] Web client disconnected: {}'.format(request.sid))
#socketio.on('connect', namespace='/cv')
def connect_cv():
print('[INFO] CV client connected: {}'.format(request.sid))
#socketio.on('disconnect', namespace='/cv')
def disconnect_cv():
print('[INFO] CV client disconnected: {}'.format(request.sid))
Here are some links which would come in handy :
https://towardsdatascience.com/video-streaming-in-web-browsers-with-opencv-flask-93a38846fe00
https://learn.alwaysai.co/build-your-own-video-streaming-server-with-flask-socketio
https://github.com/alwaysai/video-streamer

How to send images from Flask to JavaScript in real time

I'm currently writing a program that uses webRTC, Flask, and openCV etc... to analyze a webcam video in real time.
I succeeded in sending the webcam video from JavaScript to the Flask server, but I cannot display the image after analysis from Flask to HTML.
For example, I tried to save the image file once.
#app.route("/img", methods=["POST"])
def img():
img = cv2.imdecode(np.fromstring(request.files['video'].read(), np.uint8), cv2.IMREAD_UNCHANGED)
   #Processing by openCV...
cv2.imwrite("test.jpg", img)
return "success"
#app.route('/feed')
def feed():
return Response(gen(), mimetype='multipart/x-mixed-replace; boundary=frame')
def gen():
while True:
with open('test.jpg', 'rb') as f:
img = f.read()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + img + b'\r\n')
Next is the HTML code
<img id="cap-src" src="{{ url_for('feed') }}">
However, this code curiously didn't update the image displayed in HTML, so I gave up.
Then I tried the method of not saving the image.
#app.route("/img", methods=["POST"])
def img():
global img
img = cv2.imdecode(np.fromstring(request.files['video'].read(), np.uint8), cv2.IMREAD_UNCHANGED)
def generate_img():
  #Processing by openCV...
#app.route('/feed')
def feed():
return Response(gen(), mimetype='multipart/x-mixed-replace; boundary=frame')
def gen():
while True:
img = generate_img()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + img + b'\r\n')
The HTML code does not change.
However, this method did not update the image displayed in HTML.
Is there any good way?
And I want to use a method that doesn't save the image if possible.Thank you.
Finally, I put the summarized code.
This is the HTML code
<html>
<head>
</head>
<body>
<img id="img">
<video id="myvideo" width="720px" autoplay></video>
<button id="start"></button>
<canvas id="videocanvas"></canvas>
<img id="cap-src" src="">
<script src="https://code.jquery.com/jquery-1.12.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script>
$(function(){
const constraints = window.constraints = {
audio: false,
video: {
facingMode: "environment"
}
};
async function init() {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
const video = document.querySelector('#myvideo');
const videoTracks = stream.getVideoTracks();
window.stream = stream;
video.srcObject = stream;
e.target.disabled = true;
} catch{
$('#errorMsg').text('error');
}
}
$('#start').click(init);
var canvas = $('#videocanvas')[0];
$('#myvideo').on('loadedmetadata', function(){
var video = $('#myvideo')[0];
var width = canvas.width = video.videoWidth;
var height = canvas.height = video.videoHeight;
var ctx = canvas.getContext("2d");
var fd = new FormData();
fd.append('video', null);
setInterval(function(){
ctx.drawImage(video, 0, 0, width, height);
canvas.toBlob(function(blob){
fd.set('video', blob);
$.ajax({
url: "/img",
type : "POST",
processData: false,
contentType: false,
data : fd,
dataType: "text",
})
.done(function(data){
console.log(data);
})
.fail(function(data){
console.log(data);
});
}, 'image/jpeg');
},100);
});
});
document.getElementById("start").onclick = function() {
document.getElementById("cap-src").src = "{{ url_for('feed') }}";
}
</script>
</body>
</html>
And the python code.
from flask import Flask, render_template, Response, request, jsonify
import cv2
import numpy as np
from PIL import Image
#app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,POST') # Put any other methods you need here
return response
#app.route('/')
def index():
return render_template('index.html')
#app.route("/img", methods=["POST"])
def img():
img = cv2.imdecode(np.fromstring(request.files['video'].read(), np.uint8), cv2.IMREAD_UNCHANGED)
image = cv2.resize(img, (480, 300))
cv2.imwrite("test.jpg", image)
ret, jpeg = cv2.imencode('.jpg', image)
jpeg = jpeg.tobytes()
return "success"
#api.route('/feed')
def feed():
return Response(gen(), mimetype='multipart/x-mixed-replace; boundary=frame')
def gen():
while True:
with open('./templates/dst/test.jpg', 'rb') as f:
img = f.read()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + img + b'\r\n')
Since the issue you mentioned is about "displaying the image after analysis from Flask to HTML", so here is the solution to your problem, it can send video or camera output images to the html. For more details follow this tutorial
The main python app (which will run on the server) file is here:
app.py
from flask import Flask, render_template, request,Response
import cv2,imutils,time
import pyshine as ps
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
def changeBrightness(img,value):
""" This function will take an image (img) and the brightness
value. It will perform the brightness change using OpenCv
and after split, will merge the img and return it.
"""
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
lim = 255 - value
v[v>lim] = 255
v[v<=lim] += value
final_hsv = cv2.merge((h,s,v))
img = cv2.cvtColor(final_hsv,cv2.COLOR_HSV2BGR)
return img
def changeBlur(img,value):
""" This function will take the img image and blur values as inputs.
After perform blur operation using opencv function, it returns
the image img.
"""
kernel_size = (value+1,value+1) # +1 is to avoid 0
img = cv2.blur(img,kernel_size)
return img
def pyshine_process(params):
print("Parameters:",params)
"""Video streaming generator function."""
CAMERA=True
if CAMERA:
cap = cv2.VideoCapture(0)
else:
cap = cv2.VideoCapture('videos/mario.mp4')
print('FUNCTION DONE')
# Read until video is completed
fps=0
st=0
frames_to_count=20
cnt=0
while(cap.isOpened()):
ret, img = cap.read()
brightness_value_now = int(params['brightness'])
blur_value_now = int(params['blur'])
img = changeBrightness(img,brightness_value_now)
img = changeBlur(img,blur_value_now)
if ret == True:
if cnt == frames_to_count:
try: # To avoid divide by 0 we put it in try except
fps = round(frames_to_count/(time.time()-st))
st = time.time()
cnt=0
except:
pass
cnt+=1
img = imutils.resize(img, width=640)
text = 'FPS: '+str(fps)
img = ps.putBText(img,text,text_offset_x=20,text_offset_y=30,background_RGB=(10,20,222))
text = str(time.strftime("%d %b %Y %H.%M.%S %p"))
img = ps.putBText(img,text,text_offset_x=190,text_offset_y=30,background_RGB=(228,20,222))
text = f"Brightness: {brightness_value_now}"
img = ps.putBText(img,text,text_offset_x=20,text_offset_y=300,background_RGB=(20,210,4))
text = f'Blur: {blur_value_now}'
img = ps.putBText(img,text,text_offset_x=490,text_offset_y=300,background_RGB=(210,20,4))
frame = cv2.imencode('.JPEG', img,[cv2.IMWRITE_JPEG_QUALITY,20])[1].tobytes()
time.sleep(0.016)
yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
else:
break
#app.route('/res',methods = ['POST','GET'])
def res():
global result
if request.method == 'POST':
result = request.form.to_dict()
return render_template("results.html",result = result)
#app.route('/results')
def video_feed():
global result
params= result
return Response(pyshine_process(params),mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(debug=True, host='192.168.1.104',port=9999,threaded=True)
Here are the files for the templates folder
index.html
<html>
<head>
<title>PyShine streaming video application </title>
</head>
<body>
<h1>Please input the parameters (0 to 100): </h1>
<form action = "http://192.168.1.104:9999/res" method = "POST">
<table>
<tr>
<td align="right">Brightness:</td>
<td align="left"><input type="text" name="brightness" value="1" /></td>
</tr>
<tr>
<td align="right">Blur:</td>
<td align="left"><input type="text" name="blur" value="0" /></td>
</tr>
<tr>
<td></td>
<td align="right"><input type = "submit" value = "submit" /></td>
</tr>
</table>
</form>
</body>
</html>
results.html
<!DOCTYPE html>
<html>
<head>
<title>PyShine Streaming Video Application </title>
</head>
<body>
<h1>PyShine streaming processed video... </h1>
<br>
<img src="">
<br>
<input type="button" value="Go back!" onclick="history.back()">
</body>
</html>
Important: change the host IP address according to your specifications.

Return Frame as well as JSON response using same API in Flask Python

Using mentioned below code I am trying to return video feed as well as some JSON data in response which will help me further in displaying the data in browser for a particular frame, but from success, frame = cap.read() I am not able to fetch data from variable success and share the data with API in which I am getting streamed data,
from flask import Flask, render_template, Response
import cv2
app = Flask(__name__)
# list of camera accesses
cameras = [
"rtsp://username:password#ip_address:554/user=username_password='password'_channel=channel_number_stream=0.sdp",
"rtsp://username:password#ip_address:554/user=username_password='password'_channel=channel_number_stream=0.sdp",
...
]
def find_camera(list_id):
return cameras[int(list_id)]
def gen_frames(camera_id):
cam = find_camera(camera_id) # return the camera access link with credentials. Assume 0?
# cam = cameras[int(id)]
cap = cv2.VideoCapture(cam) # capture the video from the live feed
while True:
# # Capture frame-by-frame. Return boolean(True=frame read correctly. )
success, frame = cap.read() # read the camera frame
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') # concat frame one by one and show result
#app.route('/video_feed/<string:list_id>/', methods=["GET"])
def video_feed(list_id):
return Response(gen_frames(list_id),
mimetype='multipart/x-mixed-replace; boundary=frame')
#app.route('/', methods=["GET"])
def index():
return render_template('index.html', camera_list=len(cameras), camera=cameras)
if __name__ == '__main__':
app.run()
Any Suggestion on this will be very helpful here

Categories