0

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()
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
peter
  • 4,289
  • 12
  • 44
  • 67

0 Answers0