SpyC0der77 commited on
Commit
dacbe6c
·
verified ·
1 Parent(s): c4922ab

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -0
app.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import csv
4
+ import math
5
+ import tempfile
6
+ import os
7
+ import gradio as gr
8
+
9
+ def read_motion_csv(csv_filename):
10
+ """
11
+ Reads a CSV file with columns: frame, mag, ang, zoom.
12
+ For each row, computes a displacement from mag and ang and
13
+ accumulates these to build a per-frame cumulative offset.
14
+
15
+ Returns:
16
+ A dictionary mapping frame numbers to (dx, dy) offsets.
17
+ The offsets are the negative cumulative displacements,
18
+ which can be used to counteract the camera motion.
19
+ """
20
+ motion_data = {}
21
+ cumulative_dx = 0.0
22
+ cumulative_dy = 0.0
23
+ with open(csv_filename, 'r') as csvfile:
24
+ reader = csv.DictReader(csvfile)
25
+ for row in reader:
26
+ frame_num = int(row['frame'])
27
+ mag = float(row['mag'])
28
+ ang = float(row['ang'])
29
+ # Convert angle (in degrees) to radians
30
+ rad = math.radians(ang)
31
+ # Compute displacement vector from magnitude and angle
32
+ dx = mag * math.cos(rad)
33
+ dy = mag * math.sin(rad)
34
+ # Accumulate the displacement over frames
35
+ cumulative_dx += dx
36
+ cumulative_dy += dy
37
+ # Store the negative cumulative offset to counteract motion
38
+ motion_data[frame_num] = (-cumulative_dx, -cumulative_dy)
39
+ return motion_data
40
+
41
+ def stabilize_video_using_csv(video_file, csv_file, zoom=1.0, output_file=None):
42
+ """
43
+ Stabilizes the input video using motion data from the CSV file.
44
+
45
+ Args:
46
+ video_file (str): Path to the input video.
47
+ csv_file (str): Path to the CSV file generated by the detection code.
48
+ zoom (float): Optional zoom factor to apply before stabilization (default: 1.0).
49
+ output_file (str): Path for the output stabilized video. If None, a temporary file is created.
50
+
51
+ Returns:
52
+ output_file (str): The path to the stabilized video file.
53
+ """
54
+ # Read motion data from CSV
55
+ motion_data = read_motion_csv(csv_file)
56
+
57
+ cap = cv2.VideoCapture(video_file)
58
+ if not cap.isOpened():
59
+ raise ValueError("Could not open video file.")
60
+
61
+ fps = cap.get(cv2.CAP_PROP_FPS)
62
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
63
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
64
+
65
+ # Create a temporary file for output if not provided
66
+ if output_file is None:
67
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
68
+ output_file = temp_file.name
69
+ temp_file.close()
70
+
71
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
72
+ out = cv2.VideoWriter(output_file, fourcc, fps, (width, height))
73
+
74
+ frame_num = 1
75
+ while True:
76
+ ret, frame = cap.read()
77
+ if not ret:
78
+ break
79
+
80
+ # Optionally apply zoom (resize and center-crop)
81
+ if zoom != 1.0:
82
+ zoomed_frame = cv2.resize(frame, None, fx=zoom, fy=zoom, interpolation=cv2.INTER_LINEAR)
83
+ zoomed_h, zoomed_w = zoomed_frame.shape[:2]
84
+ start_x = max((zoomed_w - width) // 2, 0)
85
+ start_y = max((zoomed_h - height) // 2, 0)
86
+ frame = zoomed_frame[start_y:start_y+height, start_x:start_x+width]
87
+
88
+ # Retrieve stabilization offset from CSV data (if available)
89
+ dx, dy = motion_data.get(frame_num, (0, 0))
90
+
91
+ # Apply an affine transformation to counteract the motion
92
+ transform = np.array([[1, 0, dx],
93
+ [0, 1, dy]], dtype=np.float32)
94
+ stabilized_frame = cv2.warpAffine(frame, transform, (width, height))
95
+
96
+ out.write(stabilized_frame)
97
+ frame_num += 1
98
+
99
+ cap.release()
100
+ out.release()
101
+ return output_file
102
+
103
+ def process_video(video_file, csv_file, zoom):
104
+ """
105
+ Gradio interface function to stabilize a video.
106
+ Accepts an input video file, a motion CSV file, and a zoom factor.
107
+ Returns the original video and the stabilized video.
108
+ """
109
+ # Convert input file objects to file paths if needed
110
+ if isinstance(video_file, dict):
111
+ video_file = video_file["name"]
112
+ if isinstance(csv_file, dict):
113
+ csv_file = csv_file["name"]
114
+
115
+ stabilized_path = stabilize_video_using_csv(video_file, csv_file, zoom=zoom)
116
+ return video_file, stabilized_path
117
+
118
+ with gr.Blocks() as demo:
119
+ gr.Markdown("# Video Stabilization with Motion Data")
120
+ with gr.Row():
121
+ with gr.Column():
122
+ video_input = gr.Video(label="Input Video")
123
+ csv_input = gr.File(label="Motion CSV File (e.g., video.flow.csv)", file_count="single")
124
+ zoom_slider = gr.Slider(minimum=1.0, maximum=2.0, step=0.1, value=1.0, label="Zoom Factor")
125
+ process_button = gr.Button("Stabilize Video")
126
+ with gr.Column():
127
+ original_video = gr.Video(label="Original Video")
128
+ stabilized_video = gr.Video(label="Stabilized Video")
129
+
130
+ process_button.click(
131
+ fn=process_video,
132
+ inputs=[video_input, csv_input, zoom_slider],
133
+ outputs=[original_video, stabilized_video]
134
+ )
135
+
136
+ demo.launch()