muhammadsalmanalfaridzi commited on
Commit
75b9799
·
verified ·
1 Parent(s): 9013bb7

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -0
app.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from dotenv import load_dotenv
3
+ from roboflow import Roboflow
4
+ import tempfile
5
+ import os
6
+ import requests
7
+ import cv2
8
+ import numpy as np
9
+
10
+ # ========== Konfigurasi ==========
11
+ load_dotenv()
12
+
13
+ # Roboflow Config
14
+ rf_api_key = os.getenv("ROBOFLOW_API_KEY")
15
+ workspace = os.getenv("ROBOFLOW_WORKSPACE")
16
+ project_name = os.getenv("ROBOFLOW_PROJECT")
17
+ model_version = int(os.getenv("ROBOFLOW_MODEL_VERSION"))
18
+
19
+ # OWLv2 API Config
20
+ OWLV2_API_URL = "https://api.landing.ai/v1/tools/text-to-object-detection"
21
+ OWLV2_PROMPTS = ["beverage", "bottle", "cans", "boxed milk", "milk"]
22
+
23
+ # Inisialisasi Model YOLO
24
+ rf = Roboflow(api_key=rf_api_key)
25
+ project = rf.workspace(workspace).project(project_name)
26
+ yolo_model = project.version(model_version).model
27
+
28
+ # ========== Fungsi Deteksi Kombinasi ==========
29
+ def detect_combined(image):
30
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file:
31
+ image.save(temp_file, format="JPEG")
32
+ temp_path = temp_file.name
33
+
34
+ try:
35
+ # ========== [1] YOLO: Deteksi Produk Nestlé (Per Class) ==========
36
+ yolo_pred = yolo_model.predict(temp_path, confidence=50, overlap=80).json()
37
+
38
+ nestle_class_count = {}
39
+ nestle_boxes = []
40
+ for pred in yolo_pred['predictions']:
41
+ class_name = pred['class']
42
+ nestle_class_count[class_name] = nestle_class_count.get(class_name, 0) + 1
43
+ nestle_boxes.append((pred['x'], pred['y'], pred['width'], pred['height']))
44
+
45
+ total_nestle = sum(nestle_class_count.values())
46
+
47
+ # ========== [2] OWLv2: Deteksi Kompetitor ==========
48
+ with open(temp_path, "rb") as image_file:
49
+ response = requests.post(OWLV2_API_URL,
50
+ files={"image": image_file},
51
+ data={"prompts": OWLV2_PROMPTS, "model": "owlv2"})
52
+
53
+ owlv2_pred = response.json().get("objects", [])
54
+
55
+ competitor_class_count = {}
56
+ competitor_boxes = []
57
+ for obj in owlv2_pred:
58
+ x1, y1, x2, y2 = obj["bbox"]
59
+ class_name = obj["label"].strip().lower()
60
+ if not is_overlap((x1, y1, x2, y2), nestle_boxes):
61
+ competitor_class_count[class_name] = competitor_class_count.get(class_name, 0) + 1
62
+ competitor_boxes.append({"class": class_name, "box": (x1, y1, x2, y2), "confidence": obj["score"]})
63
+
64
+ total_competitor = sum(competitor_class_count.values())
65
+
66
+ # ========== [3] Format Output ==========
67
+ result_text = "Product Nestle\n\n"
68
+ for class_name, count in nestle_class_count.items():
69
+ result_text += f"{class_name}: {count}\n"
70
+ result_text += f"\nTotal Products Nestle: {total_nestle}\n\n"
71
+ result_text += f"Total Unclassified Products: {total_competitor}\n" if competitor_class_count else "No Unclassified Products detected\n"
72
+
73
+ # ========== [4] Visualisasi ==========
74
+ img = cv2.imread(temp_path)
75
+
76
+ for pred in yolo_pred['predictions']:
77
+ x, y, w, h = pred['x'], pred['y'], pred['width'], pred['height']
78
+ cv2.rectangle(img, (int(x-w/2), int(y-h/2)), (int(x+w/2), int(y+h/2)), (0,255,0), 2)
79
+ cv2.putText(img, pred['class'], (int(x-w/2), int(y-h/2-10)), cv2.FONT_HERSHEY_SIMPLEX, 0.55, (0,255,0), 2)
80
+
81
+ for comp in competitor_boxes:
82
+ x1, y1, x2, y2 = comp['box']
83
+ display_name = "unclassified" if comp['class'] in OWLV2_PROMPTS else comp['class']
84
+ cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 2)
85
+ cv2.putText(img, f"{display_name} {comp['confidence']:.2f}", (int(x1), int(y1-10)), cv2.FONT_HERSHEY_SIMPLEX, 0.55, (0, 0, 255), 2)
86
+
87
+ output_path = "/tmp/combined_output.jpg"
88
+ cv2.imwrite(output_path, img)
89
+
90
+ return output_path, result_text
91
+
92
+ except Exception as e:
93
+ return temp_path, f"Error: {str(e)}"
94
+ finally:
95
+ os.remove(temp_path)
96
+
97
+
98
+ def is_overlap(box1, boxes2, threshold=0.3):
99
+ x1_min, y1_min, x1_max, y1_max = box1
100
+ for b2 in boxes2:
101
+ x2, y2, w2, h2 = b2
102
+ x2_min = x2 - w2/2
103
+ x2_max = x2 + w2/2
104
+ y2_min = y2 - h2/2
105
+ y2_max = y2 + h2/2
106
+ dx = min(x1_max, x2_max) - max(x1_min, x2_min)
107
+ dy = min(y1_max, y2_max) - max(y1_min, y2_min)
108
+ if (dx >= 0) and (dy >= 0):
109
+ area_overlap = dx * dy
110
+ area_box1 = (x1_max - x1_min) * (y1_max - y1_min)
111
+ if area_overlap / area_box1 > threshold:
112
+ return True
113
+ return False
114
+
115
+ with gr.Blocks(theme=gr.themes.Base(primary_hue="teal", secondary_hue="teal", neutral_hue="slate")) as iface:
116
+ gr.Markdown("""<div style="text-align: center;"><h1>NESTLE - STOCK COUNTING</h1></div>""")
117
+ with gr.Row():
118
+ with gr.Column():
119
+ input_image = gr.Image(type="pil", label="Input Image")
120
+ with gr.Column():
121
+ output_image = gr.Image(label="Detect Object")
122
+ with gr.Column():
123
+ output_text = gr.Textbox(label="Counting Object")
124
+
125
+ # Tombol untuk memproses input
126
+ detect_button = gr.Button("Detect")
127
+
128
+ # Hubungkan tombol dengan fungsi deteksi
129
+ detect_button.click(
130
+ fn=detect_combined,
131
+ inputs=input_image,
132
+ outputs=[output_image, output_text]
133
+ )