I am trying to create a motion detecting alarm by using the cv2.createBackgroundSubtractorMOG2() function to check for moving objects and sound an alarm. This is my code:
import cv2
import numpy as np
import winsound
kernel=np.ones((5,5),np.uint8)
cap=cv2.VideoCapture(0)
fgbg=cv2.createBackgroundSubtractorMOG2()
while True:
ret,frame=cap.read()
fgmask=fgbg.apply(frame) #creates binary image of moving objects
fgmask=cv2.erode(fgmask,kernel,iterations=1) #erosion to remove noise
counter=np.sum(fgmask==255) # counts the number of white pixels in the mask
cv2.imshow('img',fgmask)
cv2.imshow('frame',frame)
print(counter)
if counter>50: #sounds an alarm if the number of white pixels is greater than a certain limit
winsound.Beep(1000,2000)
print("beep")
if (cv2.waitKey(1) & 0xFF)==ord('q'):
break
cap.release()
The problem is caused as the program is paused for 2 seconds when the winsound.Beep function is called and after it resumes the program glitches and repeatedly starts beeping.
If I remove the winsound.Beep function the program works as expected. Why does this happen?
The reason you're experiencing such problem is because winsound.Beep(1000,2000)
is a blocking operation and should be runned on a separate thread.
In order for you to accomplish what you're trying to do, here the working code:
import cv2
import numpy as np
import winsound
import threading
kernel=np.ones((5,5),np.uint8)
cap=cv2.VideoCapture(0)
fgbg=cv2.createBackgroundSubtractorMOG2()
def playSound():
winsound.Beep(1000,2000)
while True:
ret,frame=cap.read()
fgmask=fgbg.apply(frame)
fgmask=cv2.erode(fgmask,kernel,iterations=1)
counter=np.sum(fgmask==255)
cv2.imshow('img',fgmask)
cv2.imshow('frame',frame)
if counter>50:
# Run the playSound function on a separate thread
t = threading.Thread(target=playSound)
t.start()
if (cv2.waitKey(1) & 0xFF)==ord('q'):
break
cap.release()
Hope this helps