control-freak-ide/data/motion_tracker.py
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

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()