Spaces:
Running
Running
File size: 5,377 Bytes
ee2a1ac 32450de ee2a1ac 57ef3c4 ee2a1ac 57ef3c4 32450de ee2a1ac 32450de d785524 ee2a1ac 4c40bba ee2a1ac 4c40bba ee2a1ac 32450de 4c40bba 32450de d785524 4c40bba ee2a1ac af3b295 d785524 af3b295 4c40bba af3b295 ee2a1ac 32450de d785524 32450de ee2a1ac d785524 32450de ee2a1ac d785524 4c40bba ee2a1ac d785524 ee2a1ac 4c40bba ee2a1ac 4c40bba ee2a1ac 32450de ee2a1ac 32450de d785524 ee2a1ac 32450de ee2a1ac 32450de ee2a1ac 32450de d785524 32450de ee2a1ac 32450de ee2a1ac af3b295 5bd8421 d785524 af3b295 ee2a1ac af3b295 57ef3c4 4c40bba ee2a1ac d785524 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
import gradio as gr
import cv2
import os
import random
import zipfile
from PIL import Image
from datetime import datetime
import io
import hashlib
def procesar_video(video):
try:
if isinstance(video, dict):
original_name = video.get("name", "video")
video_path = video.get("file", video.get("data"))
else:
original_name = os.path.basename(video)
video_path = video
allowed_extensions = ('.mp4', '.avi', '.mov', '.mkv')
if not original_name.lower().endswith(allowed_extensions):
raise gr.Error("Solo se permiten archivos de video (mp4, avi, mov, mkv)")
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
temp_dir = f"temp_{datetime.now().strftime('%Y%m%d%H%M%S')}"
os.makedirs(temp_dir, exist_ok=True)
# Extracci贸n de fotogramas
cap = cv2.VideoCapture(video_path)
frame_count = 0
frame_paths = []
while True:
ret, frame = cap.read()
if not ret:
break
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = Image.fromarray(frame_rgb)
img_path = os.path.join(temp_dir, f"frame_{frame_count:04d}.jpg")
img.save(img_path)
frame_paths.append(img_path)
frame_count += 1
cap.release()
if frame_count == 0:
raise gr.Error("No se pudieron extraer fotogramas del video")
# Crear collage
selected_frames = random.sample(frame_paths, min(4, len(frame_paths)))
images = [Image.open(img) for img in selected_frames]
margin = 10
collage = Image.new('RGB',
(images[0].width * 2 + margin, images[0].height * 2 + margin),
(255,255,255))
positions = [
(0, 0),
(images[0].width + margin, 0),
(0, images[0].height + margin),
(images[0].width + margin, images[0].height + margin)
]
for i, img in enumerate(images):
collage.paste(img, positions[i])
collage_path = os.path.join(temp_dir, "collage.jpg")
collage.save(collage_path)
# Generaci贸n del ZIP con todos los fotogramas
base_name = os.path.splitext(original_name)[0]
zip_filename = f"{base_name}.zip"
final_zip_path = os.path.join(temp_dir, zip_filename)
with zipfile.ZipFile(final_zip_path, mode="w") as zipf:
for img_path in frame_paths:
zipf.write(img_path, os.path.basename(img_path))
chain_content = (
f"Nombre del archivo: {original_name}\n"
f"Fecha de carga y extracci贸n: {timestamp}\n"
f"N煤mero de fotogramas: {frame_count}\n"
)
zipf.writestr("cadena_custodia.txt", chain_content)
return collage_path, final_zip_path, temp_dir
except Exception as e:
raise gr.Error(f"Error al procesar el video: {str(e)}")
def limpiar_cache(temp_dir):
if temp_dir and os.path.exists(temp_dir):
for file in os.listdir(temp_dir):
os.remove(os.path.join(temp_dir, file))
os.rmdir(temp_dir)
with gr.Blocks(title="Extracci贸n de Fotogramas Forenses") as demo:
gr.Markdown("# Herramienta de Extracci贸n de Fotogramas Forenses")
gr.Markdown("**Carga un video para extraer TODOS los fotogramas y generar un collage de muestra.**")
gr.Markdown("Desarrollado por Jos茅 R. Leonett para el Grupo de Peritos Forenses Digitales de Guatemala - [www.forensedigital.gt](https://www.forensedigital.gt)")
with gr.Row():
with gr.Column():
video_input = gr.Video(label="Subir Video", interactive=True)
procesar_btn = gr.Button("Procesar Fotogramas", interactive=False)
with gr.Column():
gallery_output = gr.Image(label="Collage de Muestra")
download_btn = gr.Button("DESCARGAR FOTOGRAMAS", interactive=False)
download_file = gr.File(label="Archivo ZIP generado", visible=False)
temp_dir_state = gr.State(None)
zip_path_state = gr.State(None)
def on_video_change(video):
if video:
return gr.update(interactive=True), gr.update(interactive=False)
return gr.update(interactive=False), gr.update(interactive=False)
video_input.change(
fn=on_video_change,
inputs=video_input,
outputs=[procesar_btn, download_btn],
queue=False
)
def procesar_y_mostrar(video):
if temp_dir_state.value:
limpiar_cache(temp_dir_state.value)
collage_path, zip_path, temp_dir = procesar_video(video)
return collage_path, zip_path, temp_dir, zip_path, gr.update(interactive=True), gr.update(interactive=False)
procesar_btn.click(
fn=procesar_y_mostrar,
inputs=video_input,
outputs=[gallery_output, download_file, temp_dir_state, zip_path_state, download_btn, procesar_btn],
)
def trigger_download(zip_path):
with open(zip_path, "rb") as f:
file_bytes = f.read()
return os.path.basename(zip_path), file_bytes
download_btn.click(
fn=trigger_download,
inputs=zip_path_state,
outputs=download_file,
)
if __name__ == "__main__":
demo.launch() |