Skip to content
141,273 changes: 141,273 additions & 0 deletions 1_detection_to_csv.ipynb

Large diffs are not rendered by default.

245,759 changes: 245,759 additions & 0 deletions 1_detection_to_csv_wbb.ipynb

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions 2_detect_red_all.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import cv2
import os
import pandas as pd
import numpy as np
from os.path import splitext, basename, join
from datetime import datetime, timedelta
from glob import glob

# Function to detect red light in the ROI
def detect_red_light(image):
lower_red = np.array([0, 120, 70])
upper_red = np.array([10, 255, 255])
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_red, upper_red)
return cv2.countNonZero(mask) > 0

# Function to manually draw the ROI
def draw_roi(event, x, y, flags, param):
global traffic_light_box, drawing, top_left_pt, bottom_right_pt, roi_selected
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
top_left_pt = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
bottom_right_pt = (x, y)
roi_selected = True

# Paths
videos_path = 'C:/Users/marya1/Box/MnDOT DNRTOR Project/Meenakshi/videos'
output_path = 'C:/Users/marya1/Box/MnDOT DNRTOR Project/Meenakshi/detect_red'
#videos_path = 'C:/Users/ASUS/Box/MnDOT DNRTOR Project/Pratik'
#output_path = 'C:/Users/ASUS/Box/MnDOT DNRTOR Project/Pratik/output'
#videos_path = 'E:/MnDOT/Videos'
#output_path = 'E:/MnDOT/Videos/output'


# List all video files
video_files = glob(join(videos_path, '*.mp4'))

for video_path in video_files:
# Initialize variables for each video
traffic_light_box = None
roi_selected = False

# Display video and select ROI
cap = cv2.VideoCapture(video_path)
ret, first_frame = cap.read()
if not ret:
print("Failed to read video:", video_path)
cap.release()
continue # Skip to the next video

# Input for date and time
video_date = input(f"Enter the video start date (yyyy-mm-dd) for {basename(video_path)}: ")
video_start_time = input(f"Enter the video start time (hh-mm-ss) for {basename(video_path)}: ")
start_datetime = datetime.strptime(f"{video_date} {video_start_time}", "%Y-%m-%d %H-%M-%S")

cv2.namedWindow('Frame')
cv2.setMouseCallback('Frame', draw_roi)

print("Draw a bounding box around the traffic light and press 'Enter'.")
while True:
frame_copy = first_frame.copy()
if roi_selected:
cv2.rectangle(frame_copy, top_left_pt, bottom_right_pt, (0, 255, 0), 2)
cv2.imshow('Frame', frame_copy)
key = cv2.waitKey(1)
if key == 13: # Enter key
traffic_light_box = (top_left_pt[0], top_left_pt[1], bottom_right_pt[0] - top_left_pt[0], bottom_right_pt[1] - top_left_pt[1])
break

cv2.destroyAllWindows()

df = pd.DataFrame(columns=['Frame_Number', 'Date', 'Time', 'Red_Light'])
frame_counter = 0
fps = cap.get(cv2.CAP_PROP_FPS)

while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
current_time = start_datetime + timedelta(seconds=frame_counter / fps)
date_str = current_time.strftime("%Y-%m-%d")
time_str = current_time.strftime("%H:%M:%S")

traffic_light_roi = frame[traffic_light_box[1]:traffic_light_box[1]+traffic_light_box[3],
traffic_light_box[0]:traffic_light_box[0]+traffic_light_box[2]]
red_light_detected = detect_red_light(traffic_light_roi)

new_row = {'Frame_Number': frame_counter, 'Date': date_str, 'Time': time_str, 'Red_Light': red_light_detected}
df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)

frame_counter += 1

cap.release()

# Save the DataFrame to a CSV file
csv_file_name = splitext(basename(video_path))[0] + '.csv'
csv_path = join(output_path, csv_file_name)
df.to_csv(csv_path, index=False)
print(f"CSV saved at {csv_path}")
55 changes: 55 additions & 0 deletions 3_merge_detection_red.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import pandas as pd
import os
from glob import glob

def merge_csv_with_timestamps(output_csv_dir, timestamps_csv_dir, merged_csv_dir):
# List all CSV files in the output CSV directory
output_csv_files = glob(os.path.join(output_csv_dir, '*.csv'))

for output_csv_path in output_csv_files:
# Derive the base file name without extension to match with timestamp file
base_file_name = os.path.basename(output_csv_path)

# Construct the expected timestamp CSV file path
timestamps_csv_path = os.path.join(timestamps_csv_dir, base_file_name)

# Check if the corresponding timestamps CSV exists
if not os.path.exists(timestamps_csv_path):
print(f"No matching timestamp file found for {base_file_name}. Skipping...")
continue

# Load the CSV files
output_df = pd.read_csv(output_csv_path)
timestamps_df = pd.read_csv(timestamps_csv_path)

# Merge the two dataframes on the Frame and Frame_Number columns
merged_df = pd.merge(output_df, timestamps_df, left_on='Frame', right_on='Frame_Number', how='left')

# Including all relevant columns and renaming
#final_df = merged_df[['Datetime', 'Frame', 'Track', 'Class', 'BBox', 'Time', 'Date', 'Red_Light']].copy()
final_df = merged_df[['Datetime', 'Frame', 'Track', 'Class', 'Class_ID','xmin', 'ymin','xmax','ymax', 'Time', 'Date', 'Red_Light']].copy()
final_df.rename(columns={'Frame': 'FrameNumber', 'Red_Light': 'Color'}, inplace=True)

# Handle 'Color' column
final_df['Color'].fillna('Not Red', inplace=True)
final_df['Color'] = final_df['Color'].apply(lambda x: 'Red' if x == True else 'Not Red')

# Construct path for saving the merged CSV
merged_csv_path = os.path.join(merged_csv_dir, base_file_name)

# Save the merged dataframe
final_df.to_csv(merged_csv_path, index=False)
print(f"Merged CSV saved to {merged_csv_path}")

# Directories containing the CSV files
#output_csv_dir = 'C:/Users/marya1/Box/MnDOT DNRTOR Project/Meenakshi/detect_objects'
#timestamps_csv_dir = 'C:/Users/marya1/Box/MnDOT DNRTOR Project/Meenakshi/detect_red'
#merged_csv_dir = 'C:/Users/marya1/Box/MnDOT DNRTOR Project/Meenakshi/final_csv'


output_csv_dir = '/home/marya1/Documents/MnDoTNRToR/inference/detect_objects/processing'
timestamps_csv_dir = '/home/marya1/Documents/MnDoTNRToR/inference/detect_red'
merged_csv_dir = '/home/marya1/Documents/MnDoTNRToR/inference/final_csv'

# Call the function with the directories
merge_csv_with_timestamps(output_csv_dir, timestamps_csv_dir, merged_csv_dir)
39 changes: 39 additions & 0 deletions 3_merge_detection_red2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import pandas as pd
import os
from glob import glob

def merge_csv_with_timestamps(output_csv_dir, timestamps_csv_dir, merged_csv_dir):
output_csv_files = glob(os.path.join(output_csv_dir, '*.csv'))

for output_csv_path in output_csv_files:
base_file_name = os.path.basename(output_csv_path)
timestamps_csv_path = os.path.join(timestamps_csv_dir, base_file_name)

if not os.path.exists(timestamps_csv_path):
print(f"No matching timestamp file found for {base_file_name}. Skipping...")
continue

try:
output_df = pd.read_csv(output_csv_path, on_bad_lines='warn')
timestamps_df = pd.read_csv(timestamps_csv_path, on_bad_lines='warn')
except Exception as e:
print(f"Error reading {base_file_name}: {e}")
continue

merged_df = pd.merge(output_df, timestamps_df, left_on='Frame', right_on='Frame_Number', how='left')
final_df = merged_df[['Datetime', 'Frame', 'Track', 'Class', 'Class_ID', 'xmin', 'ymin', 'xmax', 'ymax', 'Time', 'Date', 'Red_Light']].copy()
final_df.rename(columns={'Frame': 'FrameNumber', 'Red_Light': 'Color'}, inplace=True)
final_df['Color'].fillna('Not Red', inplace=True)
final_df['Color'] = final_df['Color'].apply(lambda x: 'Red' if x == True else 'Not Red')

merged_csv_path = os.path.join(merged_csv_dir, base_file_name)
final_df.to_csv(merged_csv_path, index=False)
print(f"Merged CSV saved to {merged_csv_path}")


output_csv_dir = '/home/marya1/Documents/MnDoTNRToR/inference/detect_objects/processing'
timestamps_csv_dir = '/home/marya1/Documents/MnDoTNRToR/inference/detect_red'
merged_csv_dir = '/home/marya1/Documents/MnDoTNRToR/inference/final_csv'

# Use the directories as defined in the script
merge_csv_with_timestamps(output_csv_dir, timestamps_csv_dir, merged_csv_dir)
126 changes: 126 additions & 0 deletions 4_detect_violations_confirmation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import cv2
import pandas as pd
from os.path import join, basename, splitext
from glob import glob

# Define global variables for ROI drawing
drawing = False
roi_selected = False
top_left_pt, bottom_right_pt = None, None

def draw_roi(event, x, y, flags, param):
global drawing, roi_selected, top_left_pt, bottom_right_pt
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
top_left_pt = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
bottom_right_pt = (x, y)
roi_selected = True

def is_within_roi(xmin, ymin, xmax, ymax, roi):
roi_xmin, roi_ymin, roi_xmax, roi_ymax = roi
return xmin >= roi_xmin and xmax <= roi_xmax and ymin >= roi_ymin and ymax <= roi_ymax


def count_vehicles_and_violations(csv_file, roi, valid_classes=[1, 2, 3, 5, 7], min_frames=60):
df = pd.read_csv(csv_file)
# Assuming 'Date' column is in 'YYYY-MM-DD' format and 'Time' in 'HH:MM:SS' format
df['DateTime'] = pd.to_datetime(df['Date'] + ' ' + df['Time'], errors='coerce')

red_light_phases = df[df['Color'] == 'Red'].groupby((df['Color'] != df['Color'].shift()).cumsum())
results = []

for _, phase in red_light_phases:
start_of_red_light = phase['DateTime'].iloc[0]
next_phase_start = phase['DateTime'].iloc[-1] + pd.Timedelta(seconds=1)

# Skip intervals less than 1 second
if (next_phase_start - start_of_red_light).total_seconds() <= 1:
continue

tracks_in_roi = df[(df['DateTime'] >= start_of_red_light) & (df['DateTime'] < next_phase_start)]
tracks_in_roi = tracks_in_roi[tracks_in_roi.apply(lambda row: is_within_roi(row['xmin'], row['ymin'], row['xmax'], row['ymax'], roi), axis=1)]
valid_tracks_in_roi = tracks_in_roi[tracks_in_roi['Class_ID'].isin(valid_classes)]

# Count frames for each track and filter out those with less than min_frames
frame_counts = valid_tracks_in_roi.groupby('Track').size()
tracks_more_than_min_frames = frame_counts[frame_counts >= min_frames].index
valid_tracks_in_roi = valid_tracks_in_roi[valid_tracks_in_roi['Track'].isin(tracks_more_than_min_frames)]

exiting_tracks = valid_tracks_in_roi.groupby('Track').last()
exiting_tracks = exiting_tracks[exiting_tracks.index.isin(tracks_more_than_min_frames)]
violations = exiting_tracks[exiting_tracks['Color'] == 'Red'].index.nunique()
violating_track_ids = exiting_tracks[exiting_tracks['Color'] == 'Red'].index.unique().tolist()
total_vehicles = valid_tracks_in_roi['Track'].nunique()

total_vehicles_complying = valid_tracks_in_roi['Track'].nunique() - violations
complying_track_ids = valid_tracks_in_roi[~valid_tracks_in_roi['Track'].isin(violating_track_ids)]['Track'].unique().tolist()

results.append({
'Start_of_Red_Light': start_of_red_light.strftime('%Y-%m-%d %H:%M:%S'),
'Beginning_of_Not_Red': next_phase_start.strftime('%Y-%m-%d %H:%M:%S'),
'Total_Vehicles': total_vehicles,
'Vehicles_Complying': total_vehicles_complying,
'Vehicles_Violating': violations,
'Complying Tracks': complying_track_ids,
'Violating Tracks': violating_track_ids,
'Compliance Rate': (total_vehicles - violations) / total_vehicles if total_vehicles > 0 else 1
})

results_df = pd.DataFrame(results)


if not results_df.empty:
overall_compliance_rate = (results_df['Total_Vehicles'].sum() - results_df['Vehicles_Violating'].sum()) / results_df['Total_Vehicles'].sum()
overall_summary = pd.DataFrame([{'Start_of_Red_Light': 'Overall', 'Beginning_of_Not_Red': '', 'Total_Vehicles': results_df['Total_Vehicles'].sum(), 'Vehicles_Violating': results_df['Vehicles_Violating'].sum(), 'Compliance Rate': overall_compliance_rate}])
results_df = pd.concat([results_df, overall_summary], ignore_index=True)

return results_df

csv_path = '/home/marya1/Documents/MnDoTNRToR/inference/final_csv'
output_path='/home/marya1/Documents/MnDoTNRToR/inference/detect_violations_trial'
videos_path = '/home/marya1/Documents/MnDoTNRToR/videos/processing'

video_files = glob(join(videos_path, '*.mp4'))

for video_path in video_files:
cap = cv2.VideoCapture(video_path)
ret, first_frame = cap.read()
if not ret:
print(f"Failed to read video: {video_path}")
continue

# Reset RoI selection variables
drawing = False
roi_selected = False
top_left_pt, bottom_right_pt = None, None

cv2.namedWindow('Frame')
cv2.setMouseCallback('Frame', draw_roi)
print("Draw a bounding box around the area of interest and press 'Enter'.")

while True:
frame_copy = first_frame.copy()
if roi_selected:
cv2.rectangle(frame_copy, top_left_pt, bottom_right_pt, (0, 255, 0), 2)
cv2.imshow('Frame', frame_copy)
key = cv2.waitKey(1) & 0xFF
if key == 13: # Enter key is pressed
break

if not roi_selected:
print(f"RoI not selected for video: {video_path}. Skipping...")
cv2.destroyAllWindows()
continue

roi = (top_left_pt[0], top_left_pt[1], bottom_right_pt[0], bottom_right_pt[1])
cv2.destroyAllWindows()
cap.release()

# Proceed with analysis using selected RoI
csv_file = join(csv_path, splitext(basename(video_path))[0] + '.csv')
analysis_results = count_vehicles_and_violations(csv_file, roi)
output_file = join(output_path, splitext(basename(video_path))[0] + '_violations.csv')
analysis_results.to_csv(output_file, index=False)
print(f"Analysis saved to {output_file}")
Loading