├── .DS_Store ├── README.md ├── diff-bkgnd-frame.jpg ├── diff-overlay.jpg ├── frame.jpg ├── heatmap_gif.gif ├── input.mp4 ├── make_video.py ├── mall.mp4 ├── mask.jpg └── motion_heatmap.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # motion-heatmap-opencv 2 | A repository to store codes and supportive material to the omonimous [Medium](https://medium.com/p/fd806e8a2340) article. 3 | This code is an adaptation of the [Intel Motion Heatmap](https://github.com/intel-iot-devkit/python-cv-samples/tree/master/examples/motion-heatmap) 4 | 5 | ![](./heatmap_gif.gif) 6 | 7 | # Run 8 | Cone this repository, `cd` into the directory and run `python motion_heatmap.py `, if you want to use another video change the path in `motion_heatmap.py` in the `main()` function. 9 | 10 | # Requirements 11 | To run this script you will need python 3.6+ installed along with OpenCV 3.3.0+ and numpy. 12 | Make also sure to have installed the MOG background subtractor by running: 13 | 14 | `pip install opencv-contrib-python` 15 | 16 | # Enjoy! 17 | -------------------------------------------------------------------------------- /diff-bkgnd-frame.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/diff-bkgnd-frame.jpg -------------------------------------------------------------------------------- /diff-overlay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/diff-overlay.jpg -------------------------------------------------------------------------------- /frame.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/frame.jpg -------------------------------------------------------------------------------- /heatmap_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/heatmap_gif.gif -------------------------------------------------------------------------------- /input.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/input.mp4 -------------------------------------------------------------------------------- /make_video.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import os 3 | import re 4 | from progress.bar import Bar 5 | 6 | """ 7 | A utility function to merge together many frames into a video. 8 | 9 | """ 10 | 11 | 12 | def atoi(text): 13 | # A helper function to return digits inside text 14 | return int(text) if text.isdigit() else text 15 | 16 | 17 | def natural_keys(text): 18 | # A helper function to generate keys for sorting frames AKA natural sorting 19 | return [atoi(c) for c in re.split(r'(\d+)', text)] 20 | 21 | 22 | def make_video(image_folder, video_name): 23 | images = [img for img in os.listdir(image_folder)] 24 | images.sort(key=natural_keys) 25 | 26 | frame = cv2.imread(os.path.join(image_folder, images[0])) 27 | height, width, layers = frame.shape 28 | 29 | fourcc = cv2.VideoWriter_fourcc(*"MJPG") 30 | 31 | video = cv2.VideoWriter(video_name, fourcc, 30.0, (width, height)) 32 | bar = Bar('Creating Video', max=len(images)) 33 | 34 | for image in images: 35 | video.write(cv2.imread(os.path.join(image_folder, image))) 36 | bar.next() 37 | 38 | cv2.destroyAllWindows() 39 | video.release() 40 | 41 | for file in os.listdir(image_folder): 42 | os.remove(image_folder + file) 43 | -------------------------------------------------------------------------------- /mall.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/mall.mp4 -------------------------------------------------------------------------------- /mask.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robsannaa/motion-heatmap-opencv/248bb153ac70c51b3669095e6b6ea0b567f5cb60/mask.jpg -------------------------------------------------------------------------------- /motion_heatmap.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import copy 4 | from make_video import make_video 5 | from progress.bar import Bar 6 | 7 | 8 | def main(): 9 | capture = cv2.VideoCapture('input.mp4') 10 | background_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG() 11 | length = int(capture.get(cv2.CAP_PROP_FRAME_COUNT)) 12 | 13 | bar = Bar('Processing Frames', max=length) 14 | 15 | first_iteration_indicator = 1 16 | for i in range(0, length): 17 | 18 | ret, frame = capture.read() 19 | 20 | # If first frame 21 | if first_iteration_indicator == 1: 22 | 23 | first_frame = copy.deepcopy(frame) 24 | height, width = frame.shape[:2] 25 | accum_image = np.zeros((height, width), np.uint8) 26 | first_iteration_indicator = 0 27 | else: 28 | 29 | filter = background_subtractor.apply(frame) # remove the background 30 | cv2.imwrite('./frame.jpg', frame) 31 | cv2.imwrite('./diff-bkgnd-frame.jpg', filter) 32 | 33 | threshold = 2 34 | maxValue = 2 35 | ret, th1 = cv2.threshold(filter, threshold, maxValue, cv2.THRESH_BINARY) 36 | 37 | # add to the accumulated image 38 | accum_image = cv2.add(accum_image, th1) 39 | cv2.imwrite('./mask.jpg', accum_image) 40 | 41 | color_image_video = cv2.applyColorMap(accum_image, cv2.COLORMAP_SUMMER) 42 | 43 | video_frame = cv2.addWeighted(frame, 0.7, color_image_video, 0.7, 0) 44 | 45 | name = "./frames/frame%d.jpg" % i 46 | cv2.imwrite(name, video_frame) 47 | 48 | if cv2.waitKey(1) & 0xFF == ord('q'): 49 | break 50 | bar.next() 51 | 52 | bar.finish() 53 | 54 | make_video('./frames/', './output.avi') 55 | 56 | color_image = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT) 57 | result_overlay = cv2.addWeighted(first_frame, 0.7, color_image, 0.7, 0) 58 | 59 | # save the final heatmap 60 | cv2.imwrite('diff-overlay.jpg', result_overlay) 61 | 62 | # cleanup 63 | capture.release() 64 | cv2.destroyAllWindows() 65 | 66 | 67 | if __name__ == '__main__': 68 | main() 69 | --------------------------------------------------------------------------------