Skip to content

Instantly share code, notes, and snippets.

@mike-huls
Last active February 14, 2024 08:26
Show Gist options
  • Save mike-huls/372d968aa523484b8cca05844dfc8443 to your computer and use it in GitHub Desktop.
Save mike-huls/372d968aa523484b8cca05844dfc8443 to your computer and use it in GitHub Desktop.
import cv2
import numpy as np
from PIL import ImageGrab
def motion_detector_gist():
previous_frame = None
while True:
# 1. Load image; convert to RGB
img_brg = np.array(ImageGrab.grab())
img_rgb = cv2.cvtColor(src=img_brg, code=cv2.COLOR_BGR2RGB)
# 2. Prepare image; grayscale and blur
prepared_frame = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
prepared_frame = cv2.GaussianBlur(src=prepared_frame, ksize=(5, 5), sigmaX=0)
# 2. Calculate the difference
if (previous_frame is None):
# First frame; there is no previous one yet
previous_frame = prepared_frame
continue
# 3. calculate difference and update previous frame
diff_frame = cv2.absdiff(src1=previous_frame, src2=prepared_frame)
previous_frame = prepared_frame
# 4. Dilute the image a bit to make differences more seeable; more suitable for contour detection
kernel = np.ones((5, 5))
diff_frame = cv2.dilate(diff_frame, kernel, 1)
# 5. Only take different areas that are different enough (>20 / 255)
thresh_frame = cv2.threshold(src=diff_frame, thresh=20, maxval=255, type=cv2.THRESH_BINARY)[1]
# 6. Find and optionally draw contours
contours, _ = cv2.findContours(image=thresh_frame, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE)
# Comment below to stop drawing contours
cv2.drawContours(image=img_rgb, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=2, lineType=cv2.LINE_AA)
# Uncomment 6 lines below to stop drawing rectangles
# for contour in contours:
# if cv2.contourArea(contour) < 50:
# # too small: skip!
# continue
# (x, y, w, h) = cv2.boundingRect(contour)
# cv2.rectangle(img=img_rgb, pt1=(x, y), pt2=(x + w, y + h), color=(0, 255, 0), thickness=2)
cv2.imshow('Motion detector', img_rgb)
if (cv2.waitKey(30) == 27):
# out.release()
break
# Cleanup
cv2.destroyAllWindows()
if __name__ == "__main__":
motion_detector_gist()
@roastedmonk
Copy link

Can i get the full source code?

@mike-huls
Copy link
Author

he roastedmonk. check out the full source code plus accompanying article here

@DrJaymz
Copy link

DrJaymz commented Jun 23, 2022

he roastedmonk. check out the full source code plus accompanying article here

That's not the "full code", in fact, you will not be able to construct a working example from that document just fragments of how bits of the idea work - which limits its usefulness to just reference. So I would remove the term full-code if you're not going to post it.

@roastedmonk
Copy link

roastedmonk commented Jun 23, 2022 via email

@mike-huls
Copy link
Author

@DrJaymz
Just call the function in this gist with

if (name == "main"):
motion_detector_gist()

@AstroAndy74
Copy link

Nice function! The article explains it fully, and the code is complete bar being called.
Thanks

@batona
Copy link

batona commented Nov 17, 2022

Thank you for good example.
But could you be so kind to show the real working code, not a snippet. I tried to show my kid this example and it took 2 hours to get it working.

import cv2
import numpy as np
from PIL import ImageGrab

def motion_detector_gist():
......
motion_detector_gist()

@sz55net
Copy link

sz55net commented Dec 28, 2022

import cv2 import numpy as np from PIL import ImageGrab

Thank you @batona!

@lorenzua02
Copy link

lorenzua02 commented Mar 2, 2023

Please notice that this piece of code is repeated twice, you can safely delete one of the if

@mike-huls
Copy link
Author

Thank you @lorenzua02! I've fixed it!

@nearz
Copy link

nearz commented Apr 3, 2023

Thanks for the example. FYI, your article still has frame_count and the if statement where prepared_frame can never be reached.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment