FutureFabrik commited on
Commit
3425a7c
·
verified ·
1 Parent(s): 58ce335

This web application allows users to sort and group frame images extracted from multiple camera folders. Users upload ZIP files (each containing frame images from a specific camera), then specify a regex pattern (with one capturing group) and the start and end frame numbers. The app extracts the ZIP files, uses the regex to determine each image’s frame number, calculates a frame index (so that the image corresponding to the start frame becomes Frame 1), and then groups images from all cameras into corresponding frame folders (e.g., Frame_1, Frame_2, etc.). Finally, the sorted frames are compressed into a downloadable ZIP file.

Files changed (1) hide show
  1. app.py +134 -0
app.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import shutil
4
+ import tempfile
5
+ import zipfile
6
+
7
+ import gradio as gr
8
+
9
+ def process_zips(camera_zips, regex_pattern, start_frame, end_frame):
10
+ """
11
+ Processes uploaded ZIP files containing frame images from one or more cameras.
12
+
13
+ Args:
14
+ camera_zips (list): A list of uploaded ZIP files (each representing one camera folder).
15
+ regex_pattern (str): A regex pattern with one capturing group that extracts the numeric frame value.
16
+ start_frame (str): The start frame number (as string, will be converted to int).
17
+ end_frame (str): The end frame number (as string, will be converted to int).
18
+
19
+ Returns:
20
+ str: The path to the output ZIP file containing the sorted frames.
21
+
22
+ The function:
23
+ 1. Extracts each uploaded ZIP into a temporary folder.
24
+ 2. Uses the ZIP file name (without extension) as the camera name.
25
+ 3. Iterates over every file in the extracted folder, applying the regex to extract the numeric frame.
26
+ 4. For files whose numeric value is between start_frame and end_frame (inclusive),
27
+ computes the frame index as:
28
+ frame_index = extracted_number - start_frame + 1
29
+ 5. Copies each matching file into an output folder structure where each frame index gets its own folder.
30
+ 6. Compresses the entire output directory into a ZIP file and returns its path.
31
+ """
32
+ try:
33
+ start_frame = int(start_frame)
34
+ end_frame = int(end_frame)
35
+ except ValueError:
36
+ return "Error: Start and End frame numbers must be integers."
37
+
38
+ if start_frame > end_frame:
39
+ return "Error: Start frame must be less than or equal to End frame."
40
+
41
+ total_frames = end_frame - start_frame + 1
42
+
43
+ # Create a temporary output directory for sorted frames
44
+ output_dir = tempfile.mkdtemp(prefix="sorted_frames_")
45
+
46
+ # List to hold (camera_name, folder) tuples
47
+ camera_folders = []
48
+
49
+ for uploaded_zip in camera_zips:
50
+ # Save the uploaded ZIP to a temporary file
51
+ temp_zip_path = os.path.join(tempfile.gettempdir(), uploaded_zip.name)
52
+ with open(temp_zip_path, "wb") as f:
53
+ f.write(uploaded_zip.read())
54
+
55
+ # Create a temporary directory to extract the ZIP contents
56
+ extract_dir = os.path.join(tempfile.gettempdir(), uploaded_zip.name + "_extracted")
57
+ os.makedirs(extract_dir, exist_ok=True)
58
+ with zipfile.ZipFile(temp_zip_path, "r") as zip_ref:
59
+ zip_ref.extractall(extract_dir)
60
+
61
+ # If the ZIP extracts to a single subdirectory, use that folder
62
+ subdirs = [os.path.join(extract_dir, d) for d in os.listdir(extract_dir)
63
+ if os.path.isdir(os.path.join(extract_dir, d))]
64
+ camera_folder = subdirs[0] if len(subdirs) == 1 else extract_dir
65
+
66
+ # Use the ZIP filename (without extension) as the camera name
67
+ camera_name = os.path.splitext(uploaded_zip.name)[0]
68
+ camera_folders.append((camera_name, camera_folder))
69
+
70
+ # Build a mapping for each camera: { frame_index: file_full_path }
71
+ camera_mappings = {}
72
+ for camera_name, folder in camera_folders:
73
+ mapping = {}
74
+ for file_name in os.listdir(folder):
75
+ full_path = os.path.join(folder, file_name)
76
+ if os.path.isfile(full_path):
77
+ try:
78
+ m = re.search(regex_pattern, file_name)
79
+ except re.error as e:
80
+ print(f"Regex error on file {file_name}: {e}")
81
+ continue
82
+ if m:
83
+ try:
84
+ num = int(m.group(1))
85
+ except ValueError:
86
+ continue
87
+ if start_frame <= num <= end_frame:
88
+ frame_index = num - start_frame + 1
89
+ mapping[frame_index] = full_path
90
+ camera_mappings[camera_name] = mapping
91
+
92
+ # Create output subfolders for each frame index and copy matching files from each camera
93
+ for frame_index in range(1, total_frames + 1):
94
+ frame_folder = os.path.join(output_dir, f"Frame_{frame_index}")
95
+ os.makedirs(frame_folder, exist_ok=True)
96
+ for camera_name, mapping in camera_mappings.items():
97
+ if frame_index in mapping:
98
+ src_file = mapping[frame_index]
99
+ file_base = os.path.basename(src_file)
100
+ # Rename the file by prefixing it with the camera name
101
+ dst_file = os.path.join(frame_folder, f"{camera_name}_{file_base}")
102
+ try:
103
+ shutil.copy(src_file, dst_file)
104
+ except Exception as e:
105
+ print(f"Error copying {src_file} to {dst_file}: {e}")
106
+
107
+ # Compress the output directory into a ZIP file
108
+ output_zip_base = os.path.join(tempfile.gettempdir(), "sorted_frames")
109
+ shutil.make_archive(base_name=output_zip_base, format="zip", root_dir=output_dir)
110
+ output_zip_path = output_zip_base + ".zip"
111
+
112
+ return output_zip_path
113
+
114
+ # Create the Gradio interface
115
+ iface = gr.Interface(
116
+ fn=process_zips,
117
+ inputs=[
118
+ gr.File(label="Camera Folder ZIPs", file_count="multiple", type="bytes"),
119
+ gr.Textbox(label="Regex Pattern (with one capturing group)"),
120
+ gr.Textbox(label="Start Frame Number"),
121
+ gr.Textbox(label="End Frame Number")
122
+ ],
123
+ outputs=gr.File(label="Download Sorted Frames ZIP"),
124
+ title="Frame Sorting Tool",
125
+ description=(
126
+ "Upload one or more ZIP files (each representing a camera folder with frame files), "
127
+ "enter a regex pattern (for example, `_(\\d+)`), and provide the start and end frame numbers. "
128
+ "The tool will group frames by frame index (so that frame 1 from all cameras is together) "
129
+ "and return a downloadable ZIP file with the sorted frames."
130
+ )
131
+ )
132
+
133
+ if __name__ == "__main__":
134
+ iface.launch()