Last active
December 10, 2019 14:10
-
-
Save raiever/2044928db9deb98c5e05dedacdc565e2 to your computer and use it in GitHub Desktop.
[OpenCV] Web Streaming from IP camera with Flask
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# import the necessary packages | |
from pyimagesearch.motion_detection import SingleMotionDetector | |
from imutils.video import VideoStream | |
from flask import Response, Flask, render_template | |
import threading | |
import argparse | |
import datetime, time | |
import imutils | |
import cv2 | |
# initialize the output frame and a lock used to ensure thread-safe | |
# exchanges of the output frames (useful when multiple browsers/tabs are viewing the stream) | |
outputFrame = None | |
lock = threading.Lock() | |
# initialize a flask object | |
app = Flask(__name__) | |
# initialize the video stream and allow the camera sensor to | |
# warmup | |
# vs = VideoStream(usePiCamera=1).start() | |
# vs = VideoStream(src=0).start() | |
source = "rtsp://admin:[email protected]/profile2/media.smp" | |
cap = cv2.VideoCapture(source) | |
time.sleep(2.0) | |
@app.route("/") | |
def index(): | |
# return the rendered template | |
return render_template("index.html") | |
def stream(frameCount): | |
global outputFrame, lock | |
while True: | |
ret_val, frame = cap.read() | |
frame = cv2.resize(frame, (640, 360)) | |
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | |
gray = cv2.GaussianBlur(gray, (7,7), 0) | |
with lock: | |
outputFrame = frame.copy() | |
def detect_motion(frameCount): | |
# grab global references to the video stream, output frame, and lock variables | |
# global vs, outputFrame, lock | |
global outputFrame, lock | |
# initialize the motion detector and the total number of frames | |
# read thus far | |
md = SingleMotionDetector.SingleMotionDetector(accumWeight=0.1) | |
total = 0 | |
# loop over frames from the video stream | |
while True: | |
# read the next frame from the video stream, resize it, | |
# convert the frame to grayscale, and blur it | |
# frame = vs.read() | |
ret_val, frame = cap.read() | |
# frame = imutils.resize(frame, width=400) | |
frame = cv2.resize(frame, (640,360)) | |
# gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | |
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | |
gray = cv2.GaussianBlur(gray, (7, 7), 0) | |
# grab the current timestamp and draw it on the frame | |
timestamp = datetime.datetime.now() | |
cv2.putText(frame, timestamp.strftime( | |
"%A %d %B %Y %I:%M:%S%p"), (10, frame.shape[0] - 10), | |
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1) | |
# if the total number of frames has reached a sufficient | |
# number to construct a reasonable background model, then | |
# continue to process the frame | |
if total > frameCount: | |
# detect motion in the image | |
motion = md.detect(gray) | |
# check to see if motion was found in the frame | |
if motion is not None: | |
# unpack the tuple and draw the box surrounding the | |
# "motion area" on the output frame | |
(thresh, (minX, minY, maxX, maxY)) = motion | |
cv2.rectangle(frame, (minX, minY), (maxX, maxY), | |
(0, 0, 255), 2) | |
# update the background model and increment the total number | |
# of frames read thus far | |
md.update(gray) | |
total += 1 | |
# acquire the lock, set the output frame, and release the | |
# lock | |
with lock: | |
# outputFrame = frame.copy() | |
outputFrame = frame.copy() | |
def generate(): | |
# grab global references to the output frame and lock variables | |
global outputFrame, lock | |
# loop over frames from the output stream | |
while True: | |
# wait until the lock is acquired | |
with lock: | |
# check if the output frame is available, otherwise skip | |
# the iteration of the loop | |
if outputFrame is None: | |
continue | |
# encode the frame in JPEG format | |
(flag, encodedImage) = cv2.imencode(".jpg", outputFrame) | |
# ensure the frame was successfully encoded | |
if not flag: | |
continue | |
# yield the output frame in the byte format | |
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + | |
bytearray(encodedImage) + b'\r\n') | |
@app.route("/video_feed") | |
def video_feed(): | |
# return the response generated along with the specific media | |
# type (mime type) | |
return Response(generate(), | |
mimetype = "multipart/x-mixed-replace; boundary=frame") | |
# check to see if this is the main thread of execution | |
if __name__ == '__main__': | |
# construct the argument parser and parse command line arguments | |
ap = argparse.ArgumentParser() | |
ap.add_argument("-i", "--ip", type=str, required=True, | |
help="ip address of the device") | |
ap.add_argument("-o", "--port", type=int, required=True, | |
help="ephemeral port number of the server (1024 to 65535)") | |
ap.add_argument("-f", "--frame-count", type=int, default=32, | |
help="# of frames used to construct the background model") | |
args = vars(ap.parse_args()) | |
# start a thread that will perform motion detection | |
# t = threading.Thread(target=detect_motion, args=(args["frame_count"],)) | |
# t.daemon = True | |
# t.start() | |
t = threading.Thread(target=stream, args=(args["frame_count"],)) | |
t.daemon = True | |
t.start() | |
# start the flask app | |
app.run(host=args["ip"], port=args["port"], debug=True, | |
threaded=True, use_reloader=False) | |
# release the video stream pointer | |
cap.release() | |
cap.stop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment