-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
148 lines (111 loc) · 4.55 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python3
"""
Reference: <https://github.com/methylDragon/opencv-motion-detector>
"""
from __future__ import annotations
import sys
import cv2
import imutils
import numpy as np
device_index = int(sys.argv[1]) if len(sys.argv) > 1 else 0
# =============================================================================
# USER-SET PARAMETERS
# =============================================================================
# Number of frames to pass before changing the frame to compare the current
# frame against
FRAMES_TO_PERSIST = 10
# Minimum boxed area for a detected motion to count as actual motion
# Use to filter out noise or small objects
MIN_SIZE_FOR_MOVEMENT = 2000
# Minimum length of time where no motion is detected it should take
# (in program cycles) for the program to declare that there is no movement
MOVEMENT_DETECTED_PERSISTENCE = 100
# =============================================================================
# CORE PROGRAM
# =============================================================================
# Create capture object
cap = cv2.VideoCapture(device_index) # Flush the stream
cap.release()
cap = cv2.VideoCapture(device_index) # Then start the webcam
# Init frame variables
first_frame = None
next_frame = None
# Init display font and timeout counters
font = cv2.FONT_HERSHEY_SIMPLEX
delay_counter = 0
movement_persistent_counter = 0
# LOOP!
while True:
# Set transient motion detected as false
transient_movement_flag = False
# Read frame
ret, frame = cap.read()
text = "Unoccupied"
# If there's an error in capturing
if not ret:
print("CAPTURE ERROR")
continue
# Resize and save a greyscale version of the image
frame = imutils.resize(frame, width=750)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Blur it to remove camera noise (reducing false positives)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
# If the first frame is nothing, initialise it
if first_frame is None:
first_frame = gray
delay_counter += 1
# Otherwise, set the first frame to compare as the previous frame
# But only if the counter reaches the appriopriate value
# The delay is to allow relatively slow motions to be counted as large
# motions if they're spread out far enough
if delay_counter > FRAMES_TO_PERSIST:
delay_counter = 0
first_frame = next_frame
# Set the next frame to compare (the current frame)
next_frame = gray
# Compare the two frames, find the difference
frame_delta = cv2.absdiff(first_frame, next_frame)
thresh = cv2.threshold(frame_delta, 25, 255, cv2.THRESH_BINARY)[1]
# Fill in holes via dilate(), and find contours of the thesholds
thresh = cv2.dilate(thresh, None, iterations=2)
cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# loop over the contours
for c in cnts:
# Save the coordinates of all found contours
(x, y, w, h) = cv2.boundingRect(c)
# If the contour is too small, ignore it, otherwise, there's transient
# movement
if cv2.contourArea(c) > MIN_SIZE_FOR_MOVEMENT:
transient_movement_flag = True
# Draw a rectangle around big enough movements
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
# The moment something moves momentarily, reset the persistent
# movement timer.
if transient_movement_flag:
movement_persistent_flag = True
movement_persistent_counter = MOVEMENT_DETECTED_PERSISTENCE
# As long as there was a recent transient movement, say a movement
# was detected
if movement_persistent_counter > 0:
text = "Movement Detected " + str(movement_persistent_counter)
movement_persistent_counter -= 1
else:
text = "No Movement Detected"
# Print the text on the screen, and display the raw and processed video
# feeds
cv2.putText(frame, str(text), (10, 35), font, 0.75, (255, 255, 255), 2, cv2.LINE_AA)
# For if you want to show the individual video frames
# cv2.imshow("frame", frame)
# cv2.imshow("delta", frame_delta)
# Convert the frame_delta to color for splicing
frame_delta = cv2.cvtColor(frame_delta, cv2.COLOR_GRAY2BGR)
# Splice the two video frames together to make one long horizontal one
cv2.imshow("frame", np.hstack((frame_delta, frame)))
# Interrupt trigger by pressing q to quit the open CV program
ch = cv2.waitKey(1)
if ch & 0xFF == ord('q'):
break
# Cleanup when closed
cv2.waitKey(0)
cv2.destroyAllWindows()
cap.release()