This repository was archived by the owner on Jan 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 210
Expand file tree
/
Copy pathmotion-heatmap.py
More file actions
81 lines (66 loc) · 3.41 KB
/
motion-heatmap.py
File metadata and controls
81 lines (66 loc) · 3.41 KB
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
'''
Copyright (c) 2017 Intel Corporation.
Licensed under the MIT license. See LICENSE file in the project root for full license information.
'''
import copy
import cv2
import numpy as np
def main():
"""
This method is used to see movement patterns over time. It creates a heatmap of the movements.
For example, it could be used to see the usage of entrances to a factory floor over time,
or patterns of shoppers in a store.
"""
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
out = cv2.VideoWriter('motion_heatmap_output.avi', cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'), 30, (int(cap.get(3)), int(cap.get(4))))
# out = cv2.VideoWriter('output.avi', cv2.VideoWriter_fourcc(*'XVID'), 40, (int(cap.get(3)), int(cap.get(4)))) # Also works
fgbg = cv2.createBackgroundSubtractorMOG2()
first_iteration_indicator = 1
while cap.isOpened():
ret, frame = cap.read()
if ret:
'''
There are some important reasons this if statement exists:
-in the first run there is no previous frame, so this accounts for that
-the first frame is saved to be used for the overlay after the accumulation has occurred
-the height and width of the video are used to create an empty image for accumulation (accum_image)
'''
if first_iteration_indicator == 1:
first_frame = copy.deepcopy(frame)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
height, width = gray.shape[:2]
accum_image = np.zeros((height, width), np.uint8)
first_iteration_indicator = 0
else:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # convert to grayscale
fgmask = fgbg.apply(gray) # remove the background
cv2.imshow('diff-bkgnd-frame', fgmask) # result of the background subtraction
# apply a binary threshold only keeping pixels above thresh and setting the result to maxValue.
# If you want motion to be picked up more, increase the value of maxValue.
# To pick up the least amount of motion over time, set maxValue = 1
thresh = 1
max_value = 5
ret, th_img = cv2.threshold(fgmask, thresh, max_value, cv2.THRESH_BINARY)
# add to the accumulated image
accum_image = cv2.add(accum_image, th_img)
cv2.imshow('diff-accum', accum_image) # accumulated frame
cv2.imshow('frame', gray) # current frame
# apply a color map
# COLORMAP_PINK also works well, COLORMAP_BONE is acceptable if the background is dark
color_image = cv2.applyColorMap(accum_image, cv2.COLORMAP_INFERNO)
cv2.imshow('diff-color', color_image) # colorMap frame
# overlay the color mapped image to the first frame
result_overlay = cv2.addWeighted(first_frame, 0.7, color_image, 0.7, 0)
cv2.imshow('diff-overlay', result_overlay) # final overlay frame
cv2.imwrite('diff-overlay.png', result_overlay) # final overlay image
out.write(result_overlay)
else:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
ch_ = cv2.waitKey(1)
if ch_ == 27 or ch_ == ord('q') or ch_ == ord('Q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()