130 lines
5.2 KiB
Python
130 lines
5.2 KiB
Python
import cv2.cv as cv
|
|
from datetime import datetime
|
|
import time
|
|
import paho.mqtt.client as mqtt
|
|
|
|
def on_connect(client, userdata, flags, rc):
|
|
print("Connected with result code "+str(rc))
|
|
|
|
# Subscribing in on_connect() means that if we lose the connection and
|
|
# reconnect then subscriptions will be renewed.
|
|
client.subscribe("$SYS/#")
|
|
|
|
# The callback for when a PUBLISH message is received from the server.
|
|
def on_message(client, userdata, msg):
|
|
print(msg.topic+" "+str(msg.payload))
|
|
|
|
client = mqtt.Client()
|
|
client.on_connect = on_connect
|
|
client.on_message = on_message
|
|
|
|
client.connect("localhost", 1883, 60)
|
|
|
|
class MotionDetectorInstantaneous():
|
|
|
|
def onChange(self, val): #callback when the user change the detection threshold
|
|
self.threshold = val
|
|
|
|
def __init__(self,threshold=8, doRecord=True, showWindows=True):
|
|
self.writer = None
|
|
self.font = None
|
|
self.doRecord=doRecord #Either or not record the moving object
|
|
self.show = showWindows #Either or not show the 2 windows
|
|
self.frame = None
|
|
|
|
self.capture=cv.CaptureFromCAM(0)
|
|
self.frame = cv.QueryFrame(self.capture) #Take a frame to init recorder
|
|
if doRecord:
|
|
self.initRecorder()
|
|
|
|
self.frame1gray = cv.CreateMat(self.frame.height, self.frame.width, cv.CV_8U) #Gray frame at t-1
|
|
cv.CvtColor(self.frame, self.frame1gray, cv.CV_RGB2GRAY)
|
|
|
|
#Will hold the thresholded result
|
|
self.res = cv.CreateMat(self.frame.height, self.frame.width, cv.CV_8U)
|
|
|
|
self.frame2gray = cv.CreateMat(self.frame.height, self.frame.width, cv.CV_8U) #Gray frame at t
|
|
|
|
self.width = self.frame.width
|
|
self.height = self.frame.height
|
|
self.nb_pixels = self.width * self.height
|
|
self.threshold = threshold
|
|
self.isRecording = False
|
|
self.trigger_time = 0 #Hold timestamp of the last detection
|
|
|
|
if showWindows:
|
|
cv.NamedWindow("Image")
|
|
cv.CreateTrackbar("Detection treshold: ", "Image", self.threshold, 100, self.onChange)
|
|
|
|
def initRecorder(self): #Create the recorder
|
|
codec = cv.CV_FOURCC('M', 'J', 'P', 'G') #('W', 'M', 'V', '2')
|
|
self.writer=cv.CreateVideoWriter(datetime.now().strftime("%b-%d_%H_%M_%S")+".wmv", codec, 5, cv.GetSize(self.frame), 1)
|
|
#FPS set to 5 because it seems to be the fps of my cam but should be ajusted to your needs
|
|
self.font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 1, 1, 0, 2, 8) #Creates a font
|
|
|
|
def run(self):
|
|
started = time.time()
|
|
while True:
|
|
|
|
curframe = cv.QueryFrame(self.capture)
|
|
instant = time.time() #Get timestamp o the frame
|
|
|
|
self.processImage(curframe) #Process the image
|
|
|
|
if not self.isRecording:
|
|
if self.somethingHasMoved():
|
|
self.trigger_time = instant #Update the trigger_time
|
|
if instant > started +5:#Wait 5 second after the webcam start for luminosity adjusting etc..
|
|
print datetime.now().strftime("%b %d, %H:%M:%S"), "Something is moving !"
|
|
if self.doRecord: #set isRecording=True only if we record a video
|
|
self.isRecording = True
|
|
else:
|
|
if instant >= self.trigger_time +10: #Record during 10 seconds
|
|
print datetime.now().strftime("%b %d, %H:%M:%S"), "Stop recording"
|
|
self.isRecording = False
|
|
client.publish("camMoveStopped","{}")
|
|
else:
|
|
cv.PutText(curframe,datetime.now().strftime("%b %d, %H:%M:%S"), (25,30),self.font, 0) #Put date on the frame
|
|
cv.WriteFrame(self.writer, curframe) #Write the frame
|
|
|
|
if self.show:
|
|
cv.ShowImage("Image", curframe)
|
|
cv.ShowImage("Res", self.res)
|
|
|
|
cv.Copy(self.frame2gray, self.frame1gray)
|
|
c=cv.WaitKey(1) % 0x100
|
|
if c==27 or c == 10: #Break if user enters 'Esc'.
|
|
break
|
|
|
|
def processImage(self, frame):
|
|
cv.CvtColor(frame, self.frame2gray, cv.CV_RGB2GRAY)
|
|
|
|
#Absdiff to get the difference between to the frames
|
|
cv.AbsDiff(self.frame1gray, self.frame2gray, self.res)
|
|
|
|
#Remove the noise and do the threshold
|
|
cv.Smooth(self.res, self.res, cv.CV_BLUR, 5,5)
|
|
cv.MorphologyEx(self.res, self.res, None, None, cv.CV_MOP_OPEN)
|
|
cv.MorphologyEx(self.res, self.res, None, None, cv.CV_MOP_CLOSE)
|
|
cv.Threshold(self.res, self.res, 10, 255, cv.CV_THRESH_BINARY_INV)
|
|
|
|
def somethingHasMoved(self):
|
|
|
|
|
|
nb=0 #Will hold the number of black pixels
|
|
|
|
for x in range(self.height): #Iterate the hole image
|
|
for y in range(self.width):
|
|
if self.res[x,y] == 0.0: #If the pixel is black keep it
|
|
nb += 1
|
|
avg = (nb*100.0)/self.nb_pixels #Calculate the average of black pixel in the image
|
|
|
|
if avg > self.threshold:#If over the ceiling trigger the alarm
|
|
client.publish("camMove","{\"level\":" + str(avg) + "}")
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
if __name__=="__main__":
|
|
detect = MotionDetectorInstantaneous(doRecord=True)
|
|
detect.run() |