Zakha123-cyber commited on
Commit
2134ff4
·
1 Parent(s): 9b30e86

Remove frame skipping and debug video output to save storage

Browse files

MAJOR CHANGES - Process full video quality:
- Remove adaptive frame sampling from all 3 services
- Process ALL frames (no frame skip) for accurate analysis
- Remove annotated video output to save server storage
- Remove debug_videos section from API response

Changes by service:
1. facial_expression.py: Process all frames, no video output
2. eye_tracking.py: Process all frames, remove _annotate_frame usage
3. gesture_detection.py: Process all frames
4. video_processor.py: Remove debug_videos collection

Benefits:
- More accurate analysis (100% frames processed)
- Save storage space (no debug videos saved)
- Cleaner API response (no debug_videos field)

Trade-off: Longer processing time but better accuracy

app/services/eye_tracking.py CHANGED
@@ -700,9 +700,7 @@ class EyeTrackingService:
700
  def analyze_video(
701
  self,
702
  video_path: str,
703
- progress_callback: Optional[callable] = None,
704
- save_annotated_video: bool = True, # Enable by default for debugging
705
- output_path: Optional[str] = None
706
  ) -> Dict[str, Any]:
707
  """
708
  Analyze video for eye contact
@@ -710,15 +708,12 @@ class EyeTrackingService:
710
  Args:
711
  video_path: Path to video file
712
  progress_callback: Optional callback for progress updates
713
- save_annotated_video: Whether to save annotated video (default: True)
714
- output_path: Path for output video (default: auto-generated in temp/debug/)
715
 
716
  Returns:
717
- Dict containing eye tracking analysis results with annotated_video_path
718
  """
719
  try:
720
  logger.info(f"Analyzing video with Eye Tracking Service: {video_path}")
721
- logger.info(f"Save annotated video: {save_annotated_video}")
722
 
723
  cap = cv.VideoCapture(video_path)
724
  if not cap.isOpened():
@@ -731,22 +726,6 @@ class EyeTrackingService:
731
  total_frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
732
 
733
  logger.info(f"Video properties: {width}x{height} @ {fps}FPS, {total_frames} frames")
734
- logger.info(f"Video properties: {width}x{height} @ {fps}FPS, {total_frames} frames")
735
-
736
- # Setup video writer if needed
737
- out = None
738
- if save_annotated_video:
739
- if output_path is None:
740
- import os
741
- # Generate unique filename based on input video
742
- video_basename = os.path.basename(video_path)
743
- video_name = os.path.splitext(video_basename)[0]
744
- os.makedirs('temp/debug', exist_ok=True)
745
- output_path = f'temp/debug/{video_name}_eye_tracking.mp4'
746
-
747
- fourcc = cv.VideoWriter_fourcc(*'mp4v')
748
- out = cv.VideoWriter(output_path, fourcc, fps, (width, height))
749
- logger.info(f"📹 Annotated video will be saved to: {output_path}")
750
 
751
  # Initialize counters
752
  frame_count = 0
@@ -812,11 +791,6 @@ class EyeTrackingService:
812
  if gaze_pos != 'CENTER' and gaze_pos != 'UNKNOWN':
813
  gaze_away_frames += 1
814
 
815
- # Annotate frame if video output enabled
816
- if save_annotated_video and out is not None:
817
- annotated_frame = self._annotate_frame(frame, result, frame_count, blink_count, gaze_pos)
818
- out.write(annotated_frame)
819
-
820
  # Log every 100 frames
821
  if frame_count % 100 == 0:
822
  logger.info(f"Processed {frame_count}/{total_frames} frames | "
@@ -826,9 +800,6 @@ class EyeTrackingService:
826
  f"Blinks: {blink_count}")
827
 
828
  cap.release()
829
- if out is not None:
830
- out.release()
831
- logger.info(f"✓ Annotated video saved: {output_path}")
832
 
833
  # Calculate metrics
834
  duration = frame_count / fps
@@ -886,11 +857,6 @@ class EyeTrackingService:
886
  'debug_stats': debug_stats
887
  }
888
 
889
- # Always include annotated video path if saved
890
- if save_annotated_video and output_path:
891
- result['annotated_video_path'] = output_path
892
- logger.info(f"✓ Annotated video saved: {output_path}")
893
-
894
  logger.info(f"✓ Eye Tracking analysis completed: Score {score}/5 - {rating}")
895
  return result
896
 
 
700
  def analyze_video(
701
  self,
702
  video_path: str,
703
+ progress_callback: Optional[callable] = None
 
 
704
  ) -> Dict[str, Any]:
705
  """
706
  Analyze video for eye contact
 
708
  Args:
709
  video_path: Path to video file
710
  progress_callback: Optional callback for progress updates
 
 
711
 
712
  Returns:
713
+ Dict containing eye tracking analysis results
714
  """
715
  try:
716
  logger.info(f"Analyzing video with Eye Tracking Service: {video_path}")
 
717
 
718
  cap = cv.VideoCapture(video_path)
719
  if not cap.isOpened():
 
726
  total_frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
727
 
728
  logger.info(f"Video properties: {width}x{height} @ {fps}FPS, {total_frames} frames")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
729
 
730
  # Initialize counters
731
  frame_count = 0
 
791
  if gaze_pos != 'CENTER' and gaze_pos != 'UNKNOWN':
792
  gaze_away_frames += 1
793
 
 
 
 
 
 
794
  # Log every 100 frames
795
  if frame_count % 100 == 0:
796
  logger.info(f"Processed {frame_count}/{total_frames} frames | "
 
800
  f"Blinks: {blink_count}")
801
 
802
  cap.release()
 
 
 
803
 
804
  # Calculate metrics
805
  duration = frame_count / fps
 
857
  'debug_stats': debug_stats
858
  }
859
 
 
 
 
 
 
860
  logger.info(f"✓ Eye Tracking analysis completed: Score {score}/5 - {rating}")
861
  return result
862
 
app/services/facial_expression.py CHANGED
@@ -60,27 +60,12 @@ class FacialExpressionService:
60
  # Get video properties
61
  fps = int(cap.get(cv2.CAP_PROP_FPS))
62
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
63
- duration_seconds = total_frames / fps if fps > 0 else 0
64
 
65
- # ADAPTIVE FRAME SAMPLING based on video length
66
- # Short video (<30s): process every 2 frames (15-25 FPS)
67
- # Medium video (30-60s): process every 3 frames (10-17 FPS)
68
- # Long video (>60s): process every 4 frames (7-12 FPS)
69
- if duration_seconds > 60:
70
- frame_skip = 4
71
- elif duration_seconds > 30:
72
- frame_skip = 3
73
- elif fps > 30:
74
- frame_skip = 2
75
- else:
76
- frame_skip = 1
77
-
78
- logger.info(f"Video duration: {duration_seconds:.1f}s, Processing every {frame_skip} frame(s) from {total_frames} total frames")
79
 
80
  # Data storage
81
  frame_data = []
82
  frame_number = 0
83
- processed_count = 0
84
 
85
  # Process each frame
86
  while True:
@@ -89,12 +74,6 @@ class FacialExpressionService:
89
  break
90
 
91
  frame_number += 1
92
-
93
- # Skip frames if needed
94
- if frame_number % frame_skip != 0:
95
- continue
96
-
97
- processed_count += 1
98
  timestamp_start = (frame_number - 1) / fps
99
  timestamp_end = frame_number / fps
100
 
@@ -152,7 +131,7 @@ class FacialExpressionService:
152
 
153
  cap.release()
154
 
155
- logger.info(f"✓ Processed {processed_count}/{frame_number} frames (skipped every {frame_skip} frame)")
156
 
157
  # Analyze expressions
158
  df_faces = [f for f in frame_data if f['expression'] not in ['no_face', 'background']]
 
60
  # Get video properties
61
  fps = int(cap.get(cv2.CAP_PROP_FPS))
62
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
 
63
 
64
+ logger.info(f"Processing {total_frames} frames at {fps} FPS")
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  # Data storage
67
  frame_data = []
68
  frame_number = 0
 
69
 
70
  # Process each frame
71
  while True:
 
74
  break
75
 
76
  frame_number += 1
 
 
 
 
 
 
77
  timestamp_start = (frame_number - 1) / fps
78
  timestamp_end = frame_number / fps
79
 
 
131
 
132
  cap.release()
133
 
134
+ logger.info(f"✓ Processed {frame_number} frames")
135
 
136
  # Analyze expressions
137
  df_faces = [f for f in frame_data if f['expression'] not in ['no_face', 'background']]
app/services/gesture_detection.py CHANGED
@@ -107,29 +107,12 @@ class GestureDetectionService:
107
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
108
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
109
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
110
- duration_seconds = total_frames / fps if fps > 0 else 0
111
 
112
- logger.info(f"Video Info: {width}x{height} @ {fps}FPS, Total frames: {total_frames}, Duration: {duration_seconds:.1f}s")
113
-
114
- # ADAPTIVE FRAME SAMPLING based on video length
115
- # Short video (<30s): process every 2 frames
116
- # Medium video (30-60s): process every 3 frames
117
- # Long video (>60s): process every 4 frames
118
- if duration_seconds > 60:
119
- frame_skip = 4
120
- elif duration_seconds > 30:
121
- frame_skip = 3
122
- elif fps > 30:
123
- frame_skip = 2
124
- else:
125
- frame_skip = 1
126
-
127
- logger.info(f"Processing every {frame_skip} frame(s) for gesture analysis")
128
 
129
  # Data storage
130
  frame_data = []
131
  frame_count = 0
132
- processed_count = 0
133
  prev_landmarks = None
134
 
135
  while True:
@@ -139,14 +122,8 @@ class GestureDetectionService:
139
 
140
  frame_count += 1
141
 
142
- # Skip frames if needed
143
- if frame_count % frame_skip != 0:
144
- continue
145
-
146
- processed_count += 1
147
-
148
  # Progress callback
149
- if progress_callback and processed_count % 30 == 0:
150
  progress = int((frame_count / total_frames) * 100)
151
  progress_callback(frame_count, total_frames, f"Processing gestures: {progress}%")
152
 
@@ -240,7 +217,7 @@ class GestureDetectionService:
240
 
241
  cap.release()
242
 
243
- logger.info(f"✓ Processed {processed_count}/{frame_count} frames (skipped every {frame_skip} frame)")
244
 
245
  if not frame_data:
246
  logger.warning("No frames processed")
 
107
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
108
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
109
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
 
110
 
111
+ logger.info(f"Video Info: {width}x{height} @ {fps}FPS, Total frames: {total_frames}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  # Data storage
114
  frame_data = []
115
  frame_count = 0
 
116
  prev_landmarks = None
117
 
118
  while True:
 
122
 
123
  frame_count += 1
124
 
 
 
 
 
 
 
125
  # Progress callback
126
+ if progress_callback and frame_count % 30 == 0:
127
  progress = int((frame_count / total_frames) * 100)
128
  progress_callback(frame_count, total_frames, f"Processing gestures: {progress}%")
129
 
 
217
 
218
  cap.release()
219
 
220
+ logger.info(f"✓ Processed {frame_count} frames")
221
 
222
  if not frame_data:
223
  logger.warning("No frames processed")
app/services/video_processor.py CHANGED
@@ -297,7 +297,7 @@ class VideoProcessor:
297
  }
298
 
299
  # Build final response
300
- return {
301
  "level": level,
302
  "video_metadata": {
303
  "duration": metadata.duration,
@@ -309,6 +309,8 @@ class VideoProcessor:
309
  "bonus_indicators": bonus_indicators,
310
  "processing_time": 0 # Will be set by task handler
311
  }
 
 
312
 
313
 
314
  # Singleton instance
 
297
  }
298
 
299
  # Build final response
300
+ result = {
301
  "level": level,
302
  "video_metadata": {
303
  "duration": metadata.duration,
 
309
  "bonus_indicators": bonus_indicators,
310
  "processing_time": 0 # Will be set by task handler
311
  }
312
+
313
+ return result
314
 
315
 
316
  # Singleton instance