Skip to content

Commit

Permalink
Added experimental support for OpenCV dashcam
Browse files Browse the repository at this point in the history
  • Loading branch information
connervieira committed May 31, 2023
1 parent ff74bfb commit a953cc4
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 37 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,6 @@ This update refines Predator's functionality, and focuses its purpose back on li
- Added support for interface with external local services.
- Object recognition library importing has been improved.
- The configuration value to globally disable object recognition has been removed, and replaced with a single control that enables object recognition.
- Fixed an issue where dashcam recording would cause a crash when displaying the process start message.
- Improved dashcam recording.
- Fixed an issue where dashcam recording would cause a crash when displaying the process start message.
- Added support for OpenCV recording.
45 changes: 28 additions & 17 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,23 +193,34 @@ Configuration values in this section are settings specific to real-time mode.
## Dash-cam Mode Configuration

- `capture` contains settings related to the capturing of dashcam video.
- `resolution` is a string that determines what resolution Predator will attmpt to record at, and takes the form of `"[width]x[height]"`
- Be sure that your camera is capable of recording at resolution specified here. If you set an unsupported resolution, it's likely Predator will fail and not record anything.
- Example: `"1920x1080"`
- `frame_rate` is an integer that determines what framerate the dashcam will attempt to record at.
- Be sure that your camera is capable of recording at the frame rate specified here. If you set an unsupported frame rate, it's likely Predator will fail and not record anything.
- If you enter a frame rate too slow for the encoder, it might automatically be sped to a higher frame rate.
- Example: `30`
- `segment_length` is an integer that determines the length of each dashcam video clip before a new segment is created, measured in seconds.
- It should be noted that video segments are not guaranteed to exactly match the length set here.
- When this value is set to `0`, recordings will not be separated into segments.
- `devices` is a list that contains the camera devices Predator will attempt to use when recording video in dash-cam mode.
- Each entry under this setting should contain a device identifier/name, as well as a reference to the device itself.
- Examples:
- `"main_camera": "/dev/video0"`
- `"secondary_camera": "/dev/video1"`
- The device name will be appended to any video file names in order to give the user a quick indication of which camera recorded each file.
- Note: While you can specify an infinite number of cameras here, be aware that Predator might not be able to record with all of them. Bottlenecks like processor speed, RAM, and USB controller capabilities can cause issues with high numbers of cameras. Be sure to test your configuration before you start using it formally.
- `provider` determines which video back-end Predator will use. This can only be set to "ffmpeg" or "opencv".
- `opencv` contains settings that control how the OpenCV back-end records video. These settings are only considered when the `provider` value is set to "opencv".
- `resolution` sets the resolution of the video.
- `width` sets the width of the video, measured in pixels.
- `height` sets the height of the video, measured in pixels.
- `devices` is a list that contains the indexes of camera devices Predator will attempt to use when recording video in dash-cam mode.
- Each entry under this setting should contain a device identifier/name, as well as a reference to the device itself.
- Examples:
- `"main_camera": 0`
- `"secondary_camera": 1`
- `ffmpeg` contains settings that control how the FFMPEG back-end records video. These settings are only considered when the `provider` value is set to "ffmpeg".
- `resolution` is a string that determines what resolution Predator will attmpt to record at, and takes the form of `"[width]x[height]"`
- Be sure that your camera is capable of recording at resolution specified here. If you set an unsupported resolution, it's likely Predator will fail and not record anything.
- Example: `"1920x1080"`
- `frame_rate` is an integer that determines what framerate the dashcam will attempt to record at.
- Be sure that your camera is capable of recording at the frame rate specified here. If you set an unsupported frame rate, it's likely Predator will fail and not record anything.
- If you enter a frame rate too slow for the encoder, it might automatically be sped to a higher frame rate.
- Example: `30`
- `segment_length` is an integer that determines the length of each dashcam video clip before a new segment is created, measured in seconds.
- It should be noted that video segments are not guaranteed to exactly match the length set here.
- When this value is set to `0`, recordings will not be separated into segments.
- `devices` is a list that contains the camera devices Predator will attempt to use when recording video in dash-cam mode.
- Each entry under this setting should contain a device identifier/name, as well as a reference to the device itself.
- Examples:
- `"main_camera": "/dev/video0"`
- `"secondary_camera": "/dev/video1"`
- The device name will be appended to any video file names in order to give the user a quick indication of which camera recorded each file.
- Note: While you can specify an infinite number of cameras here, be aware that Predator might not be able to record with all of them. Bottlenecks like processor speed, RAM, and USB controller capabilities can cause issues with high numbers of cameras. Be sure to test your configuration before you start using it formally.
- `background_recording` is a boolean that determines whether dashcam video will be recorded in the background while using real-time mode.
- Note that Predator can only use each recording device for one task at a time, so if you run real-time mode with background recording enabled, you'll need to specify two different devices by changing `image>capture>device` and `dashcam>devices`.

Expand Down
28 changes: 20 additions & 8 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"general": {
"working_directory": "/home/cvieira/Downloads/predator",
"interface_directory": "/home/cvieira/Downloads/interface",
"working_directory": "/home/cvieira/Software/Support/Predator/Working/",
"interface_directory": "/home/cvieira/Software/Support/Predator/Interface/",
"alpr": {
"engine": "phantom",
"guesses": 5,
Expand All @@ -10,7 +10,7 @@
"alerts": {
"alerts_ignore_validation": true,
"allow_duplicate_alerts": true,
"databases": ["https://v0lttech.com/predator/plates/test.json"]
"databases": []
},
"display": {
"ascii_art_header": true,
Expand Down Expand Up @@ -133,11 +133,23 @@
},
"dashcam": {
"capture": {
"resolution": "1920x1080",
"frame_rate": 15,
"segment_length": 60,
"devices": {
"main": "/dev/video0"
"provider": "opencv",
"opencv": {
"resolution": {
"width": 1280,
"height": 720
},
"devices": {
"main": 0
}
},
"ffmpeg": {
"resolution": "1920x1080",
"frame_rate": 15,
"segment_length": 60,
"devices": {
"main": "/dev/video0"
}
}
},
"background_recording": false
Expand Down
28 changes: 18 additions & 10 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@
convert_speed = utils.convert_speed # Load the function used to convert speeds from meters per second to other units.
display_number = utils.display_number # Load the function used to display numbers as large ASCII font.
closest_key = utils.closest_key # Load the function used to find the closest entry in a dictionary to a given number.
start_dashcam = utils.start_dashcam # Load the function used to start dashcam recording.
start_dashcam_opencv = utils.start_dashcam_opencv # Load the function used to start dashcam recording using OpenCV.
start_dashcam_ffmpeg = utils.start_dashcam_ffmpeg # Load the function used to start dashcam recording using FFMPEG.
display_alerts = utils.display_alerts # Load the function used to display license plate alerts given the dictionary of alerts.
load_alert_database = utils.load_alert_database # Load the function used to load license plate alert databases.
heartbeat = utils.heartbeat # Load the function to issue heartbeats to the interface directory.
Expand Down Expand Up @@ -179,21 +180,21 @@
config["realtime"]["image"]["processing"]["cropping"]["top_margin"] = 0
config["realtime"]["image"]["processing"]["cropping"]["bottom_margin"] = 0

if (re.fullmatch("(\d\d\dx\d\d\d)", config["dashcam"]["capture"]["resolution"]) == None and re.fullmatch("(\d\d\d\dx\d\d\d)", config["dashcam"]["capture"]["resolution"]) == None and re.fullmatch("(\d\d\d\dx\d\d\d\d)", config["dashcam"]["capture"]["resolution"]) == None): # Verify that the dashcam resolution setting matches the format 000x000, 0000x000, or 0000x0000.
display_message("The 'dashcam>capture>resolution' specified in the real-time configuration section doesn't seem to align with the '0000x0000' format. It's possible there has been a typo. efaulting to '1280x720'", 3)
config["dashcam"]["capture"]["resolution"] = "1280x720"
if (re.fullmatch("(\d\d\dx\d\d\d)", config["dashcam"]["capture"]["ffmpeg"]["resolution"]) == None and re.fullmatch("(\d\d\d\dx\d\d\d)", config["dashcam"]["capture"]["ffmpeg"]["resolution"]) == None and re.fullmatch("(\d\d\d\dx\d\d\d\d)", config["dashcam"]["capture"]["ffmpeg"]["resolution"]) == None): # Verify that the dashcam resolution setting matches the format 000x000, 0000x000, or 0000x0000.
display_message("The 'dashcam>capture>ffmpeg>resolution' specified in the real-time configuration section doesn't seem to align with the '0000x0000' format. It's possible there has been a typo. efaulting to '1280x720'", 3)
config["dashcam"]["capture"]["ffmpeg"]["resolution"] = "1280x720"

if (os.path.exists(config["realtime"]["image"]["camera"]["device"]) == False): # Check to make sure that a camera device points to a valid file.
display_message("The 'realtime>image>camera>device' configuration value does not point to a valid file.", 3)


shared_realtime_dashcam_device = False
for device in config["dashcam"]["capture"]["devices"]:
if (config["dashcam"]["background_recording"] == True and config["dashcam"]["capture"]["devices"][device] == config["realtime"]["image"]["camera"]["device"]): # If Predator is configured to run background dashcam recording in real-time mode, then make sure the the dashcam camera device and real-time camera device are different.
for device in config["dashcam"]["capture"]["ffmpeg"]["devices"]:
if (config["dashcam"]["background_recording"] == True and config["dashcam"]["capture"]["ffmpeg"]["devices"][device] == config["realtime"]["image"]["camera"]["device"]): # If Predator is configured to run background dashcam recording in real-time mode, then make sure the the dashcam camera device and real-time camera device are different.
shared_realtime_dashcam_device = True
config["dashcam"]["background_recording"] = False
if (shared_realtime_dashcam_device == True):
display_message("The 'dashcam>background_recording' setting is turned on, but the same recording device has been specified in 'dashcam>capture>devices' and 'realtime>image>camera>device'. Predator can't use the same device for two different tasks. Background dash-cam recording in real-time mode has been disabled.", 3)
display_message("The 'dashcam>background_recording' setting is turned on, but the same recording device has been specified in 'dashcam>capture>ffmpeg>devices' and 'realtime>image>camera>device'. Predator can't use the same device for two different tasks. Background dash-cam recording in real-time mode has been disabled.", 3)


if (config["realtime"]["push_notifications"]["enabled"] == True): # Check to see if the user has Gotify notifications turned on in the configuration.
Expand Down Expand Up @@ -1225,7 +1226,10 @@

if (config["dashcam"]["background_recording"] == True): # Check to see if the user has enabled auto dashcam background recording in real-time mode.
debug_message("Starting background dash-cam recording")
start_dashcam(config["dashcam"]["capture"]["devices"], int(config["dashcam"]["capture"]["segment_length"]), config["dashcam"]["capture"]["resolution"], config["dashcam"]["capture"]["frame_rate"], config["general"]["working_directory"], True) # Start the dashcam recording process.
if (config["dashcam"]["capture"]["provider"] == "ffmpeg"): # Check to see if the configured video back-end is FFMPEG.
start_dashcam_ffmpeg(config["dashcam"]["capture"]["ffmpeg"]["devices"], int(config["dashcam"]["capture"]["ffmpeg"]["segment_length"]), config["dashcam"]["capture"]["ffmpeg"]["resolution"], config["dashcam"]["capture"]["ffmpeg"]["frame_rate"], config["general"]["working_directory"], True) # Start the dashcam recording process.
elif (config["dashcam"]["capture"]["provider"] == "opencv"): # Check to see if the configured video back-end is OpenCV.
start_dashcam_opencv(config["dashcam"]["capture"]["opencv"]["devices"], int(config["dashcam"]["capture"]["opencv"]["resolution"]["width"]), config["dashcam"]["capture"]["opencv"]["resolution"]["height"], config["general"]["working_directory"], True) # Start the dashcam recording process.
print("Started background dash-cam recording.")


Expand Down Expand Up @@ -1609,8 +1613,12 @@

elif (mode_selection == "3" and config["general"]["modes"]["enabled"]["dashcam"] == True): # The user has set Predator to boot into dash-cam mode.
debug_message("Started dash-cam mode")
print("\nStarting dashcam recording at " + str(config["dashcam"]["capture"]["resolution"]) + "@" + str(config["dashcam"]["capture"]["frame_rate"]) + "fps") # Print information about the recording settings.
start_dashcam(config["dashcam"]["capture"]["devices"], int(config["dashcam"]["capture"]["segment_length"]), config["dashcam"]["capture"]["resolution"], config["dashcam"]["capture"]["frame_rate"], config["general"]["working_directory"], False) # Start the dashcam recording process.
if (config["dashcam"]["capture"]["provider"] == "ffmpeg"): # Check to see if the configured video back-end is FFMPEG.
start_dashcam_ffmpeg(config["dashcam"]["capture"]["ffmpeg"]["devices"], int(config["dashcam"]["capture"]["ffmpeg"]["segment_length"]), config["dashcam"]["capture"]["ffmpeg"]["resolution"], config["dashcam"]["capture"]["ffmpeg"]["frame_rate"], config["general"]["working_directory"], False) # Start the dashcam recording process.
print("\nStarting dashcam recording at " + str(config["dashcam"]["capture"]["ffmpeg"]["resolution"]) + "@" + str(config["dashcam"]["capture"]["ffmpeg"]["frame_rate"]) + "fps") # Print information about the recording settings.
elif (config["dashcam"]["capture"]["provider"] == "opencv"): # Check to see if the configured video back-end is OpenCV.
start_dashcam_opencv(config["dashcam"]["capture"]["opencv"]["devices"], int(config["dashcam"]["capture"]["opencv"]["resolution"]["width"]), config["dashcam"]["capture"]["opencv"]["resolution"]["height"], config["general"]["working_directory"], False) # Start the dashcam recording process.
print("\nStarting dashcam recording at " + str(config["dashcam"]["capture"]["opencv"]["resolution"]["width"]) + "x" + str(config["dashcam"]["capture"]["opencv"]["resolution"]["height"]) + "@" + str(config["dashcam"]["capture"]["ffmpeg"]["frame_rate"]) + "fps") # Print information about the recording settings.



Expand Down
57 changes: 56 additions & 1 deletion utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ def debug_message(message):
if (config["realtime"]["gps"]["enabled"] == True): # Only import the GPS libraries if GPS settings are enabled.
from gps import * # Required to access GPS information.
import gpsd
if (config["dashcam"]["capture"]["provider"] == "opencv"): # Check to see if OpenCV is needed.
import cv2 # Import OpenCV
import threading



Expand Down Expand Up @@ -572,7 +575,59 @@ def closest_key(array, search_key): # This function returns the nearest timestam



def start_dashcam(dashcam_devices, segment_length, resolution, framerate, directory, background=False): # This function starts dashcam recording on a given list of dashcam devices.

dashcam_recording_active = False

def start_opencv_recording(directory, device=0, width=1280, height=720):
global dashcam_recording_active
capture = cv2.VideoCapture(device) # Open the video stream.
capture.set(cv2.CAP_PROP_FRAME_WIDTH,width) # Set the video stream width.
capture.set(cv2.CAP_PROP_FRAME_HEIGHT,height) # Set the video stream height.

file = directory + "/predator_dashcam_" + str(int(time.time())) + "_" + str(device) + "_0.avi" # Determine the file path.
output = cv2.VideoWriter(file, cv2.VideoWriter_fourcc(*'XVID'), 20.0, (width, height))

if not capture.isOpened():
print("Cannot open camera")
exit()

while dashcam_recording_active: # Only run while the dashcam recording flag is set to 'True'.
ret, frame = capture.read() # Capture a frame.
if not ret: # Check to see if the frame failed to be read.
print("Can't receive frame (stream end?). Exiting ...")
break

stamp_position = [10, height - 10]
stamp = str(round(time.time())) + " " + "ABC1234" + " " + "V0LT"
cv2.putText(frame, stamp, (stamp_position[0], stamp_position[1]), 2, 0.8, (255,255,255))

output.write(frame) # Save this frame to the video.

capture.release()
cv2.destroyAllWindows()



def start_dashcam_opencv(dashcam_devices, video_width, video_height, directory, background=False): # This function starts dashcam recording on a given list of dashcam devices.
dashcam_process = [] # Create a placeholder list to store the dashcam processes.
iteration_counter = 0 # Set the iteration counter to 0 so that we can increment it for each recording device specified.
global dashcam_recording_active
dashcam_recording_active = True

for device in dashcam_devices: # Run through each camera device specified in the configuration, and launch an FFMPEG recording instance for it.
dashcam_process.append(threading.Thread(target=start_opencv_recording, args=[directory, dashcam_devices[device], video_width, video_height], name="Dashcam" + str(iteration_counter)))
dashcam_process[iteration_counter].start()

iteration_counter = iteration_counter + 1 # Iterate the counter. This value will be used to create unique file names for each recorded video.
print("Started dashcam recording on " + str(dashcam_devices[device])) # Inform the user that recording was initiation for this camera device.

if (background == False): # If background recording is disabled, then prompt the user to press enter to halt recording.
prompt("Press enter to cancel recording...") # Wait for the user to press enter before continuing, since continuing will terminate recording.
dashcam_recording_active = False # All dashcam threads are watching this variable globally, and will terminate when it is changed to 'False'.
print("Dashcam recording halted.")


def start_dashcam_ffmpeg(dashcam_devices, segment_length, resolution, framerate, directory, provider, background=False): # This function starts dashcam recording on a given list of dashcam devices.
dashcam_process = [] # Create a placeholder list to store the dashcam processes.
iteration_counter = 0 # Set the iteration counter to 0 so that we can increment it for each recording device specified.

Expand Down

0 comments on commit a953cc4

Please sign in to comment.