commit c51424e0699b502388aafb22f7cbd60857fc53db Author: Braeden Sowinski Date: Thu Feb 17 19:58:47 2022 -0800 First Commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..05285af --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# simple-security-camera-page diff --git a/pyimagesearch/__init__.py b/pyimagesearch/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyimagesearch/__pycache__/__init__.cpython-310.pyc b/pyimagesearch/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..34f93a9 Binary files /dev/null and b/pyimagesearch/__pycache__/__init__.cpython-310.pyc differ diff --git a/pyimagesearch/motion_detection/__init__.py b/pyimagesearch/motion_detection/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyimagesearch/motion_detection/__pycache__/__init__.cpython-310.pyc b/pyimagesearch/motion_detection/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..5d4894a Binary files /dev/null and b/pyimagesearch/motion_detection/__pycache__/__init__.cpython-310.pyc differ diff --git a/pyimagesearch/motion_detection/__pycache__/singlemotiondetector.cpython-310.pyc b/pyimagesearch/motion_detection/__pycache__/singlemotiondetector.cpython-310.pyc new file mode 100644 index 0000000..d55ad2e Binary files /dev/null and b/pyimagesearch/motion_detection/__pycache__/singlemotiondetector.cpython-310.pyc differ diff --git a/pyimagesearch/motion_detection/singlemotiondetector.py b/pyimagesearch/motion_detection/singlemotiondetector.py new file mode 100644 index 0000000..d66fff0 --- /dev/null +++ b/pyimagesearch/motion_detection/singlemotiondetector.py @@ -0,0 +1,57 @@ +# import the necessary packages +import numpy as np +import imutils +import cv2 + +class SingleMotionDetector: + def __init__(self, accumWeight=0.5): + # store the accumulated weight factor + self.accumWeight = accumWeight + + # initialize the background model + self.bg = None + + def update(self, image): + # if the background model is None, initialize it + if self.bg is None: + self.bg = image.copy().astype("float") + return + + # update the background model by accumulating the weighted + # average + cv2.accumulateWeighted(image, self.bg, self.accumWeight) + + def detect(self, image, tVal=25): + # compute the absolute difference between the background model + # and the image passed in, then threshold the delta image + delta = cv2.absdiff(self.bg.astype("uint8"), image) + thresh = cv2.threshold(delta, tVal, 255, cv2.THRESH_BINARY)[1] + + # perform a series of erosions and dilations to remove small + # blobs + thresh = cv2.erode(thresh, None, iterations=2) + thresh = cv2.dilate(thresh, None, iterations=2) + + # find contours in the thresholded image and initialize the + # minimum and maximum bounding box regions for motion + cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, + cv2.CHAIN_APPROX_SIMPLE) + cnts = imutils.grab_contours(cnts) + (minX, minY) = (np.inf, np.inf) + (maxX, maxY) = (-np.inf, -np.inf) + + # if no contours were found, return None + if len(cnts) == 0: + return None + + # otherwise, loop over the contours + for c in cnts: + # compute the bounding box of the contour and use it to + # update the minimum and maximum bounding box regions + (x, y, w, h) = cv2.boundingRect(c) + (minX, minY) = (min(minX, x), min(minY, y)) + (maxX, maxY) = (max(maxX, x + w), max(maxY, y + h)) + + # otherwise, return a tuple of the thresholded image along + # with bounding box + return (thresh, (minX, minY, maxX, maxY)) diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..3310b98 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,23 @@ + + + Video Surveillance + + + +

Video Surveillance

+
+ +
+ + \ No newline at end of file diff --git a/webstreaming.py b/webstreaming.py new file mode 100644 index 0000000..98a1de7 --- /dev/null +++ b/webstreaming.py @@ -0,0 +1,127 @@ +# import the necessary packages +from pyimagesearch.motion_detection.singlemotiondetector import SingleMotionDetector +from imutils.video import VideoStream +from flask import Response +from flask import Flask +from flask import render_template +import threading +import argparse +import datetime +import imutils +import time +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() +time.sleep(2.0) + +@app.route("/") +def index(): + # return the rendered template + return render_template("index.html") + +def detect_motion(frameCount): + # grab global references to the video stream, output frame, and + # lock variables + global vs, outputFrame, lock + + # initialize the motion detector and the total number of frames + # read thus far + md = 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() + frame = imutils.resize(frame, width=400) + 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() + +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__': + # start a thread that will perform motion detection + t = threading.Thread(target=detect_motion, args=(32,)) + t.daemon = True + t.start() + + # start the flask app + app.run(host="0.0.0.0", port=8080, debug=False, + threaded=True, use_reloader=False) + +# release the video stream pointer +vs.stop() \ No newline at end of file