xktan commited on
Commit
927498e
·
verified ·
1 Parent(s): de81577

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -962
app.py DELETED
@@ -1,962 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """AdAnalyst_Mar30_logo
3
-
4
- Automatically generated by Colab.
5
-
6
- Original file is located at
7
- https://colab.research.google.com/drive/1Xh3cPajDxLv2WzsW6te3eN2JO6inFYvg
8
-
9
- #0. Install Libraries (Restart runtime at the end of the download and start running from step1)
10
- """
11
-
12
- """#1. Import Libraries"""
13
-
14
- # Download the Dutch language corpus for textblob-nl
15
- import nltk
16
- nltk.download('alpino')
17
- import gradio as gr
18
- import torch
19
- import torchvision.transforms as transforms
20
- from PIL import Image, ImageDraw
21
- import timm
22
- import numpy as np
23
- import cv2
24
- import pandas as pd
25
- import re
26
- from textblob import TextBlob
27
- from textblob_nl import PatternTagger, PatternAnalyzer
28
- from sklearn.cluster import KMeans
29
- import math
30
- from ultralytics import YOLO
31
- import easyocr
32
- import sys
33
- import os
34
- import zipfile
35
- from deepface import DeepFace
36
-
37
- """#2. Dictionaries"""
38
-
39
- # Define regex pattern for URLs
40
- url_pattern = re.compile(
41
- r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|'
42
- r'(?:%[0-9a-fA-F][0-9a-fA-F]))+|www\.(\w+\.)+\w+|(\w+\.)+(nl|com))'
43
- )
44
-
45
- # Define lists for price indications, promotions, calls to action, and car brands
46
- price_indications = [r'\u20AC', '€', 'EUR', 'euro', 'euros']
47
-
48
-
49
- promotion_words = ['korting', 'aanbieding', 'uitverkoop', 'prijsverlaging', 'afprijzing', 'voordeel',
50
- 'prijsbewust', 'goedkoop', 'besparing', 'tegen een lage prijs', 'speciale aanbieding',
51
- 'prijsvermindering', 'kortingbon', 'promotiecode', 'actie', 'actieprijs', 'tijdelijke aanbieding',
52
- 'nu met korting', 'extra voordelig', 'beste deal', 'flash sale', 'superaanbieding', 'seizoensuitverkoop',
53
- 'nu extra voordelig', 'nu met voordeel', 'exclusieve korting', 'laatste kans', 'tweede gratis', 'koopje',
54
- 'knalprijs', 'megakorting', 'laagste prijs']
55
-
56
- call_to_action_phrases = ['bezoek', 'ga naar', 'dealer', 'showroom', 'garage', 'proefrit', 'testrit',
57
- 'probeer', 'bestel nu', 'koop nu', 'reserveren', 'vraag een offerte aan', 'configureren',
58
- 'ontdek meer', 'bekijk de aanbieding', 'registreer voor updates', 'neem contact op voor meer informatie',
59
- 'kom langs', 'start hier', 'doe een aanbetaling', 'ontvang een brochure', 'financieringsmogelijkheden',
60
- 'vraag om een demo', 'bestel vandaag nog', 'nu kopen', 'nu reserveren', 'meld je aan', 'schrijf je in',
61
- 'maak een afspraak', 'bel ons', 'neem contact op', 'plan je testrit', 'configureer je auto', 'klik hier',
62
- 'vraag een proefrit aan', 'vraag een offerte', 'doe mee', 'check het aanbod', 'registreer nu', 'nu ontdekken',
63
- 'bekijk onze modellen', 'bezoek onze website', 'vraag informatie aan', 'aanbetaling', 'aanvraag', 'aanvragen', 'afspraak',
64
- 'bekijk', 'bel', 'bestel', 'contact', 'configureer', 'demo', 'doe', 'download', 'financieringsmogelijkheden', 'info',
65
- 'informatie', 'kom', 'koop', 'laat je gegevens achter', 'maak', 'meld', 'neem', 'nu', 'offerte', 'ontdek', 'ontvang',
66
- 'plan', 'probeer', 'registreer', 'reserveren', 'schrijf', 'start', 'vraag', 'website']
67
-
68
- # Expanded list of major car brands
69
- car_brands = [
70
- 'ARCFOX', 'Acura', 'Aion', 'Alfa Romeo', 'Apollo', 'Artega', 'Aston Martin', 'Audi',
71
- 'BAC', 'BAIC', 'BMW', 'BYD', 'Baojun', 'Beijing', 'Bentley', 'Bestune', 'Bugatti',
72
- 'Buick', 'Cadillac', 'Caterham', 'Changan', 'Chery', 'Chevrolet', 'Chrysler', 'Citroën',
73
- 'Cupra', 'Daewoo', 'Dacia', 'Dodge', 'Dongfeng', 'DS Automobiles', 'Ferrari', 'Fiat',
74
- 'Fisker', 'Ford', 'GAC', 'GAZ', 'GMC', 'Geely', 'Genesis', 'Great Wall', 'Gumpert',
75
- 'Haval', 'Holden', 'Honda', 'Hongqi', 'Hozon Auto', 'Hummer', 'Hyundai', 'Infiniti',
76
- 'Isuzu', 'JAC', 'Jaguar', 'Jeep', 'Kia', 'Koenigsegg', 'LEVC', 'LINCOLN', 'Lamborghini',
77
- 'Land Rover', 'Leapmotor', 'Lexus', 'Li Auto', 'Lincoln', 'Lucid', 'Luxgen', 'Lynk & Co',
78
- 'MG', 'MINI', 'Mahindra', 'Maserati', 'Mazda', 'McLaren', 'Mercedes', 'Mercury',
79
- 'Mini', 'Mitsubishi', 'Morgan', 'NIO', 'Nissan', 'Noble', 'Oldsmobile', 'Opel',
80
- 'ORA', 'Pagani', 'Peugeot', 'Perodua', 'Polestar', 'Pontiac', 'Porsche', 'Proton',
81
- 'Ram', 'Reno', 'Rezvani', 'Rimac', 'Rivian', 'Rolls-Royce', 'Roewe', 'Saab', 'Saturn',
82
- 'SAIC', 'SEAT', 'SSC North America', 'Skoda', 'Smart', 'Spyker', 'SsangYong',
83
- 'Subaru', 'Suzuki', 'Tank', 'Tata', 'Tesla', 'Toyota', 'Trumpchi', 'VinFast', 'Volkswagen',
84
- 'Volvo', 'WEY', 'W Motors', 'Wiesmann', 'Xpeng', 'Zeekr'
85
- ]
86
-
87
- # COCO class names
88
- coco_classes = {
89
- 0: "person",
90
- 1: "bicycle",
91
- 2: "car",
92
- 3: "motorcycle",
93
- 4: "airplane",
94
- 5: "bus",
95
- 6: "train",
96
- 7: "truck",
97
- 8: "boat",
98
- 9: "traffic light",
99
- 10: "fire hydrant",
100
- 11: "stop sign",
101
- 12: "parking meter",
102
- 13: "bench",
103
- 14: "bird",
104
- 15: "cat",
105
- 16: "dog",
106
- 17: "horse",
107
- 18: "sheep",
108
- 19: "cow",
109
- 20: "elephant",
110
- 21: "bear",
111
- 22: "zebra",
112
- 23: "giraffe",
113
- 24: "backpack",
114
- 25: "umbrella",
115
- 26: "handbag",
116
- 27: "tie",
117
- 28: "suitcase",
118
- 29: "frisbee",
119
- 30: "skis",
120
- 31: "snowboard",
121
- 32: "sports ball",
122
- 33: "kite",
123
- 34: "baseball bat",
124
- 35: "baseball glove",
125
- 36: "skateboard",
126
- 37: "surfboard",
127
- 38: "tennis racket",
128
- 39: "bottle",
129
- 40: "wine glass",
130
- 41: "cup",
131
- 42: "fork",
132
- 43: "knife",
133
- 44: "spoon",
134
- 45: "bowl",
135
- 46: "banana",
136
- 47: "apple",
137
- 48: "sandwich",
138
- 49: "orange",
139
- 50: "broccoli",
140
- 51: "carrot",
141
- 52: "hot dog",
142
- 53: "pizza",
143
- 54: "donut",
144
- 55: "cake",
145
- 56: "chair",
146
- 57: "couch",
147
- 58: "potted plant",
148
- 59: "bed",
149
- 60: "dining table",
150
- 61: 'toilet',
151
- 62: 'tv',
152
- 63: 'laptop',
153
- 64: 'mouse',
154
- 65: 'remote',
155
- 66: 'keyboard',
156
- 67: 'cell phone',
157
- 68: 'microwave',
158
- 69: 'oven',
159
- 70: 'toaster',
160
- 71: 'sink',
161
- 72: 'refrigerator',
162
- 73: 'book',
163
- 74: 'clock',
164
- 75: 'vase',
165
- 76: 'scissors',
166
- 77: 'teddy bear',
167
- 78: 'hair drier',
168
- 79: 'toothbrush'
169
- }
170
-
171
- # Object categories as per your request
172
- animal_classes = [14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
173
- transportation_classes = [1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
174
- sports_classes = [29, 30, 31, 32, 33, 34, 35, 36, 37, 38]
175
- food_classes = [39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 60, 68, 69, 70, 71, 72]
176
-
177
- """#3. Function Modules
178
-
179
- ## Uniqueness and Consistency
180
- """
181
-
182
- # 1. Compute image embedding
183
- # Load the pre-trained ViT model
184
- def load_vit_model():
185
- model = timm.create_model('vit_base_patch16_224', pretrained=True, num_classes=0)
186
- model.eval()
187
- return model
188
-
189
- vit_model = load_vit_model()
190
-
191
- # Define image preprocessing steps
192
- def get_preprocess_transforms():
193
- return transforms.Compose([
194
- transforms.Resize(256),
195
- transforms.CenterCrop(224),
196
- transforms.ToTensor(),
197
- transforms.Normalize(
198
- mean=(0.5, 0.5, 0.5),
199
- std=(0.5, 0.5, 0.5)
200
- )
201
- ])
202
-
203
- preprocess = get_preprocess_transforms()
204
-
205
- def compute_image_embedding(image, model, preprocess):
206
- input_tensor = preprocess(image).unsqueeze(0)
207
- with torch.no_grad():
208
- embedding = model(input_tensor)
209
- return embedding.squeeze()
210
-
211
- # 2. Get embeddings from files
212
- def get_embeddings_from_files(file_list, model, preprocess):
213
- embeddings = []
214
- for file_obj in file_list:
215
- image = Image.open(file_obj.name).convert('RGB')
216
- embedding = compute_image_embedding(image, model, preprocess)
217
- embeddings.append(embedding)
218
- return embeddings
219
-
220
- # 3. Calculate similarity scores
221
- def calculate_similarity_scores(focus_embedding, embeddings_list):
222
- from torch.nn.functional import cosine_similarity
223
- similarities = []
224
- for emb in embeddings_list:
225
- sim = cosine_similarity(focus_embedding.unsqueeze(0), emb.unsqueeze(0)).item()
226
- similarities.append(sim)
227
- average_score = sum(similarities) / len(similarities) if similarities else None
228
- return round(average_score, 4) if average_score is not None else 'None'
229
-
230
- """## OCR"""
231
-
232
- # Extract textual features
233
-
234
- # load EasyOCTR model
235
- reader = easyocr.Reader(['nl','en'], gpu=False)
236
-
237
- def extract_textual_features(image):
238
-
239
- width, height = image.size
240
- image_area = width * height
241
-
242
- image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
243
-
244
- #reader = easyocr.Reader(['nl', 'en'], gpu=False)
245
-
246
- results = reader.readtext(image_cv)
247
-
248
- extracted_text_list = []
249
- total_text_area = 0
250
-
251
- mask = np.zeros((height, width), dtype=np.uint8)
252
-
253
- for (bbox, text, prob) in results:
254
- if text.strip():
255
- extracted_text_list.append(text)
256
-
257
- points = np.array(bbox, dtype=np.int32)
258
- polygon = []
259
- for point in points:
260
- polygon.append((int(point[0]), int(point[1])))
261
-
262
- temp_mask = Image.new('L', (width, height), 0)
263
- ImageDraw.Draw(temp_mask).polygon(polygon, outline=1, fill=1)
264
- temp_array = np.array(temp_mask)
265
- mask = np.logical_or(mask, temp_array).astype(np.uint8) * 255
266
-
267
- extracted_text = ' '.join(extracted_text_list).strip()
268
-
269
- num_char = len(extracted_text.replace(" ", ""))
270
-
271
- text_area = np.sum(mask > 0)
272
- text_area_ratio = text_area / image_area if image_area > 0 else 0
273
- text_area_ratio = round(text_area_ratio, 4)
274
-
275
- return extracted_text, num_char, text_area_ratio
276
-
277
- # 5. Perform sentiment analysis
278
- def perform_sentiment_analysis(text):
279
- if text.strip():
280
- blob = TextBlob(text, pos_tagger=PatternTagger(), analyzer=PatternAnalyzer())
281
- sentiment = blob.sentiment
282
- sentiment_polarity = round(sentiment[0], 4)
283
- sentiment_subjectivity = round(sentiment[1], 4)
284
- else:
285
- sentiment_polarity = 0.0
286
- sentiment_subjectivity = 0.0
287
- return sentiment_polarity, sentiment_subjectivity
288
-
289
- # 6. Analyze additional textual features
290
- def analyze_additional_text_features(text):
291
- # URL Count
292
- urls = re.findall(url_pattern, text)
293
- url_count = len(urls)
294
-
295
- # Price Indication Count
296
- price_count = sum(text.lower().count(word.lower()) for word in price_indications)
297
-
298
- # Promotion Indication Count
299
- promotion_count = sum(text.lower().count(word.lower()) for word in promotion_words)
300
-
301
- # Call to Action Count
302
- call_to_action_count = sum(text.lower().count(phrase.lower()) for phrase in call_to_action_phrases)
303
-
304
- # Brand Salience Count
305
- brand_count = sum(text.lower().count(brand.lower()) for brand in car_brands)
306
-
307
- return url_count, price_count, promotion_count, call_to_action_count, brand_count
308
-
309
- """## Basci Visual Features"""
310
-
311
- # Function to convert RGB to Hex
312
- def rgb_to_hex(color):
313
- return '#%02x%02x%02x' % tuple(color)
314
-
315
- # Get dominant color
316
- def get_dominant_color(image, k=4):
317
- # Resize image to reduce computation time
318
- image = image.resize((150, 150))
319
- # Convert image to numpy array
320
- np_image = np.array(image)
321
- np_image = np_image.reshape((np_image.shape[0]*np_image.shape[1], 3))
322
- # Use KMeans clustering
323
- kmeans = KMeans(n_clusters=k)
324
- kmeans.fit(np_image)
325
- # Get the cluster centers
326
- colors = kmeans.cluster_centers_
327
- # Get counts of pixels in each cluster
328
- labels, counts = np.unique(kmeans.labels_, return_counts=True)
329
- # Find the most frequent color
330
- dominant_color = colors[np.argmax(counts)]
331
- # Convert to int and to hex
332
- dominant_color = dominant_color.astype(int)
333
- dominant_color_hex = rgb_to_hex(dominant_color)
334
- return dominant_color_hex, tuple(dominant_color)
335
-
336
- # Extract visual features
337
- def extract_visual_features(image):
338
- # Image resolution
339
- width, height = image.size
340
-
341
- # Average RGB values
342
- np_image = np.array(image)
343
- avg_r = np.mean(np_image[:, :, 0])
344
- avg_g = np.mean(np_image[:, :, 1])
345
- avg_b = np.mean(np_image[:, :, 2])
346
-
347
- # Dominant color
348
- dominant_color_hex, dominant_color_rgb = get_dominant_color(image)
349
-
350
- # Warm/cold hue
351
- # Convert image to HSV
352
- hsv_image = image.convert('HSV')
353
- np_hsv = np.array(hsv_image)
354
- avg_hue = np.mean(np_hsv[:, :, 0])
355
- # Convert hue from 0-255 to degrees
356
- avg_hue_deg = avg_hue * 360 / 255
357
- # Determine warm or cold
358
- # Warm colors are from 0-60 and 300-360 degrees
359
- if (0 <= avg_hue_deg <= 60) or (300 <= avg_hue_deg <= 360):
360
- hue_category = 'Warm'
361
- else:
362
- hue_category = 'Cool'
363
-
364
- # Visual complexity (Shannon entropy)
365
- # Convert image to grayscale
366
- gray_image = image.convert('L')
367
- histogram = gray_image.histogram()
368
- histogram_length = sum(histogram)
369
- samples_probability = [float(h) / histogram_length for h in histogram if h != 0]
370
- entropy = -sum([p * math.log(p, 2) for p in samples_probability])
371
-
372
- # Return the computed features
373
- return {
374
- 'Resolution': f'{width}x{height}',
375
- 'Dominant Color': dominant_color_hex,
376
- 'Dominant Color RGB': dominant_color_rgb,
377
- 'Hue Category': hue_category,
378
- 'Average Red': round(avg_r, 2),
379
- 'Average Green': round(avg_g, 2),
380
- 'Average Blue': round(avg_b, 2),
381
- 'Visual Complexity': round(entropy, 4)
382
- }
383
-
384
- """## YOLO: Perform object detection"""
385
-
386
- # Load YOLO model
387
- def load_yolo_model():
388
- model = YOLO('yolo11m.pt') # Using YOLO medium model
389
- return model
390
-
391
- yolo_model = load_yolo_model()
392
-
393
- # QR code
394
- detector = cv2.QRCodeDetector()
395
-
396
- def perform_object_detection(image_pil):
397
- image_area = image.size[0] * image.size[1]
398
-
399
- np_image = np.array(image_pil)
400
- np_image_bgr = cv2.cvtColor(np_image, cv2.COLOR_RGB2BGR)
401
-
402
- retval, decoded_info, points, _ = detector.detectAndDecodeMulti(np_image_bgr)
403
- qr_code_count = len(decoded_info)
404
-
405
- # Run YOLO model
406
- results = yolo_model(np_image_bgr)
407
-
408
- detections = results[0]
409
- boxes = detections.boxes # Bounding boxes
410
- class_ids = boxes.cls.cpu().numpy().astype(int)
411
- confidences = boxes.conf.cpu().numpy()
412
- xyxy = boxes.xyxy.cpu().numpy() # Bounding box coordinates
413
-
414
- # Initialize counts and areas
415
- car_count = 0
416
- car_coverage_area = 0
417
- car_positions = []
418
-
419
- person_count = 0
420
- animal_count = 0
421
- transportation_count = 0
422
- sports_item_count = 0
423
- food_item_count = 0
424
-
425
-
426
-
427
- for cls_id, conf, bbox in zip(class_ids, confidences, xyxy):
428
- class_name = coco_classes.get(cls_id, 'Unknown')
429
- bbox_area = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1])
430
-
431
- if cls_id == 2: # Car class
432
- car_count += 1
433
- car_coverage_area += bbox_area
434
- # Determine position
435
- x_center = (bbox[0] + bbox[2]) / 2
436
- y_center = (bbox[1] + bbox[3]) / 2
437
- if x_center < image.size[0] / 2 and y_center < image.size[1] / 2:
438
- position = 'Top-Left'
439
- elif x_center >= image.size[0] / 2 and y_center < image.size[1] / 2:
440
- position = 'Top-Right'
441
- elif x_center < image.size[0] / 2 and y_center >= image.size[1] / 2:
442
- position = 'Bottom-Left'
443
- else:
444
- position = 'Bottom-Right'
445
- car_positions.append(position)
446
- elif cls_id == 0:
447
- person_count += 1
448
- elif cls_id in animal_classes:
449
- animal_count += 1
450
- elif cls_id in transportation_classes:
451
- transportation_count += 1
452
- elif cls_id in sports_classes:
453
- sports_item_count += 1
454
- elif cls_id in food_classes:
455
- food_item_count += 1
456
-
457
- # Calculate coverage area ratio
458
- car_coverage_ratio = car_coverage_area / image_area if image_area > 0 else 0
459
- car_coverage_ratio = round(car_coverage_ratio, 4)
460
-
461
- # Get unique positions
462
- unique_positions = list(set(car_positions))
463
-
464
- return {
465
- 'Car Count': car_count,
466
- 'Car Coverage Ratio': car_coverage_ratio,
467
- 'Car Positions': ', '.join(unique_positions) if unique_positions else 'None',
468
- 'Person Count': person_count,
469
- 'Animal Object Count': animal_count,
470
- 'Transportation Object Count': transportation_count,
471
- 'Sports Item Count': sports_item_count,
472
- 'Food Item Count': food_item_count,
473
- 'QR Code Count': qr_code_count
474
- }
475
-
476
- """## Logo"""
477
-
478
- # Commented out IPython magic to ensure Python compatibility.
479
- if not os.path.exists("yolov7"):
480
- with zipfile.ZipFile("yolov7.zip", 'r') as zip_ref:
481
- zip_ref.extractall(".")
482
- print("files", os.listdir("."))
483
- sys.path.append("./yolov7")
484
- logo_model = torch.hub.load('./yolov7', 'custom', './logo_detection.pt', source='local')
485
- logo_model.conf = 0.25
486
-
487
- def detect_logos(pil_image):
488
-
489
- image_np = np.array(pil_image)
490
- results = logo_model(image_np)
491
-
492
- # results.xyxy[0] [x1, y1, x2, y2, conf, cls]
493
- detections = results.xyxy[0].cpu().numpy() if results.xyxy[0] is not None else np.empty((0, 6))
494
-
495
- logo_count = detections.shape[0]
496
- total_logo_area = 0
497
- positions = []
498
-
499
- img_height, img_width = image_np.shape[0], image_np.shape[1]
500
- image_area = img_height * img_width
501
-
502
- for det in detections:
503
- x1, y1, x2, y2, conf, cls = det
504
- box_area = (x2 - x1) * (y2 - y1)
505
- total_logo_area += box_area
506
-
507
- center_x = (x1 + x2) / 2
508
- center_y = (y1 + y2) / 2
509
-
510
- if center_x < img_width / 3:
511
- horiz = 'Left'
512
- elif center_x < 2 * img_width / 3:
513
- horiz = 'Center'
514
- else:
515
- horiz = 'Right'
516
-
517
- if center_y < img_height / 3:
518
- vert = 'Top'
519
- elif center_y < 2 * img_height / 3:
520
- vert = 'Middle'
521
- else:
522
- vert = 'Bottom'
523
-
524
- positions.append(f"{vert}-{horiz}")
525
-
526
- logo_area_ratio = total_logo_area / image_area if image_area > 0 else 0
527
- logo_area_ratio = round(logo_area_ratio,4)
528
-
529
- unique_positions = list(dict.fromkeys(positions))
530
- positions_str = ", ".join(unique_positions)
531
-
532
- return {
533
- 'Logo Count': logo_count,
534
- 'Logo Coverage Ratio': logo_area_ratio,
535
- 'Logo Positions': positions_str}
536
-
537
-
538
- def analyze_face_features(image, confidence_threshold=0.3):
539
- #GDPR -- exclude gender and race inference
540
-
541
- # BGR format for deepface
542
- image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
543
-
544
- results = DeepFace.analyze(
545
- img_path=image_cv,
546
- actions=['emotion'],
547
- detector_backend='retinaface',
548
- enforce_detection=False
549
- )
550
-
551
- # list format
552
- if not isinstance(results, list):
553
- results = [results]
554
-
555
- # return none if no face detected
556
- if not results:
557
- return {
558
- "angry": 0,
559
- "disgust": 0,
560
- "fear": 0,
561
- "happy": 0,
562
- "sad": 0,
563
- "surprise": 0,
564
- "neutral": 0}
565
-
566
- # Filter out low confidence detections
567
- filtered_results = []
568
- for face in results:
569
- # Check for face_confidence key specifically based on your output
570
- if 'face_confidence' in face and face['face_confidence'] >= confidence_threshold:
571
- filtered_results.append(face)
572
-
573
- # If no faces meet confidence threshold, return zeros
574
- if not filtered_results:
575
- return {
576
- "angry": 0,
577
- "disgust": 0,
578
- "fear": 0,
579
- "happy": 0,
580
- "sad": 0,
581
- "surprise": 0,
582
- "neutral": 0}
583
-
584
- # initiation
585
- emotions_sum = {
586
- "angry": 0,
587
- "disgust": 0,
588
- "fear": 0,
589
- "happy": 0,
590
- "sad": 0,
591
- "surprise": 0,
592
- "neutral": 0
593
- }
594
-
595
- # process faces
596
- for face in filtered_results:
597
- for emotion, value in face['emotion'].items():
598
- emotion_lower = emotion.lower()
599
- if emotion_lower in emotions_sum:
600
- emotions_sum[emotion_lower] += value
601
-
602
- # average emtions
603
- num_faces = len(filtered_results)
604
- avg_emotions = {emotion: round(value / num_faces, 2) for emotion, value in emotions_sum.items()}
605
-
606
- result = {
607
- "angry": avg_emotions["angry"],
608
- "disgust": avg_emotions["disgust"],
609
- "fear": avg_emotions["fear"],
610
- "happy": avg_emotions["happy"],
611
- "sad": avg_emotions["sad"],
612
- "surprise": avg_emotions["surprise"],
613
- "neutral": avg_emotions["neutral"],
614
- }
615
-
616
- return result
617
-
618
- """# 4. Run all analysis"""
619
-
620
- # Process image and compute all features
621
- def process_image(focal_image, same_brand_files, competitive_brand_files):
622
- # Input validation
623
- if focal_image is None:
624
- return ["Please upload the focal ad."] + [""] * 23 # Adjusted for total outputs
625
-
626
- # Compute embeddings
627
- focus_embedding = compute_image_embedding(focal_image, vit_model, preprocess)
628
-
629
- # Calculate scores
630
- if same_brand_files:
631
- same_brand_embeddings = get_embeddings_from_files(same_brand_files, vit_model, preprocess)
632
- consistency_score = calculate_similarity_scores(focus_embedding, same_brand_embeddings)
633
- consistency_score = round(consistency_score, 4)
634
- else:
635
- consistency_score = 'None'
636
-
637
- if competitive_brand_files:
638
- competitive_brand_embeddings = get_embeddings_from_files(competitive_brand_files, vit_model, preprocess)
639
- uniqueness_score = 1- calculate_similarity_scores(focus_embedding, competitive_brand_embeddings)
640
- uniqueness_score = round(uniqueness_score, 4)
641
- else:
642
- uniqueness_score = 'None'
643
-
644
- # Calculate ad_elasticity
645
- if consistency_score != 'None' and uniqueness_score != 'None':
646
- ad_elasticity = round(0.021 + 0.097*consistency_score + 0.110*uniqueness_score, 4)
647
- else:
648
- ad_elasticity = 'None' # Handle missing values gracefully
649
-
650
- # Extract textual features
651
- extracted_text, num_char, text_area_ratio = extract_textual_features(focal_image)
652
-
653
- # Sentiment analysis
654
- sentiment_polarity, sentiment_subjectivity = perform_sentiment_analysis(extracted_text)
655
-
656
- # Analyze additional textual features
657
- url_count, price_count, promotion_count, call_to_action_count, brand_salience_count = analyze_additional_text_features(extracted_text)
658
-
659
- # Extract visual features
660
- visual_features = extract_visual_features(focal_image)
661
- # Unpack visual features
662
- resolution = visual_features['Resolution']
663
- dominant_color = visual_features['Dominant Color']
664
- dominant_color_rgb = visual_features['Dominant Color RGB']
665
- hue_category = visual_features['Hue Category']
666
- avg_r = visual_features['Average Red']
667
- avg_g = visual_features['Average Green']
668
- avg_b = visual_features['Average Blue']
669
- visual_complexity = visual_features['Visual Complexity']
670
-
671
- # Perform object detection
672
- object_detection_results = perform_object_detection(focal_image)
673
- # Unpack object detection results
674
- car_count = object_detection_results['Car Count']
675
- car_coverage_ratio = object_detection_results['Car Coverage Ratio']
676
- car_positions = object_detection_results['Car Positions']
677
- person_count = object_detection_results['Person Count']
678
- animal_count = object_detection_results['Animal Object Count']
679
- transportation_count = object_detection_results['Transportation Object Count']
680
- sports_item_count = object_detection_results['Sports Item Count']
681
- food_item_count = object_detection_results['Food Item Count']
682
- qr_code_count = object_detection_results['QR Code Count']
683
-
684
- # Perform logo detection
685
- logo_detection_results = detect_logos(focal_image)
686
- # Unpack logo detection results
687
- logo_count = logo_detection_results['Logo Count']
688
- logo_area_ratio = logo_detection_results['Logo Coverage Ratio']
689
- logo_positions = logo_detection_results['Logo Positions']
690
-
691
- #emtion
692
- emotion_results = analyze_face_features(focal_image)
693
- emo_angry = emotion_results["angry"]
694
- emo_disgust = emotion_results["disgust"]
695
- emo_fear = emotion_results["fear"]
696
- emo_happy = emotion_results["happy"]
697
- emo_sad = emotion_results["sad"]
698
- emo_surprise = emotion_results["surprise"]
699
- emo_neutral = emotion_results["neutral"]
700
-
701
-
702
- # Return all outputs
703
- return [
704
- uniqueness_score,
705
- consistency_score,
706
- ad_elasticity,
707
- resolution,
708
- dominant_color,
709
- hue_category,
710
- avg_r,
711
- avg_g,
712
- avg_b,
713
- visual_complexity,
714
- car_count,
715
- car_coverage_ratio,
716
- car_positions,
717
- logo_count,
718
- logo_area_ratio,
719
- logo_positions,
720
- person_count,
721
- animal_count,
722
- transportation_count,
723
- sports_item_count,
724
- food_item_count,
725
- qr_code_count,
726
- num_char,
727
- text_area_ratio,
728
- sentiment_polarity,
729
- sentiment_subjectivity,
730
- url_count,
731
- price_count,
732
- promotion_count,
733
- call_to_action_count,
734
- brand_salience_count,
735
- emo_angry,
736
- emo_disgust,
737
- emo_fear,
738
- emo_happy,
739
- emo_sad,
740
- emo_surprise,
741
- emo_neutral
742
- ]
743
-
744
- import cv2, requests
745
- image = cv2.imdecode(np.frombuffer(requests.get("https://github.com/JaidedAI/EasyOCR/raw/master/examples/english.png").content, np.uint8), cv2.IMREAD_COLOR)
746
-
747
- image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
748
- image = image.convert('RGB')
749
- image
750
-
751
- process_image(image, None, None)
752
-
753
- """#5. Gradio Interface"""
754
-
755
- def get_score_card(value, title, thresholds, colors, labels):
756
- try:
757
- value = float(value)
758
- position = 10 # default
759
- for i, th in enumerate(thresholds):
760
- if value < th:
761
- position = 10 + i * 20
762
- break
763
- else:
764
- position = 90
765
- except (ValueError, TypeError):
766
- return f"<div style='color:gray;'>{title}: N/A</div>"
767
-
768
- color_bars = "".join([f"<div style='width:{100/len(colors)}%; background-color:{c};'></div>" for c in colors])
769
-
770
- return f"""
771
- <div style='border-radius:15px; padding:20px; background:#F9F9F9; box-shadow:0 4px 10px rgba(0,0,0,0.1);'>
772
- <div style='font-size:18px; font-weight:bold; margin-bottom:10px;'>{title}: {value:.2f}</div>
773
- <div style='position:relative; height:40px;'>
774
- <div style='display:flex; height:16px; border-radius:8px; overflow:hidden;'>
775
- {color_bars}
776
- </div>
777
- <div style='position:absolute; top:18px; left:{position}%; transform:translateX(-50%);'>
778
- <div style='width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:12px solid black;'></div>
779
- </div>
780
- </div>
781
- <div style='display:flex; justify-content:space-between; margin-top:8px; font-size:14px;'>
782
- {"".join([f"<span>{l}</span>" for l in labels])}
783
- </div>
784
- </div>
785
- """
786
-
787
-
788
- def get_consistency_card(value):
789
- return get_score_card(
790
- value=value,
791
- title="Consistency Score (within brand ad similarity)",
792
- thresholds=[0.1736, 0.3003, 0.5538, 0.6806], # +- 1 or 2 SD
793
- colors=["#FF4C4C", "#FFA500", "#FFD700", "#90EE90", "#008000"],
794
- labels=["Poor", "Low", "Avg", "Good", "Exc"]
795
- )
796
-
797
-
798
- def get_distinctiveness_card(value):
799
- return get_score_card(
800
- value=value,
801
- title="Uniqueness Score (between brand ad dissimilarity)",
802
- thresholds=[0.3937, 0.5000, 0.7125, 0.8187],
803
- colors=["#FF4C4C", "#FFA500", "#FFD700", "#90EE90", "#008000"],
804
- labels=["Poor", "Low", "Avg", "Good", "Exc"]
805
- )
806
-
807
-
808
- def get_elasticity_card(value):
809
- return get_score_card(
810
- value=value,
811
- title="Ad Elasticity",
812
- thresholds=[0.08, 0.12, 0.16, 0.20],
813
- colors=["#FF4C4C", "#FFA500", "#FFD700", "#90EE90", "#008000"],
814
- labels=["Poor", "Low", "Avg", "Good", "Exc"],
815
- )
816
-
817
- with gr.Blocks() as demo:
818
- gr.Markdown("# Ad Analyst")
819
-
820
- # Input Components
821
- with gr.Row():
822
- focal_ad = gr.Image(type='pil', label='Focal Ad', height=200)
823
- same_brand_ads = gr.File(file_types=['image'], label='Same Brand Ads', file_count='multiple')
824
- competitive_brand_ads = gr.File(file_types=['image'], label='Competitive Brand Ads', file_count='multiple')
825
- run_button = gr.Button('Run Analysis')
826
-
827
- # Output Components
828
- gr.Markdown("## Comprehensive Indexes")
829
- with gr.Row():
830
- distinctiveness_score = gr.HTML(label='Uniqueness Score (between brand ad dissimilarity)')
831
- consistency_score = gr.HTML(label='Consistency Score (within brand ad similarity)')
832
- ad_elasticity = gr.HTML(label='Ad Elasticity')
833
-
834
- gr.Markdown("## Visual Features")
835
- with gr.Row():
836
- resolution_output = gr.Textbox(label='Resolution')
837
- dominant_color_output = gr.Textbox(label='Dominant Color')
838
- dominant_color_indicator = gr.ColorPicker(label='Color Indicator', value='#FFFFFF')
839
- hue_category_output = gr.Textbox(label='Hue Category')
840
- with gr.Row():
841
- avg_r_output = gr.Textbox(label='Average Red')
842
- avg_g_output = gr.Textbox(label='Average Green')
843
- avg_b_output = gr.Textbox(label='Average Blue')
844
- visual_complexity_output = gr.Textbox(label='Visual Complexity')
845
- gr.Markdown("## Object Detection")
846
- with gr.Row():
847
- car_count_output = gr.Textbox(label='Car Count')
848
- car_coverage_ratio_output = gr.Textbox(label='Car Coverage Ratio')
849
- car_positions_output = gr.Textbox(label='Car Positions')
850
- with gr.Row():
851
- logo_count_output = gr.Textbox(label='Logo Count')
852
- logo_coverage_ratio_output = gr.Textbox(label='Logo Coverage Ratio')
853
- logo_positions_output = gr.Textbox(label='Logo Positions')
854
- with gr.Row():
855
- person_count_output = gr.Textbox(label='Person Count')
856
- animal_count_output = gr.Textbox(label='Animal Object Count')
857
- transportation_count_output = gr.Textbox(label='Transportation Object Count')
858
- with gr.Row():
859
- sports_item_count_output = gr.Textbox(label='Sports Item Count')
860
- food_item_count_output = gr.Textbox(label='Food Item Count')
861
- qr_code_count_output = gr.Textbox(label='QR Code Count') # QR code count output
862
-
863
- gr.Markdown("## Textual Features")
864
- with gr.Row():
865
- num_char = gr.Textbox(label='Character Count')
866
- text_area_ratio = gr.Textbox(label='Text Area Ratio')
867
- sentiment_polarity_output = gr.Textbox(label='Sentiment Polarity')
868
-
869
- with gr.Row():
870
- subjectivity_output = gr.Textbox(label='Subjectivity')
871
- url_count_output = gr.Textbox(label='URL Count')
872
- price_indication_count_output = gr.Textbox(label='Price Indication Count')
873
-
874
- with gr.Row():
875
- promotion_indication_count_output = gr.Textbox(label='Promotion Indication Count')
876
- call_to_action_count_output = gr.Textbox(label='Call to Action Count')
877
- brand_salience_output = gr.Textbox(label='Brand Salience Count')
878
-
879
- gr.Markdown("## Facial Emotions")
880
- with gr.Row():
881
- emo_angry_output = gr.Textbox(label='Angry')
882
- emo_disgust_output = gr.Textbox(label='Disgust')
883
- emo_fear_output = gr.Textbox(label='Fear')
884
- with gr.Row():
885
- emo_happy_output = gr.Textbox(label='Happy')
886
- emo_sad_output = gr.Textbox(label='Sad')
887
- emo_surprise_output = gr.Textbox(label='Surprise')
888
- emo_neutral_output = gr.Textbox(label='Surprise')
889
-
890
-
891
- # Define the function to be called when the button is clicked
892
- def process_and_display(focal_image, same_brand_files, competitive_brand_files):
893
- # Call the process_image function and get the outputs
894
- outputs = process_image(focal_image, same_brand_files, competitive_brand_files)
895
- # Set the dominant color indicator
896
- dominant_color_hex = outputs[4]
897
- dominant_color_indicator = dominant_color_hex if dominant_color_hex else '#FFFFFF'
898
- outputs.insert(5, dominant_color_indicator) # Insert after dominant color output
899
-
900
- ad_elasticity_value = outputs[2]
901
- ad_elasticity_card_html = get_elasticity_card(ad_elasticity_value)
902
- outputs[2]=ad_elasticity_card_html
903
-
904
- consistency_score_value = outputs[1]
905
- consistency_score_card_html = get_consistency_card(consistency_score_value)
906
- outputs[1]=consistency_score_card_html
907
-
908
- distinctiveness_score_value = outputs[0]
909
- distinctiveness_score_card_html = get_distinctiveness_card(distinctiveness_score_value)
910
- outputs[0]=distinctiveness_score_card_html
911
-
912
- return outputs
913
-
914
- # Set up the event handler
915
- run_button.click(
916
- fn=process_and_display,
917
- inputs=[focal_ad, same_brand_ads, competitive_brand_ads],
918
- outputs=[
919
- distinctiveness_score,
920
- consistency_score,
921
- ad_elasticity,
922
- resolution_output,
923
- dominant_color_output,
924
- dominant_color_indicator,
925
- hue_category_output,
926
- avg_r_output,
927
- avg_g_output,
928
- avg_b_output,
929
- visual_complexity_output,
930
- car_count_output,
931
- car_coverage_ratio_output,
932
- car_positions_output,
933
- logo_count_output,
934
- logo_coverage_ratio_output,
935
- logo_positions_output,
936
- person_count_output,
937
- animal_count_output,
938
- transportation_count_output,
939
- sports_item_count_output,
940
- food_item_count_output,
941
- qr_code_count_output,
942
- num_char,
943
- text_area_ratio,
944
- sentiment_polarity_output,
945
- subjectivity_output,
946
- url_count_output,
947
- price_indication_count_output,
948
- promotion_indication_count_output,
949
- call_to_action_count_output,
950
- brand_salience_output,
951
- emo_angry_output,
952
- emo_disgust_output,
953
- emo_fear_output,
954
- emo_happy_output,
955
- emo_sad_output,
956
- emo_surprise_output,
957
- emo_neutral_output
958
- ]
959
- )
960
-
961
- # Launch the app
962
- demo.launch()