Riolit commited on
Commit
4794db2
·
verified ·
1 Parent(s): 4287351

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +105 -0
  2. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {\rtf1\ansi\ansicpg1252\cocoartf2822
2
+ \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
3
+ {\colortbl;\red255\green255\blue255;}
4
+ {\*\expandedcolortbl;;}
5
+ \paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
6
+ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
7
+
8
+ \f0\fs24 \cf0 import cv2\
9
+ import zipfile\
10
+ import os\
11
+ import tempfile\
12
+ import gradio as gr\
13
+ \
14
+ \
15
+ def extract_frames_to_zip(video_path, num_frames=10):\
16
+ cap = cv2.VideoCapture(video_path)\
17
+ if not cap.isOpened():\
18
+ raise RuntimeError(f"Could not open video: \{video_path\}")\
19
+ \
20
+ frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\
21
+ if frame_count <= 0:\
22
+ raise RuntimeError("Could not determine frame count.")\
23
+ \
24
+ num_frames = min(num_frames, frame_count)\
25
+ \
26
+ if num_frames == 1:\
27
+ frame_indices = [0]\
28
+ else:\
29
+ frame_indices = [\
30
+ round(i * (frame_count - 1) / (num_frames - 1))\
31
+ for i in range(num_frames)\
32
+ ]\
33
+ \
34
+ # Create a temp directory for this run\
35
+ tmp_dir = tempfile.mkdtemp()\
36
+ zip_path = os.path.join(tmp_dir, "frames.zip")\
37
+ \
38
+ with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:\
39
+ for idx, frame_idx in enumerate(frame_indices):\
40
+ cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)\
41
+ ret, frame = cap.read()\
42
+ if not ret:\
43
+ print(f"Warning: Could not read frame at index \{frame_idx\}")\
44
+ continue\
45
+ \
46
+ success, buffer = cv2.imencode(".jpg", frame)\
47
+ if not success:\
48
+ print(f"Warning: Could not encode frame at index \{frame_idx\}")\
49
+ continue\
50
+ \
51
+ filename_in_zip = f"frame_\{idx:02d\}.jpg"\
52
+ zf.writestr(filename_in_zip, buffer.tobytes())\
53
+ \
54
+ cap.release()\
55
+ return zip_path\
56
+ \
57
+ \
58
+ def gradio_fn(video_file, num_frames):\
59
+ """\
60
+ video_file: path to uploaded video (from Gradio Video input)\
61
+ num_frames: integer from slider\
62
+ """\
63
+ if video_file is None:\
64
+ raise gr.Error("Please upload a video first.")\
65
+ \
66
+ # Gradio passes a dict for Video \{ 'name': ..., 'data': ... \} in some versions,\
67
+ # but in newer versions it passes a filepath string. Handle both.\
68
+ if isinstance(video_file, dict):\
69
+ video_path = video_file.get("name") or video_file.get("data")\
70
+ else:\
71
+ video_path = video_file\
72
+ \
73
+ if not video_path or not os.path.exists(video_path):\
74
+ raise gr.Error("Uploaded video file not found on the server.")\
75
+ \
76
+ zip_path = extract_frames_to_zip(video_path, int(num_frames))\
77
+ return zip_path\
78
+ \
79
+ \
80
+ with gr.Blocks() as demo:\
81
+ gr.Markdown("# Video Frame Extractor\\nUpload a video and get N evenly spaced frames as a ZIP.")\
82
+ \
83
+ with gr.Row():\
84
+ video_input = gr.Video(label="Upload video", sources=["upload"])\
85
+ num_frames_input = gr.Slider(\
86
+ minimum=2,\
87
+ maximum=30,\
88
+ value=10,\
89
+ step=1,\
90
+ label="Number of frames to extract",\
91
+ )\
92
+ \
93
+ zip_output = gr.File(label="Download frames ZIP")\
94
+ \
95
+ run_btn = gr.Button("Extract frames")\
96
+ \
97
+ run_btn.click(\
98
+ fn=gradio_fn,\
99
+ inputs=[video_input, num_frames_input],\
100
+ outputs=[zip_output],\
101
+ )\
102
+ \
103
+ if __name__ == "__main__":\
104
+ demo.launch()\
105
+ }
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {\rtf1\ansi\ansicpg1252\cocoartf2822
2
+ \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
3
+ {\colortbl;\red255\green255\blue255;}
4
+ {\*\expandedcolortbl;;}
5
+ \paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
6
+ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
7
+
8
+ \f0\fs24 \cf0 opencv-python\
9
+ gradio\
10
+ }