Skip to content
This repository has been archived by the owner on Jan 3, 2023. It is now read-only.

Direct camera input and saving the video with some other modification. #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions examples/motion-heatmap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ This sample application is useful to see movement patterns over time. For exampl
* Python\* 2.7 or greater
* OpenCV version 3.3.0 or greater
* The vtest.avi video from https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi
* Directly use camera input `cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)`

## Setup
1. You need the extra modules installed for the MOG background subtractor. This tutorial was tested on Windows\*, and the easiest way to install it was using:
```
pip install opencv-contrib-python
```
2. Download the vtest.avi video from https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi and put it in the same folder as the python script.
`NOTE`: Not required to install opencv-contrib-python, if using opencv-python v4.2.0.

2. Download the vtest.avi video from https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi and put it in the same folder as the python script. `cap = cv2.VideoCapture('vtest.avi', cv2.CAP_DSHOW)`
3. Run the python script. You should see a diff-overlay.jpg when it's done.

![](images/diff-overlay.jpg)
Expand All @@ -33,11 +36,15 @@ Note: the docs are out of date, and the propoer way to initialize is
```
cv2.bgsegm.createBackgroundSubtractorMOG()
```
`for opencv-python v4.2.0`
```
cv2.createBackgroundSubtractorMOG2()
```
* cv2.threshold() - https://docs.opencv.org/3.3.1/d7/d4d/tutorial_py_thresholding.html
* cv2.add() - https://docs.opencv.org/3.2.0/d0/d86/tutorial_py_image_arithmetics.html
* cv2.applyColorMap() - https://docs.opencv.org/3.0-beta/modules/imgproc/doc/colormaps.html
* cv2.addWeighted() - https://docs.opencv.org/3.2.0/d0/d86/tutorial_py_image_arithmetics.html

The application takes each frame and first applies background subtraction using the cv2.bgsegm.createBackgroundSubtractorMOG() object to create a mask. A threshold is then applied to the mask to remove small amounts of movement, and also to set the accumulation value for each iteration. The result of the threshold is added to an accumulation image (one that starts out at all zero and gets added to each iteration without removing anything), which is what records the motion. At the very end, a color map is applied to the accumulated image so it's easier to see the motion. This colored imaged is then combined with a copy of the first frame using cv2.addWeighted to accomplish the overlay.
The application takes each frame and first applies background subtraction using the cv2.createBackgroundSubtractorMOG2() object to create a mask. A threshold is then applied to the mask to remove small amounts of movement, and also to set the accumulation value for each iteration. The result of the threshold is added to an accumulation image (one that starts out at all zero and gets added to each iteration without removing anything), which is what records the motion. At the very end, a color map is applied to the accumulated image so it's easier to see the motion. This colored imaged is then combined with a copy of the first frame using cv2.addWeighted to accomplish the overlay.

IMPORTANT NOTICE: This software is sample software. It is not designed or intended for use in any medical, life-saving or life-sustaining systems, transportation systems, nuclear systems, or for any other mission-critical application in which the failure of the system could lead to critical injury or death. The software may not be fully tested and may contain bugs or errors; it may not be intended or suitable for commercial release. No regulatory approvals for the software have been obtained, and therefore software may not be certified for use in certain countries or environments.
130 changes: 65 additions & 65 deletions examples/motion-heatmap/motion-heatmap.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,81 @@
'''
'''
Copyright (c) 2017 Intel Corporation.
Licensed under the MIT license. See LICENSE file in the project root for full license information.
'''

import numpy as np
import cv2
import copy
import cv2
import numpy as np

def main():
cap = cv2.VideoCapture('vtest.avi')
# pip install opencv-contrib-python
fgbg = cv2.bgsegm.createBackgroundSubtractorMOG()

# number of frames is a variable for development purposes, you can change the for loop to a while(cap.isOpened()) instead to go through the whole video
num_frames = 350
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
for i in range(0, num_frames):
'''
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):
ret, frame = cap.read()
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:
ret, frame = cap.read() # read a frame
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # convert to grayscale

fgmask = fgbg.apply(gray) # remove the background

# for testing purposes, show the result of the background subtraction
# cv2.imshow('diff-bkgnd-frame', fgmask)

# 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 = 2
maxValue = 2
ret, th1 = cv2.threshold(fgmask, thresh, maxValue, cv2.THRESH_BINARY)
# for testing purposes, show the threshold image
# cv2.imwrite('diff-th1.jpg', th1)

# add to the accumulated image
accum_image = cv2.add(accum_image, th1)
# for testing purposes, show the accumulated image
# cv2.imwrite('diff-accum.jpg', accum_image)

# for testing purposes, control frame by frame
# raw_input("press any key to continue")

# for testing purposes, show the current frame
# cv2.imshow('frame', gray)
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)

if cv2.waitKey(1) & 0xFF == ord('q'):
ch_ = cv2.waitKey(1)
if ch_ == 27 or ch_ == ord('q') or ch_ == ord('Q'):
break

# apply a color map
# COLORMAP_PINK also works well, COLORMAP_BONE is acceptable if the background is dark
color_image = im_color = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT)
# for testing purposes, show the colorMap image
# cv2.imwrite('diff-color.jpg', color_image)

# overlay the color mapped image to the first frame
result_overlay = cv2.addWeighted(first_frame, 0.7, color_image, 0.7, 0)

# save the final overlay image
cv2.imwrite('diff-overlay.jpg', result_overlay)

# cleanup
cap.release()
out.release()
cv2.destroyAllWindows()

if __name__=='__main__':
main()

if __name__ == '__main__':
main()