Carlexx commited on
Commit
a6dc114
·
verified ·
1 Parent(s): 92ded17

Create app.ly

Browse files
Files changed (1) hide show
  1. app.ly +180 -0
app.ly ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import numpy as np
4
+ from skimage.metrics import structural_similarity as ssim
5
+ import matplotlib.pyplot as plt
6
+ from PIL import Image
7
+ import imagehash
8
+ import os
9
+ import math
10
+
11
+ # --- Constantes ---
12
+ THUMBNAIL_HEIGHT = 100 # Altura de cada miniatura na timeline
13
+
14
+ # --- Funções de Análise (mesmas de antes, mas adaptadas para Gradio) ---
15
+
16
+ def analisar_video(video_path, progress=gr.Progress()):
17
+ """Função principal que processa o vídeo e gera os artefatos de saída."""
18
+ if video_path is None:
19
+ raise gr.Error("Por favor, faça o upload de um arquivo de vídeo.")
20
+
21
+ # 1. Extrair Frames
22
+ progress(0, desc="Carregando vídeo e extraindo frames...")
23
+ cap = cv2.VideoCapture(video_path)
24
+ frames = []
25
+ fps = cap.get(cv2.CAP_PROP_FPS)
26
+ while True:
27
+ ret, frame = cap.read()
28
+ if not ret:
29
+ break
30
+ frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # Gradio usa RGB
31
+ cap.release()
32
+
33
+ if not frames:
34
+ raise gr.Error("Não foi possível ler os frames do vídeo.")
35
+
36
+ # 2. Análise Frame-a-Frame
37
+ ssim_scores = []
38
+ phash_distances = []
39
+ num_frames = len(frames)
40
+
41
+ for i in progress.tqdm(range(num_frames - 1), desc="Analisando transições..."):
42
+ frame_atual = frames[i]
43
+ proximo_frame = frames[i+1]
44
+
45
+ # Converte para cinza para SSIM
46
+ gray1 = cv2.cvtColor(frame_atual, cv2.COLOR_RGB2GRAY)
47
+ gray2 = cv2.cvtColor(proximo_frame, cv2.COLOR_RGB2GRAY)
48
+ ssim_val, _ = ssim(gray1, gray2, full=True)
49
+
50
+ # Converte para PIL para pHash
51
+ pil_img1 = Image.fromarray(frame_atual)
52
+ pil_img2 = Image.fromarray(proximo_frame)
53
+ phash_dist = imagehash.phash(pil_img1) - imagehash.phash(pil_img2)
54
+
55
+ ssim_scores.append(ssim_val)
56
+ phash_distances.append(phash_dist)
57
+
58
+ # 3. Gerar Gráfico
59
+ progress(0.8, desc="Gerando gráfico de análise...")
60
+ grafico_path = gerar_grafico_analise(ssim_scores, phash_distances, num_frames, fps)
61
+
62
+ # 4. Gerar Timeline Visual
63
+ progress(0.9, desc="Criando timeline de miniaturas...")
64
+ timeline_path = gerar_timeline_visual(frames, num_frames, fps)
65
+
66
+ return grafico_path, timeline_path
67
+
68
+ def gerar_grafico_analise(ssim_scores, phash_distances, num_frames, fps):
69
+ """Gera e salva um gráfico com as métricas de análise."""
70
+ x_axis_frames = range(num_frames - 1)
71
+ x_axis_time = [i / fps for i in x_axis_frames]
72
+
73
+ fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(16, 10), sharex=True)
74
+ fig.suptitle('Análise Quantitativa da Coerência do Vídeo', fontsize=16)
75
+
76
+ # --- Gráfico 1: SSIM ---
77
+ ax1.plot(x_axis_time, ssim_scores, color='tab:blue', lw=2)
78
+ ax1.set_ylabel('Índice SSIM (1.0 = Perfeito)')
79
+ ax1.set_title('Métrica 1: Fidelidade do Eco e Continuidade da Cena')
80
+ ax1.grid(True, linestyle='--', alpha=0.6)
81
+ ax1.set_ylim(0, 1.05)
82
+ ax1.axhline(y=0.9, color='green', linestyle='--', label='Limiar de Alta Fidelidade (0.9)')
83
+ ax1.legend()
84
+
85
+ # --- Gráfico 2: pHash ---
86
+ ax2.plot(x_axis_time, phash_distances, color='tab:red', lw=2)
87
+ ax2.set_ylabel('Distância pHash (0 = Idêntico)')
88
+ ax2.set_title('Métrica 2: Detecção de Transições Semânticas e Cortes')
89
+ ax2.grid(True, linestyle='--', alpha=0.6)
90
+ ax2.axhline(y=10, color='orange', linestyle='--', label='Limiar de Corte Forte (>10)')
91
+ ax2.legend()
92
+
93
+ ax2.set_xlabel('Tempo (segundos)')
94
+
95
+ plt.tight_layout(rect=[0, 0.03, 1, 0.95])
96
+
97
+ grafico_path = 'analise_fidelidade.png'
98
+ plt.savefig(grafico_path)
99
+ plt.close() # Libera memória
100
+ return grafico_path
101
+
102
+ def gerar_timeline_visual(frames, num_frames, fps):
103
+ """Cria uma única imagem com miniaturas de frames em intervalos regulares."""
104
+ intervalo_frames = 8
105
+ indices_selecionados = list(range(0, num_frames, intervalo_frames))
106
+
107
+ thumbnails = []
108
+ for i in indices_selecionados:
109
+ frame = Image.fromarray(frames[i])
110
+ # Redimensiona mantendo a proporção
111
+ aspect_ratio = frame.width / frame.height
112
+ new_width = int(THUMBNAIL_HEIGHT * aspect_ratio)
113
+ thumbnail = frame.resize((new_width, THUMBNAIL_HEIGHT), Image.Resampling.LANCZOS)
114
+ thumbnails.append(thumbnail)
115
+
116
+ # Calcula o tamanho da imagem final
117
+ total_width = sum(t.width for t in thumbnails)
118
+ max_height = THUMBNAIL_HEIGHT
119
+
120
+ # Cria a imagem da timeline
121
+ timeline_img = Image.new('RGB', (total_width, max_height + 40), (255, 255, 255))
122
+ from PIL import ImageDraw, ImageFont
123
+ draw = ImageDraw.Draw(timeline_img)
124
+ try:
125
+ font = ImageFont.truetype("DejaVuSans.ttf", 15)
126
+ except IOError:
127
+ font = ImageFont.load_default()
128
+
129
+ current_x = 0
130
+ for i, thumb in enumerate(thumbnails):
131
+ timeline_img.paste(thumb, (current_x, 0))
132
+ # Adiciona o timestamp
133
+ frame_idx = indices_selecionados[i]
134
+ timestamp = frame_idx / fps
135
+ draw.text((current_x + 5, max_height + 5), f"{timestamp:.1f}s", fill=(0,0,0), font=font)
136
+ current_x += thumb.width
137
+
138
+ timeline_path = 'timeline_visual.png'
139
+ timeline_img.save(timeline_path)
140
+ return timeline_path
141
+
142
+ # --- Interface Gradio ---
143
+
144
+ with gr.Blocks(theme=gr.themes.Soft(), title="Analisador de Coerência ADUC-SDR") as demo:
145
+ gr.Markdown(
146
+ """
147
+ # Prova Científica da Arquitetura ADUC-SDR
148
+ ### Validação Quantitativa da Coerência Narrativa e Fidelidade do Eco
149
+ Faça o upload de um vídeo gerado para mapear matematicamente sua estabilidade e transições.
150
+ Este Space analisa cada frame para provar a continuidade mantida pela arquitetura.
151
+ Desenvolvido a partir do projeto: [carlex22/Aduc-sdr](https://github.com/carlex22/Aduc-sdr).
152
+ """
153
+ )
154
+
155
+ with gr.Row():
156
+ with gr.Column(scale=1):
157
+ video_input = gr.Video(label="Upload do Vídeo", sources=["upload"])
158
+ analyze_button = gr.Button("Analisar Vídeo", variant="primary")
159
+
160
+ with gr.Column(scale=2):
161
+ gr.Markdown("### **Resultados da Análise**")
162
+ plot_output = gr.Image(label="Gráfico de Análise (SSIM e pHash)", type="filepath")
163
+ timeline_output = gr.Image(label="Timeline Visual (A cada 8 frames)", type="filepath")
164
+
165
+ analyze_button.click(
166
+ fn=analisar_video,
167
+ inputs=[video_input],
168
+ outputs=[plot_output, timeline_output]
169
+ )
170
+
171
+ gr.Examples(
172
+ [["https://huggingface.co/spaces/carlex22/aduc-sdr/resolve/main/video.mp4"]],
173
+ inputs=[video_input],
174
+ )
175
+
176
+
177
+ if __name__ == "__main__":
178
+ # Para rodar localmente com GPU, você pode precisar configurar o PyTorch.
179
+ # No HF Spaces, a GPU é gerenciada pelo ambiente.
180
+ demo.queue().launch(share=True)