Add timestamp overlay feature for video mode

- Add --timestamp / --ts flag to embed frame count on bottom left corner
- Implement add_timestamp_overlay() function with large, visible text
- Yellow text on black background for good visibility
- Shows 'Frame: X/Y' format with current and total frame counts
- Works with both column and row video modes
- Applied after rotation for proper positioning
- Update documentation with timestamp examples and parameter descriptions
- Tested successfully with sample video files
This commit is contained in:
yair-mv 2025-11-08 12:26:11 +02:00
parent c1faa2088c
commit 8fece16ca7
2 changed files with 70 additions and 4 deletions

67
main.py
View File

@ -475,7 +475,49 @@ def extract_row_strip(video_path, y_row, output_path, change_threshold=0.01, rel
cv2.imwrite(str(output_path), strip_image)
def extract_column_strip_video(video_path, x_column, output_path, change_threshold=0.005, relax=0, start_frame=0, end_frame=None, fps=30):
def add_timestamp_overlay(frame, frame_count, total_frames):
"""
Add frame count overlay to the bottom left corner of the frame.
Args:
frame: The video frame to add overlay to
frame_count: Current frame number (1-based)
total_frames: Total number of frames
Returns:
Frame with timestamp overlay
"""
overlay = frame.copy()
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 1.2
font_thickness = 2
text_color = (0, 255, 255) # Yellow for visibility
bg_color = (0, 0, 0) # Black background
# Create timestamp text
timestamp_text = f"Frame: {frame_count}/{total_frames}"
# Get text size for background rectangle
(text_width, text_height), baseline = cv2.getTextSize(timestamp_text, font, font_scale, font_thickness)
# Position at bottom left with some padding
x_pos = 10
y_pos = frame.shape[0] - 10 # Bottom of frame minus padding
# Draw background rectangle
cv2.rectangle(overlay,
(x_pos - 5, y_pos - text_height - baseline - 5),
(x_pos + text_width + 5, y_pos + baseline + 5),
bg_color, -1)
# Draw text
cv2.putText(overlay, timestamp_text, (x_pos, y_pos - baseline),
font, font_scale, text_color, font_thickness, cv2.LINE_AA)
return overlay
def extract_column_strip_video(video_path, x_column, output_path, change_threshold=0.005, relax=0, start_frame=0, end_frame=None, fps=30, timestamp=False):
"""
Extract vertical strip at x_column from each frame and create an MJPEG video.
Each frame of the output video shows the accumulated scan lines up to that point.
@ -489,6 +531,7 @@ def extract_column_strip_video(video_path, x_column, output_path, change_thresho
start_frame: First frame to process (0-based)
end_frame: Last frame to process (None = until end)
fps: Output video frame rate
timestamp: If True, embed frame count on bottom left corner
"""
cap = cv2.VideoCapture(str(video_path))
@ -611,6 +654,10 @@ def extract_column_strip_video(video_path, x_column, output_path, change_thresho
# Convert to numpy array and create the frame
strip_frame = np.stack(accumulated_columns, axis=1)
# Add timestamp overlay if requested
if timestamp:
strip_frame = add_timestamp_overlay(strip_frame, frame_idx + 1, len(significant_columns))
# Write frame to video
out.write(strip_frame)
@ -625,7 +672,7 @@ def extract_column_strip_video(video_path, x_column, output_path, change_thresho
print(f"Total duration: {len(significant_columns)/fps:.2f} seconds")
def extract_row_strip_video(video_path, y_row, output_path, change_threshold=0.01, relax=0, start_frame=0, end_frame=None, fps=30):
def extract_row_strip_video(video_path, y_row, output_path, change_threshold=0.01, relax=0, start_frame=0, end_frame=None, fps=30, timestamp=False):
"""
Extract horizontal strip at y_row from each frame and create an MJPEG video.
Each frame of the output video shows the accumulated scan lines up to that point.
@ -639,6 +686,7 @@ def extract_row_strip_video(video_path, y_row, output_path, change_threshold=0.0
start_frame: First frame to process (0-based)
end_frame: Last frame to process (None = until end)
fps: Output video frame rate
timestamp: If True, embed frame count on bottom left corner
"""
cap = cv2.VideoCapture(str(video_path))
@ -766,6 +814,10 @@ def extract_row_strip_video(video_path, y_row, output_path, change_threshold=0.0
# Rotate counter-clockwise 90 degrees to match image mode orientation
strip_frame = cv2.rotate(strip_frame, cv2.ROTATE_90_COUNTERCLOCKWISE)
# Add timestamp overlay if requested (after rotation)
if timestamp:
strip_frame = add_timestamp_overlay(strip_frame, frame_idx + 1, len(significant_rows))
# Write frame to video
out.write(strip_frame)
@ -862,6 +914,13 @@ def main():
help="Output video frame rate (default: 30.0, only used with --video)"
)
parser.add_argument(
"--timestamp",
"--ts",
action="store_true",
help="Embed frame count on bottom left corner (video mode only)"
)
args = parser.parse_args()
# Validate input file
@ -973,11 +1032,11 @@ def main():
if args.xcolumn is not None:
print(f"Column mode: Extracting vertical line at x={args.xcolumn}")
extract_column_strip_video(video_path, args.xcolumn, output_path, args.threshold, args.relax,
args.start, args.end, args.fps)
args.start, args.end, args.fps, args.timestamp)
else:
print(f"Row mode: Extracting horizontal line at y={args.yrow}")
extract_row_strip_video(video_path, args.yrow, output_path, args.threshold, args.relax,
args.start, args.end, args.fps)
args.start, args.end, args.fps, args.timestamp)
print("MJPEG video generation completed successfully!")
else:

View File

@ -36,6 +36,11 @@ uv run main.py .\line500fps32pix.mp4 --video --fps 30
```
Output: `results/video/line500fps32pix_a3f2_t0_01_fps30_0.avi`
**Video with Timestamp** - Add frame count overlay to video:
```bash
uv run main.py .\line500fps32pix.mp4 --video --fps 30 --timestamp
```
**Debug Mode** - Analyze changes and generate threshold recommendations:
```bash
uv run main.py .\line500fps32pix.mp4 --debug
@ -68,6 +73,7 @@ uv sync
- `--debug` - Analyze changes without creating strip image, outputs to `results/debug/`
- `--video` - Generate MJPEG video showing accumulated scan lines over time
- `--fps N` - Output video frame rate (default: 30.0, only used with `--video`)
- `--timestamp` / `--ts` - Embed frame count on bottom left corner (video mode only)
- `--timeline` - Overlay frame numbers as timeline/ruler on output image (image mode only)
- `--start N` - Start frame number (0-based, default: 0)
- `--end N` - End frame number (0-based, default: last frame)
@ -112,6 +118,7 @@ uv sync
- Creates MJPEG AVI files showing scan line accumulation over time
- Each video frame shows the progressive build-up of the strip photography effect
- Configurable frame rate with `--fps` parameter
- Optional timestamp overlay with `--timestamp` / `--ts` showing frame count in bottom left corner
- Video dimensions automatically calculated based on input video and scan line count
- Compatible with both row and column extraction modes
- Timeline overlay not supported in video mode (use image mode with `--timeline` instead)