raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
852 stars 181 forks source link

[HOW-TO] Record video duration with Motion Capture #1049

Closed SuperCoder-101 closed 3 months ago

SuperCoder-101 commented 3 months ago

How do you set video duration with motion capture?

Currently, I am working on a motion detection camera project using a Raspberry Pi 3B and a noIR camera module V2.1, this would be a fun first-time project.

What I want to accomplish is for my camera to start recording video once motion is detected, the video should have a duration of about 10 minutes. After 10 minutes it should no longer record video regardless if motion is still occurring on the camera. Then my camera should wait about 10 seconds before it attempts to record any video once motion is detected.

Here is my current script it is mostly based on capture_motion.py with a few modifications of my own

#!/usr/bin/python3

 import time

 import os

 import numpy as np

 from picamera2 import Picamera2
 from picamera2.encoders import H264Encoder
 from picamera2.outputs import FfmpegOutput

 directory_path = "/media/your_user/flashdrive/"

 # Check if the directory path exists, create it if it doesn't
 if not os.path.exists(directory_path):
    os.makedirs(directory_path)

lsize = (320, 240)
picam2 = Picamera2()
video_config = picam2.create_video_configuration(main={"size": (1280, 720), "format": "RGB888"},
                                                 lores={"size": lsize, "format": "YUV420"})
picam2.configure(video_config)
encoder = H264Encoder(1000000)
picam2.start()

w, h = lsize
prev = None
encoding = False    
ltime = 0

while True:
    cur = picam2.capture_buffer("lores")
    cur = cur[:w * h].reshape(h, w)
    if prev is not None:
        # Measure pixels differences between current and
        # previous frame
        mse = np.square(np.subtract(cur, prev)).mean()
        if mse > 7:
            if not encoding:
                # Specify the output fil path with a unqiue timestamp
                output_file_path = os.path.join(directory_path, f"{int(time.time())}.mp4")

                encoder.output = FfmpegOutput(output_file_path, audio=False)
                picam2.start_encoder(encoder)
                encoding = True
                print("New Motion", mse)
            ltime = time.time()
        else:
            if encoding and time.time() - ltime > 2.0:
                picam2.stop_encoder()
                encoding = False
    prev = cur

I have considered using


 t1 = time.time()
 duration = t1 - t0
 if duration > 30:
      break

I also tried to use 'time.sleep()' to get it to record for 30 seconds as a test and make my script stop for 5 seconds.

This mostly worked, however, I ran into the issue of my motion capture always running as if I were to set the code to only record for 30 seconds and stop for 5 seconds, and then it would start again saying that it was "capturing motion" even when no motion was occurring.

Unfortunately, I am having difficulty finding any information related to the motion capture.py script with any video recording duration.

No, I do not want to use MotionEye for motion detection recording, I plan on placing this in a field to record butterflies on an orchid where Wi-Fi is not an option. I already have a plan for this script to run at boot with systemd services.

I will continue to work on my script as I wait for responses here, but any help with this would be appreciated as I keep reading through the Picamera2 libraries.

SuperCoder-101 commented 3 months ago

I think I got the issue fixed, and here is what I did to fix it.

#!/usr/bin/python3

import time
import os

import numpy as np

from picamera2 import Picamera2
from picamera2.encoders import H264Encoder
from picamera2.outputs import FfmpegOutput

directory_path = "/media/your_user/flashdrive/"

# Time to sleep before checking for motion again (10 seconds)
sleep_duration = 10

# Check if the directory path exists, create it if it doesn't
if not os.path.exists(directory_path):
    os.makedirs(directory_path)

lsize = (320, 240)
picam2 = Picamera2()
video_config = picam2.create_video_configuration(main={"size": (1280, 720), "format": "RGB888"},
                                                 lores={"size": lsize, "format": "YUV420"})
picam2.configure(video_config)
encoder = H264Encoder(1000000)
picam2.start()

w, h = lsize
prev = None
encoding = False   
t0 = 0

while True:
    cur = picam2.capture_buffer("lores")
    cur = cur[:w * h].reshape(h, w)
    if prev is not None:
        # Measure pixels differences between current and
        # previous frame
        mse = np.square(np.subtract(cur, prev)).mean()
        if mse > 7:
            if not encoding:
                # Specify the output file path with a unqiue timestamp
                output_file_path = os.path.join(directory_path, f"{int(time.time())}.mp4")

                encoder.output = FfmpegOutput(output_file_path, audio=False)
                picam2.start_encoder(encoder)
                encoding = True
                print("New Motion", mse)
                t0 = time.time() # start time of recording
        else:
            if encoding:
                t1 = time.time() # current time
                duration = t1 - t0 # current time - start time
                # Use 11 instead of 10 otherwise you get 9 seconds (zero-based indexing)
                if duration > 11:
                    picam2.stop_encoder()
                    encoding = False
                    print("Stop recording now that 10 seconds has passed") # Print statement to see that this section is being executed
                    print("Sleep for 10 seconds...") # Sleep for 10 seconds before beginning new motion capture
    prev = cur
    time.sleep(1)