I have the following code with which, I am trying to detect movements (ideally with adjustable threshold) in specific regions of a video (roi_masks). I am just doing something fatally wrong, because it returns false positive detections sometimes even if camera is completely covered (so black images are returned) or even when there is completely no movement at all (static room).
What am I doing wrong and what changes do I need to make to fix it?
NOTE: I need to work with cv2
, numpy
and picamera2
. My camera is NoIR version for night vision and I am using additional IR lens for night light.
import cv2
from picamera2 import Picamera2
import numpy as np
from datetime import datetime
import time
# Define the regions of interest (ROIs) as a list of NumPy arrays, each representing an irregular shape mask.
# For example, let's define two ROIs as irregular shapes.
# roi_masks = [
# np.array([[100, 100], [150, 200], [250, 200], [300, 100]], dtype=np.int32), # Polygon 1
# np.array([[350, 300], [400, 400], [500, 400], [550, 300]], dtype=np.int32), # Polygon 2
# ]
roi_masks = [
#np.array([[0, 0], [0, 1080], [1920, 1080], [1920, 0]], dtype=np.int32), # Polygon 1
#np.array([[350, 300], [400, 400], [500, 400], [550, 300]], dtype=np.int32), # Polygon 2
np.array([[50, 500], [120,1000], [500, 800], [600, 550]], dtype=np.int32), # Polygon 1
np.array([[950, 100], [1100, 400], [1800, 400], [1600, 200]], dtype=np.int32), # Polygon 2
]
IMG_DIMS = (1920, 1080)
# Threshold for change detection (adjust this value as needed)
CHANGE_THRESHOLD = 25
# Background model
bg_subtractor = cv2.createBackgroundSubtractorMOG2()
# Function to check for motion
def check_for_motion(frame, prev_frame, threshold):
diff_frame = cv2.absdiff(frame, prev_frame)
motion = np.sum(diff_frame) > threshold
return motion
# Function to detect changes in the ROIs
def detect_changes(frame, prev_frame, roi_masks):
diff_frame = cv2.absdiff(frame, prev_frame)
roi_frames = []
for roi_mask in roi_masks:
mask = np.zeros_like(diff_frame)
cv2.fillPoly(mask, [roi_mask], 255)
roi_frame = cv2.bitwise_and(diff_frame, mask)
roi_frames.append(roi_frame)
return roi_frames
# Function to save the time string to a file
def save_time_to_file():
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open("change_detected.txt", "a") as file:
file.write(current_time + "\n")
# Main function
def main():
# Set up the camera
picam = Picamera2()
config = picam.create_preview_configuration()
config['main']['size'] = IMG_DIMS
config['main']['format'] = "RGB888"
picam.align_configuration(config)
#print(config)
picam.configure(config)
picam.start()
print(f"Program 1")
# Read the first frame to initialize previous frame
#ret, prev_frame = cap.read()
#print(f"Program 2")
background_frame = picam.capture_array()
while True:
# Read the current frame from the camera
#ret, frame = cap.read()
frame = picam.capture_array()
print(f"Program 3")
#if not ret:
# break
print(f"Program 4")
# Convert the frames to grayscale for easier processing
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray_background_frame = cv2.cvtColor(background_frame, cv2.COLOR_BGR2GRAY)
# Apply background subtraction
fg_mask = bg_subtractor.apply(gray_frame)
fg_mask_background = bg_subtractor.apply(gray_background_frame)
# Detect changes in the ROIs
roi_frames = detect_changes(fg_mask, fg_mask_background, roi_masks)
# Check if any big change is detected in the ROIs
for i, roi_frame in enumerate(roi_frames):
if cv2.countNonZero(roi_frame) > CHANGE_THRESHOLD:
print(f"Big change detected in ROI {i+1} at {datetime.now()}")
save_time_to_file()
cv2.imwrite("framed.jpg", gray_frame) # save frame as JPEG file
cv2.imwrite("framedprevious.jpg", gray_background_frame)
time.sleep(5)
# Update the background frame
background_frame = frame.copy()
time.sleep(0.5) #prerusenie pre mensie vytazovanie CPU
# Release the camera
picam.stop()
if __name__ == "__main__":
print(f"Program starting")
main()