leonett commited on
Commit
ee2a1ac
verified
1 Parent(s): 0a51d5b

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +111 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import os
4
+ import random
5
+ import zipfile
6
+ from PIL import Image
7
+ from datetime import datetime
8
+
9
+ def procesar_video(video_path):
10
+ try:
11
+ # Configurar directorio temporal
12
+ temp_dir = f"temp_{datetime.now().strftime('%Y%m%d%H%M%S')}"
13
+ os.makedirs(temp_dir, exist_ok=True)
14
+
15
+ # Leer el video
16
+ cap = cv2.VideoCapture(video_path)
17
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
18
+
19
+ # Seleccionar 4 fotogramas aleatorios
20
+ frame_indices = sorted(random.sample(range(total_frames), 4))
21
+ selected_frames = []
22
+
23
+ for idx in frame_indices:
24
+ cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
25
+ ret, frame = cap.read()
26
+ if ret:
27
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
28
+ img = Image.fromarray(frame_rgb)
29
+ img_path = os.path.join(temp_dir, f"frame_{idx}.jpg")
30
+ img.save(img_path)
31
+ selected_frames.append(img_path)
32
+
33
+ cap.release()
34
+
35
+ # Crear collage
36
+ images = [Image.open(img) for img in selected_frames]
37
+ collage = Image.new('RGB', (images[0].width * 2, images[0].height * 2))
38
+
39
+ collage.paste(images[0], (0, 0))
40
+ collage.paste(images[1], (images[0].width, 0))
41
+ collage.paste(images[2], (0, images[0].height))
42
+ collage.paste(images[3], (images[0].width, images[0].height))
43
+
44
+ collage_path = os.path.join(temp_dir, "collage.jpg")
45
+ collage.save(collage_path)
46
+
47
+ # Crear archivo ZIP
48
+ zip_path = os.path.join(temp_dir, "frames.zip")
49
+ with zipfile.ZipFile(zip_path, 'w') as zipf:
50
+ for img in selected_frames:
51
+ zipf.write(img, os.path.basename(img))
52
+
53
+ return collage_path, zip_path, temp_dir
54
+
55
+ except Exception as e:
56
+ raise gr.Error(f"Error al procesar el video: {str(e)}")
57
+
58
+ def limpiar_cache(temp_dir):
59
+ if temp_dir and os.path.exists(temp_dir):
60
+ for file in os.listdir(temp_dir):
61
+ os.remove(os.path.join(temp_dir, file))
62
+ os.rmdir(temp_dir)
63
+
64
+ with gr.Blocks(title="Extracci贸n de Fotogramas Forenses") as demo:
65
+ gr.Markdown("# Herramienta de Extracci贸n de Fotogramas Forenses")
66
+ gr.Markdown("**Carga un video para extraer 4 fotogramas aleatorios y generar un collage.**")
67
+ gr.Markdown("Desarrollado por Jos茅 R. Leonett para el Grupo de Peritos Forenses Digitales de Guatemala - [www.forensedigital.gt](https://www.forensedigital.gt)")
68
+
69
+ with gr.Row():
70
+ with gr.Column():
71
+ video_input = gr.Video(label="Subir Video", interactive=True)
72
+ procesar_btn = gr.Button("Procesar Fotogramas", interactive=False)
73
+
74
+ with gr.Column():
75
+ gallery_output = gr.Image(label="Collage de Fotogramas")
76
+ download_btn = gr.Button("DESCARGAR FOTOGRAMAS", interactive=False)
77
+
78
+ temp_dir_state = gr.State()
79
+
80
+ def habilitar_procesar(video):
81
+ return gr.Button(interactive=True) if video else gr.Button(interactive=False)
82
+
83
+ def procesar_y_mostrar(video):
84
+ limpiar_cache(temp_dir_state.value)
85
+ collage_path, zip_path, temp_dir = procesar_video(video)
86
+ return collage_path, zip_path, temp_dir, gr.Button(interactive=True)
87
+
88
+ def actualizar_descarga(temp_dir):
89
+ return gr.Button(interactive=bool(temp_dir))
90
+
91
+ video_input.change(
92
+ fn=habilitar_procesar,
93
+ inputs=video_input,
94
+ outputs=procesar_btn,
95
+ queue=False
96
+ )
97
+
98
+ procesar_btn.click(
99
+ fn=procesar_y_mostrar,
100
+ inputs=video_input,
101
+ outputs=[gallery_output, download_btn, temp_dir_state, download_btn],
102
+ )
103
+
104
+ download_btn.click(
105
+ fn=lambda temp_dir: os.path.join(temp_dir, "frames.zip"),
106
+ inputs=temp_dir_state,
107
+ outputs=gr.File(label="Frames descargados"),
108
+ )
109
+
110
+ if __name__ == "__main__":
111
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ opencv-python-headless
3
+ pillow