vagrillo commited on
Commit
0d635bf
·
verified ·
1 Parent(s): edd1986

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -290
app.py CHANGED
@@ -1,292 +1,86 @@
1
- import torch
2
- from PIL import Image, ImageDraw, ImageFont
3
- from transformers import GroundingDinoProcessor
4
- from modeling_grounding_dino import GroundingDinoForObjectDetection
5
-
6
- from PIL import Image, ImageDraw, ImageFont
7
- from itertools import cycle
8
- import os
9
- from datetime import datetime
10
- import gradio as gr
11
- import tempfile
12
-
13
- # Load model and processor
14
- model_id = "fushh7/llmdet_swin_large_hf"
15
- model_id = "fushh7/llmdet_swin_tiny_hf"
16
- DEVICE = "cpu"
17
-
18
- print(f"[INFO] Using device: {DEVICE}")
19
- print(f"[INFO] Loading model from {model_id}...")
20
-
21
- processor = GroundingDinoProcessor.from_pretrained(model_id)
22
- model = GroundingDinoForObjectDetection.from_pretrained(model_id).to(DEVICE)
23
- model.eval()
24
-
25
- print("[INFO] Model loaded successfully.")
26
-
27
- # Pre-defined palette (extend or tweak as you like)
28
- BOX_COLORS = [
29
- "deepskyblue", "red", "lime", "dodgerblue",
30
- "cyan", "magenta", "yellow",
31
- "orange", "chartreuse"
32
- ]
33
-
34
- def save_cropped_images(original_image, boxes, labels, scores):
35
- """
36
- Salva ogni regione ritagliata definita dalle bounding box in file temporanei.
37
-
38
- :param original_image: Immagine PIL originale
39
- :param boxes: Lista di bounding box [x_min, y_min, x_max, y_max]
40
- :param labels: Lista di etichette per ogni box
41
- :param scores: Lista di punteggi di confidenza
42
- :return: Lista dei percorsi dei file temporanei salvati
43
- """
44
- saved_paths = []
45
-
46
- for i, (box, label, score) in enumerate(zip(boxes, labels, scores)):
47
- # Crea un file temporaneo
48
- with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_file:
49
- filepath = tmp_file.name
50
-
51
- # Ritaglia la regione dall'immagine originale
52
- cropped_img = original_image.crop(box)
53
-
54
- # Salva l'immagine ritagliata
55
- cropped_img.save(filepath)
56
- saved_paths.append(filepath)
57
-
58
- return saved_paths
59
-
60
- def draw_boxes(image, boxes, labels, scores, colors=BOX_COLORS, font_path="arial.ttf", font_size=16):
61
- """
62
- Draw bounding boxes and labels on a PIL Image.
63
-
64
- :param image: PIL Image object
65
- :param boxes: Iterable of [x_min, y_min, x_max, y_max]
66
- :param labels: Iterable of label strings
67
- :param scores: Iterable of scalar confidences (0-1)
68
- :param colors: List/tuple of colour names or RGB tuples
69
- :param font_path: Path to a TTF font for labels
70
- :param font_size: Int size of font to use, default 16
71
- :return: PIL Image with drawn boxes
72
- """
73
- # Ensure we can iterate colours indefinitely
74
- colour_cycle = cycle(colors)
75
- draw = ImageDraw.Draw(image)
76
-
77
- # Pick a font (fallback to default if missing)
78
- try:
79
- font = ImageFont.truetype(font_path, size=font_size)
80
- except IOError:
81
- font = ImageFont.load_default(size=font_size)
82
-
83
- # Assign a consistent colour per label (optional)
84
- label_to_colour = {}
85
-
86
- for box, label, score in zip(boxes, labels, scores):
87
- # Reuse colour if label seen before, else take next from cycle
88
- colour = label_to_colour.setdefault(label, next(colour_cycle))
89
-
90
- x_min, y_min, x_max, y_max = map(int, box)
91
-
92
- # Draw rectangle
93
- draw.rectangle([x_min, y_min, x_max, y_max], outline=colour, width=2)
94
-
95
- # Compose text
96
- text = f"{label} ({score:.3f})"
97
- text_size = draw.textbbox((0, 0), text, font=font)[2:]
98
-
99
- # Draw text background for legibility
100
- bg_coords = [x_min, y_min - text_size[1] - 4,
101
- x_min + text_size[0] + 4, y_min]
102
- draw.rectangle(bg_coords, fill=colour)
103
-
104
- # Draw text
105
- draw.text((x_min + 2, y_min - text_size[1] - 2),
106
- text, fill="black", font=font)
107
-
108
- return image
109
-
110
- def resize_image_max_dimension(image, max_size=4096):
111
- """
112
- Resize an image so that the longest side is at most max_size pixels,
113
- while maintaining the aspect ratio.
114
-
115
- :param image: PIL Image object
116
- :param max_size: Maximum dimension in pixels (default: 1024)
117
- :return: PIL Image object (resized)
118
- """
119
- width, height = image.size
120
-
121
- # Check if resizing is needed
122
- # if max(width, height) <= max_size:
123
- # return image
124
-
125
- # Calculate new dimensions maintaining aspect ratio
126
- ratio = max_size / max(width, height)
127
- new_width = int(width * ratio)
128
- new_height = int(height * ratio)
129
-
130
- # Resize the image using high-quality resampling
131
- return image.resize((new_width, new_height), Image.Resampling.LANCZOS)
132
-
133
- def detect_and_draw(
134
- img: Image.Image,
135
- text_query: str,
136
- box_threshold: float = 0.14,
137
- text_threshold: float = 0.13,
138
- save_crops: bool = True
139
- ):
140
- """
141
- Detect objects described in `text_query`, draw boxes, return the image and crops.
142
- Note: `text_query` must be lowercase and each concept ends with a dot
143
- (e.g. 'a cat. a remote control.')
144
- """
145
-
146
- # Make sure text is lowered
147
- text_query = text_query.lower()
148
-
149
- # If the image size is too large, we make it smaller
150
- img = resize_image_max_dimension(img, max_size=4096)
151
-
152
- # Preprocess the image
153
- inputs = processor(images=img, text=text_query, return_tensors="pt").to(DEVICE)
154
-
155
- with torch.no_grad():
156
- outputs = model(**inputs)
157
-
158
- results = processor.post_process_grounded_object_detection(
159
- outputs,
160
- inputs.input_ids,
161
- text_threshold=text_threshold,
162
- target_sizes=[img.size[::-1]]
163
- )[0]
164
-
165
- img_out = img.copy()
166
- img_out = draw_boxes(
167
- img_out,
168
- boxes = results["boxes"].cpu().numpy(),
169
- labels = results.get("text_labels", results.get("labels", [])),
170
- scores = results["scores"]
171
  )
172
-
173
- # Lista per i percorsi dei crop
174
- crop_paths = []
175
-
176
- if save_crops:
177
- crop_paths = save_cropped_images(
178
- img,
179
- boxes=results["boxes"].cpu().numpy(),
180
- labels=results.get("text_labels", results.get("labels", [])),
181
- scores=results["scores"]
182
- )
183
- print(f"Generated {len(crop_paths)} cropped images")
184
-
185
- return img_out, crop_paths
186
-
187
- # Create example list
188
-
189
- # Create example list dynamically from examples directory
190
- def load_examples_from_directory(directory="examples"):
191
- """
192
- Carica automaticamente tutti i file JPG dalla directory degli esempi.
193
-
194
- :param directory: Percorso della directory contenente gli esempi
195
- :return: Lista di esempi nel formato [filepath, text_query, box_threshold, text_threshold]
196
- """
197
- examples = []
198
-
199
- # Verifica se la directory esiste
200
- if not os.path.exists(directory):
201
- print(f"[WARNING] Directory '{directory}' non trovata. Creala e aggiungi file JPG.")
202
- return examples
203
-
204
- # Cerca tutti i file JPG nella directory
205
- #jpg_files = [f for f in os.listdir(directory) if f.lower().endswith('.jpg')]
206
- jpg_files = [f for f in os.listdir(directory) if f.lower().endswith(('.jpg', '.png'))]
207
- if not jpg_files:
208
- print(f"[WARNING] Nessun file JPG trovato nella directory '{directory}'")
209
- return examples
210
-
211
- print(f"[INFO] Trovati {len(jpg_files)} file JPG nella directory examples/")
212
-
213
- # Crea gli esempi per ogni file JPG
214
- for jpg_file in jpg_files:
215
- filepath = os.path.join(directory, jpg_file)
216
- examples.append([filepath, "heads.", 0.24, 0.23])
217
-
218
- return examples
219
-
220
- # Popola automaticamente la lista degli esempi
221
- examples = load_examples_from_directory()
222
-
223
- # Se non sono stati trovati esempi, usa un esempio di fallback
224
- if not examples:
225
- print("[INFO] Usando esempio di fallback")
226
- examples = [
227
- ["examples/stickers(1).jpg", "heads.", 0.24, 0.23],
228
- ]
229
-
230
-
231
-
232
- # Funzione per pulire i file temporanei dopo l'uso
233
- def cleanup_temp_files(crop_paths):
234
- for path in crop_paths:
235
- try:
236
- os.unlink(path)
237
- except:
238
- pass
239
-
240
- # Create Gradio demo
241
- with gr.Blocks(title="VTLinuxDayDemo25", css=".gradio-container {max-width: 100% !important}") as demo:
242
- gr.Markdown("# Student Finder")
243
- gr.Markdown("Upload una foto di classe e regola le soglie.")
244
-
245
- with gr.Row():
246
- with gr.Column():
247
- image_input = gr.Image(type="pil", label="Input Image")
248
- text_query = gr.Textbox(
249
- value="heads.",
250
- label="Text Query (lowercase, end each with '.', for example 'heads. faces. hands.')"
251
- )
252
- box_threshold = gr.Slider(0.0, 1.0, 0.14, step=0.05, label="Box Threshold")
253
- text_threshold = gr.Slider(0.0, 1.0, 0.13, step=0.05, label="Text Threshold")
254
- submit_btn = gr.Button("Detect")
255
 
256
- with gr.Column():
257
- image_output = gr.Image(type="pil", label="Detections")
258
-
259
- # Galleria per i crop
260
- gallery = gr.Gallery(
261
- label="Detected Crops",
262
- columns=[4],
263
- rows=[2],
264
- object_fit="contain",
265
- height="auto"
266
- )
267
-
268
- # Esempi
269
- gr.Examples(
270
- examples=examples,
271
- inputs=[image_input, text_query, box_threshold, text_threshold],
272
- outputs=[image_output, gallery],
273
- fn=detect_and_draw,
274
- cache_examples=True
275
- )
276
-
277
- # Pulsante di submit
278
- submit_btn.click(
279
- fn=detect_and_draw,
280
- inputs=[image_input, text_query, box_threshold, text_threshold],
281
- outputs=[image_output, gallery]
282
- )
283
-
284
- # Pulisci i file temporanei quando viene caricato un nuovo esempio
285
- demo.load(
286
- fn=lambda: None,
287
- inputs=None,
288
- outputs=None,
289
- )
290
-
291
- if __name__ == "__main__":
292
- demo.launch(server_name="0.0.0.0", share=False)
 
 
 
 
 
1
+ from flask import Flask, request, render_template, redirect, url_for, make_response
2
+ import datetime
3
+
4
+ app = Flask(__name__)
5
+ SECRET_PASSWORD = "VeronaTrento25!"
6
+ COOKIE_NAME = "authenticated"
7
+
8
+ def is_authenticated():
9
+ """Verifica se l'utente è autenticato tramite cookie"""
10
+ auth_cookie = request.cookies.get(COOKIE_NAME)
11
+ if auth_cookie == "true":
12
+ return True
13
+ return False
14
+
15
+ def set_auth_cookie(response):
16
+ """Imposta il cookie di autenticazione per 24 ore"""
17
+ expires = datetime.datetime.now() + datetime.timedelta(hours=24)
18
+ response.set_cookie(
19
+ COOKIE_NAME,
20
+ "true",
21
+ expires=expires,
22
+ httponly=True,
23
+ secure=False # Imposta True in produzione con HTTPS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  )
25
+ return response
26
+
27
+ @app.route('/')
28
+ def index():
29
+ # Se l'utente è già autenticato, mostra il contenuto normale
30
+ if is_authenticated():
31
+ return render_template('index.html') # Sostituisci con il tuo template
32
+
33
+ # Altrimenti reindirizza alla pagina di login
34
+ return redirect(url_for('login'))
35
+
36
+ @app.route('/login', methods=['GET', 'POST'])
37
+ def login():
38
+ # Se l'utente è già autenticato, reindirizza alla home
39
+ if is_authenticated():
40
+ return redirect(url_for('index'))
41
+
42
+ error = None
43
+ if request.method == 'POST':
44
+ password = request.form.get('password')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ if password == SECRET_PASSWORD:
47
+ # Password corretta, crea risposta e imposta cookie
48
+ response = make_response(redirect(url_for('index')))
49
+ response = set_auth_cookie(response)
50
+ return response
51
+ else:
52
+ error = "Password errata. Riprova."
53
+
54
+ return render_template('login.html', error=error)
55
+
56
+ @app.route('/logout')
57
+ def logout():
58
+ """Route per il logout (elimina il cookie)"""
59
+ response = make_response(redirect(url_for('login')))
60
+ response.set_cookie(COOKIE_NAME, '', expires=0)
61
+ return response
62
+
63
+ # Aggiungi questo decoratore a tutte le route che vuoi proteggere
64
+ def require_auth(f):
65
+ """Decorator per proteggere le route"""
66
+ def decorated_function(*args, **kwargs):
67
+ if not is_authenticated():
68
+ return redirect(url_for('login'))
69
+ return f(*args, **kwargs)
70
+ decorated_function.__name__ = f.__name__
71
+ return decorated_function
72
+
73
+ # Esempio di utilizzo del decorator su altre route
74
+ @app.route('/protected')
75
+ @require_auth
76
+ def protected_route():
77
+ return "Questa è una pagina protetta!"
78
+
79
+ # Le tue route esistenti vanno modificate aggiungendo @require_auth
80
+ # @app.route('/tua_route')
81
+ # @require_auth
82
+ # def tua_funzione():
83
+ # return render_template('tuo_template.html')
84
+
85
+ if __name__ == '__main__':
86
+ app.run(debug=True)