Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python3 #24

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,27 @@
import imutils
import time
import numpy as np
import datetime

video_res = (640, 480)
object_det_res = (320, 240)

video_frame_rate = 30
video_out_dir = '/home/pi/'

background_frame = None
background_update_rate = 120 # 2 mins. Period to update background frame for motion detection.
last_back_update = None
motion_det_min_area = 2000 # Regulate motion detection sensitivity. Smaller value - greater sensitivity.

class VideoCamera(object):
def __init__(self, flip = False):
self.vs = PiVideoStream().start()
self.vs = PiVideoStream(resolution=video_res, framerate=video_frame_rate).start()
self.flip = flip

self.x_coef = float(video_res[0]) / object_det_res[0] # needed to translate between frame sizes
self.y_coef = float(video_res[1]) / object_det_res[1]

time.sleep(2.0)

def __del__(self):
Expand All @@ -23,10 +39,50 @@ def get_frame(self):
ret, jpeg = cv2.imencode('.jpg', frame)
return jpeg.tobytes()

def motion_detection(self):
frame = self.flip_if_needed(self.vs.read()) #grabbing frame

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #graying it
gray = cv2.GaussianBlur(gray, (5, 5), 0) #blurring

global background_frame
global last_back_update
global background_update_rate
global motion_det_min_area

if (background_frame is None) or (time.time() - last_back_update) > background_update_rate:
background_frame = gray
last_back_update = time.time()
return None, False

frameDelta = cv2.absdiff(background_frame, gray)
thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]

thresh = cv2.dilate(thresh, None, iterations=2) #fill the holes
(_, cnts, _) = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #find contours of the objects

found_something = False

return_obj = frame
# return_obj = gray

for c in cnts:
# if the contour is too small, ignore it
if cv2.contourArea(c) < motion_det_min_area:
continue

found_something = True
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(return_obj, (x, y), (x + w, y + h), (153, 0, 204), 2) # different color rectangle for motion detect

ret, jpeg = cv2.imencode('.jpg', return_obj)
return (jpeg.tobytes(), found_something)

def get_object(self, classifier):
found_objects = False
frame = self.flip_if_needed(self.vs.read()).copy()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.resize(gray, object_det_res, interpolation=cv2.INTER_AREA)

objects = classifier.detectMultiScale(
gray,
Expand All @@ -41,9 +97,27 @@ def get_object(self, classifier):

# Draw a rectangle around the objects
for (x, y, w, h) in objects:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.rectangle(frame
, (int(self.x_coef * x), int(self.y_coef * y))
, (int(self.x_coef * x + self.x_coef * w), int(self.y_coef * y + self.y_coef * h))
, (0, 255, 0)
, 2)

ret, jpeg = cv2.imencode('.jpg', frame)
return (jpeg.tobytes(), found_objects)

def capture_video(self, send_video_len):
video_loc = video_out_dir + datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S") +'.avi'
fourcc = cv2.VideoWriter_fourcc(*'X264')
out = cv2.VideoWriter(video_loc, fourcc, video_frame_rate, video_res)

start_time = time.time()
while (time.time() - start_time) <= send_video_len:
frame = self.flip_if_needed(self.vs.read())
#(_, _, frame) = self.motion_detection()
out.write(frame)
out.release()

return video_loc


43 changes: 38 additions & 5 deletions mail.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
from os.path import basename
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
from email.mime.image import MIMEImage

# Email you want to send the update from (only works with gmail)
fromEmail = '[email protected]'
Expand All @@ -20,19 +22,50 @@ def sendEmail(image):
msgRoot.preamble = 'Raspberry pi security camera update'

msgAlternative = MIMEMultipart('alternative')
msgRoot.attach(msgAlternative)
msgText = MIMEText('Smart security cam found object')
msgText = MIMEText('Smart security cam found object.')
msgAlternative.attach(msgText)

msgText = MIMEText('<img src="cid:image1">', 'html')
msgAlternative.attach(msgText)

msgImage = MIMEImage(image)
msgImage.add_header('Content-ID', '<image1>')

msgRoot.attach(msgAlternative)
msgRoot.attach(msgImage)

smtp = smtplib.SMTP('smtp.gmail.com', 587)
smtp.starttls()
smtp.login(fromEmail, fromEmailPassword)
smtp.sendmail(fromEmail, toEmail, msgRoot.as_string())
smtp.quit()

def sendVideoEmail(vid, keep_video_after_sending):
msgRoot = MIMEMultipart('related')
msgRoot['Subject'] = 'Security Update'
msgRoot['From'] = fromEmail
msgRoot['To'] = toEmail
msgRoot.preamble = 'Raspberry pi security camera update'

textStr = 'Smart security cam finished recording video.'
if keep_video_after_sending:
textStr += ' The video is saved on your Raspberry Pi at location: ' + vid

msgAlternative = MIMEMultipart('alternative')
msgText = MIMEText(textStr)
msgAlternative.attach(msgText)

with open(vid, "rb") as fil:
part = MIMEApplication(fil.read(), Name=basename(vid))

# After the file is closed
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(vid)

msgRoot.attach(msgAlternative)
msgRoot.attach(part)

smtp = smtplib.SMTP('smtp.gmail.com', 587)
smtp.starttls()
smtp.login(fromEmail, fromEmailPassword)
smtp.sendmail(fromEmail, toEmail, msgRoot.as_string())
smtp.quit()
48 changes: 35 additions & 13 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import cv2
import sys
from mail import sendEmail
from mail import sendEmail, sendVideoEmail
from flask import Flask, render_template, Response
from camera import VideoCamera
from flask_basicauth import BasicAuth
import time
import threading
import os

email_update_interval = 600 # sends an email only once in this time interval
video_camera = VideoCamera(flip=True) # creates a camera object, flip vertically
video_camera = VideoCamera(flip=False) # creates a camera object, flip vertically
object_classifier = cv2.CascadeClassifier("models/fullbody_recognition_model.xml") # an opencv classifier
use_motion_detection = False

send_video = True
send_video_len = 30 #length of the video attached to the second email
keep_video_after_sending = False

# App Globals (do not edit)
app = Flask(__name__)
Expand All @@ -21,17 +27,33 @@
last_epoch = 0

def check_for_objects():
global last_epoch
while True:
try:
frame, found_obj = video_camera.get_object(object_classifier)
if found_obj and (time.time() - last_epoch) > email_update_interval:
last_epoch = time.time()
print "Sending email..."
sendEmail(frame)
print "done!"
except:
print "Error sending email: ", sys.exc_info()[0]
global last_epoch
while True:
try:
global use_motion_detection
if use_motion_detection:
frame, found_obj = video_camera.motion_detection()
if found_obj:
# motion detection is fired only if detected in two frames in a row (reduces false positive)
frame, found_obj = video_camera.motion_detection()
else:
frame, found_obj = video_camera.get_object(object_classifier)
if found_obj and (time.time() - last_epoch) > email_update_interval:
last_epoch = time.time()
print ("Sending email...")
sendEmail(frame)
print ("done!")
if send_video:
print ("Capturing video...")
vid = video_camera.capture_video(send_video_len)
print ("Sending video email...")
sendVideoEmail(vid, keep_video_after_sending)
print ("done!")
if not keep_video_after_sending:
os.remove(vid)
print ("Video file removed")
except:
print ("Error sending email: ", sys.exc_info()[0])

@app.route('/')
@basic_auth.required
Expand Down