From 6832a01329e280ee8eec6c167f0587413c2dce28 Mon Sep 17 00:00:00 2001 From: "cintraai-coding-assistant[bot]" <146896159+cintraai-coding-assistant[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:41:44 +0000 Subject: [PATCH 1/2] ADHOC-56240, Task 1: Refactor video_motion to handle multiple videos Modify the video_motion method in the Sensync class to accept a list of video paths and process each video concurrently using threading. This change allows for more efficient video processing by utilizing multiple threads, improving the performance of the motion detection feature in environments with multiple video inputs. --- sensync.py | 112 +++++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 50 deletions(-) diff --git a/sensync.py b/sensync.py index 5db3273..3095307 100644 --- a/sensync.py +++ b/sensync.py @@ -7,62 +7,73 @@ import cv2 import numpy as np import os -import pandas as pd +import pandas as pd import math +import threading -class Sensync(): - - def sensor_motion(self, sensor_path:str, frames:int): + +class Sensync: + def sensor_motion(self, sensor_path: str, frames: int): df = pd.read_csv(sensor_path) # Calculate magnitude of acceleration - df['magnitude'] = np.sqrt(df['x']**2 + df['y']**2 + df['z']**2) - + df["magnitude"] = np.sqrt(df["x"] ** 2 + df["y"] ** 2 + df["z"] ** 2) + # Create a time index based on the timestamps - df['time_index'] = pd.to_datetime(df['seconds_elapsed'], unit='s') - - df = df.set_index('time_index') - df_resampled = df['magnitude'].resample('33.33ms').mean() + df["time_index"] = pd.to_datetime(df["seconds_elapsed"], unit="s") + + df = df.set_index("time_index") + df_resampled = df["magnitude"].resample("33.33ms").mean() return df_resampled - - def video_motion(self, video_path:str): - cap = cv2.VideoCapture(video_path) - if not cap.isOpened(): - print("Error opening video file") - raise Exception('Could not open the video file specified, please check the path and try again') - # Initialize variables - prev_frame = None + + def video_motion(self, video_paths: list): + def process_video(video_path): + cap = cv2.VideoCapture(video_path) + if not cap.isOpened(): + print(f"Error opening video file: {video_path}") + raise Exception( + f"Could not open the video file {video_path}, please check the path and try again" + ) + prev_frame = None + local_frame_differences = [] + + while True: + ret, frame = cap.read() + if not ret: + break + frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + if prev_frame is not None: + frame_diff = cv2.absdiff(prev_frame, frame_gray) + total_diff = frame_diff.sum() + local_frame_differences.append(total_diff) + prev_frame = frame_gray + frame_differences.extend(local_frame_differences) + frame_differences = [] - - while True: - - ret, frame = cap.read() - if not ret: - break - - # Convert the frame to grayscale - frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - - # If this isn't the first frame... - if prev_frame is not None: - frame_diff = cv2.absdiff(prev_frame, frame_gray) - total_diff = frame_diff.sum() - frame_differences.append(total_diff) - prev_frame = frame_gray - + threads = [] + for video_path in video_paths: + thread = threading.Thread(target=process_video, args=(video_path,)) + threads.append(thread) + thread.start() + + for thread in threads: + thread.join() + return frame_differences - - def sync(self, video_path:str, - fps:int, - sensor_path:str, - window=30, - export_path='', - export=False, - ): - if export == True and export_path == '': - raise Exception('export_path must be valid!') - - vid_motion = self.video_motion(video_path) + + def sync( + self, + video_path: str, + fps: int, + sensor_path: str, + window=30, + export_path="", + export=False, + ): + if export == True and export_path == "": + raise Exception("export_path must be valid!") + + vid_motion = self.video_motion([video_path]) sensor_motion = self.sensor_motion(sensor_path, fps) bestOffset = 0 @@ -70,11 +81,12 @@ def sync(self, video_path:str, for offset in range(-fps * window, fps * window): # Calculate correlation for current offset - corr = np.corrcoef(vid_motion[offset:offset + 2*fps*window], sensor_motion[offset:offset + 2*fps*window])[0, 1] + corr = np.corrcoef( + vid_motion[offset : offset + 2 * fps * window], + sensor_motion[offset : offset + 2 * fps * window], + )[0, 1] if corr > bestCorr: bestCorr = corr bestOffset = offset return bestOffset - - \ No newline at end of file From e16e5eaa60f1696b4a65417f2f43b0b52a171c1a Mon Sep 17 00:00:00 2001 From: "cintraai-coding-assistant[bot]" <146896159+cintraai-coding-assistant[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:42:13 +0000 Subject: [PATCH 2/2] ADHOC-56240, Task 2: Improve error handling in video processing Add try-except blocks to manage exceptions in video_motion method. Handle file not found, unsupported formats, and general processing errors with meaningful messages. Also, validate export_path when exporting data and handle index errors in correlation calculations. --- sensync.py | 61 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/sensync.py b/sensync.py index 3095307..b07056b 100644 --- a/sensync.py +++ b/sensync.py @@ -28,26 +28,26 @@ def sensor_motion(self, sensor_path: str, frames: int): def video_motion(self, video_paths: list): def process_video(video_path): - cap = cv2.VideoCapture(video_path) - if not cap.isOpened(): - print(f"Error opening video file: {video_path}") - raise Exception( - f"Could not open the video file {video_path}, please check the path and try again" - ) - prev_frame = None - local_frame_differences = [] - - while True: - ret, frame = cap.read() - if not ret: - break - frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - if prev_frame is not None: - frame_diff = cv2.absdiff(prev_frame, frame_gray) - total_diff = frame_diff.sum() - local_frame_differences.append(total_diff) - prev_frame = frame_gray - frame_differences.extend(local_frame_differences) + try: + cap = cv2.VideoCapture(video_path) + if not cap.isOpened(): + raise IOError(f"Could not open video file: {video_path}") + prev_frame = None + local_frame_differences = [] + + while True: + ret, frame = cap.read() + if not ret: + break + frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + if prev_frame is not None: + frame_diff = cv2.absdiff(prev_frame, frame_gray) + total_diff = frame_diff.sum() + local_frame_differences.append(total_diff) + prev_frame = frame_gray + frame_differences.extend(local_frame_differences) + except Exception as e: + print(f"Error processing video {video_path}: {str(e)}") frame_differences = [] threads = [] @@ -70,8 +70,8 @@ def sync( export_path="", export=False, ): - if export == True and export_path == "": - raise Exception("export_path must be valid!") + if export and export_path == "": + raise ValueError("export_path must be valid!") vid_motion = self.video_motion([video_path]) sensor_motion = self.sensor_motion(sensor_path, fps) @@ -81,12 +81,15 @@ def sync( for offset in range(-fps * window, fps * window): # Calculate correlation for current offset - corr = np.corrcoef( - vid_motion[offset : offset + 2 * fps * window], - sensor_motion[offset : offset + 2 * fps * window], - )[0, 1] - if corr > bestCorr: - bestCorr = corr - bestOffset = offset + try: + corr = np.corrcoef( + vid_motion[offset : offset + 2 * fps * window], + sensor_motion[offset : offset + 2 * fps * window], + )[0, 1] + if corr > bestCorr: + bestCorr = corr + bestOffset = offset + except IndexError: + continue # Skip offsets that are out of range return bestOffset