File size: 6,110 Bytes
bd977a3 bf1fd9f 0f3d01e bf1fd9f b60852c bf1fd9f 6f2c705 b60852c bf1fd9f 6f2c705 bf1fd9f 6f2c705 bf1fd9f 6f2c705 bf1fd9f 6f2c705 bf1fd9f 6f2c705 bf1fd9f 6f2c705 bf1fd9f 6f2c705 56ff081 0aa4aac 6f2c705 8b978f6 6f2c705 bf1fd9f 6f2c705 56ff081 bf1fd9f 56ff081 6f2c705 b60852c 6f2c705 b60852c 6f2c705 bf1fd9f b60852c 6f2c705 b60852c 6f2c705 bf1fd9f 6f2c705 bf1fd9f 6f2c705 bf1fd9f b60852c bf1fd9f b60852c bf1fd9f 0f3d01e bf1fd9f b60852c |
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 146 147 148 149 150 |
import gradio as gr
from dotenv import load_dotenv
from roboflow import Roboflow
import tempfile
import os
import requests
import cv2
import numpy as np
import subprocess
# ========== Load Environment Variables ==========
load_dotenv()
# Roboflow Config
rf_api_key = os.getenv("ROBOFLOW_API_KEY")
workspace = os.getenv("ROBOFLOW_WORKSPACE")
project_name = os.getenv("ROBOFLOW_PROJECT")
model_version = int(os.getenv("ROBOFLOW_MODEL_VERSION"))
# CountGD Config
COUNTGD_API_KEY = os.getenv("COUNTGD_API_KEY")
# Inisialisasi YOLO Model dari Roboflow
rf = Roboflow(api_key=rf_api_key)
project = rf.workspace(workspace).project(project_name)
yolo_model = project.version(model_version).model
# ========== Fungsi untuk Menghitung IoU ==========
def iou(boxA, boxB):
xA = max(boxA[0], boxB[0])
yA = max(boxA[1], boxB[1])
xB = min(boxA[2], boxB[2])
yB = min(boxA[3], boxB[3])
interArea = max(0, xB - xA) * max(0, yB - yA)
boxAArea = (boxA[2] - boxA[0]) * (boxA[3] - boxA[1])
boxBArea = (boxB[2] - boxB[0]) * (boxB[3] - boxB[1])
return interArea / float(boxAArea + boxBArea - interArea) if (boxAArea + boxBArea - interArea) > 0 else 0
# ========== Fungsi Deteksi Kombinasi ==========
def detect_combined(image):
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file:
image.save(temp_file, format="JPEG")
temp_path = temp_file.name
try:
# YOLO Detection (Produk Nestlé)
yolo_pred = yolo_model.predict(temp_path, confidence=50, overlap=80).json()
nestle_class_count = {}
nestle_boxes = [] # (x_center, y_center, width, height)
for pred in yolo_pred['predictions']:
class_name = pred['class']
nestle_class_count[class_name] = nestle_class_count.get(class_name, 0) + 1
nestle_boxes.append((pred['x'], pred['y'], pred['width'], pred['height']))
total_nestle = sum(nestle_class_count.values())
# CountGD Detection (Produk Kompetitor)
url = "https://api.landing.ai/v1/tools/text-to-object-detection"
competitor_class_count = {}
competitor_boxes = []
COUNTGD_PROMPTS = ["cans", "bottle", "mixed box"]
headers = {"Authorization": f"Basic {COUNTGD_API_KEY}"}
for prompt in COUNTGD_PROMPTS:
with open(temp_path, "rb") as f:
files = {"image": f}
data = {"prompts": [prompt], "model": "countgd"}
response = requests.post(url, files=files, data=data, headers=headers)
result = response.json()
if 'data' in result and result['data']:
detections = result['data'][0]
detections_sorted = sorted(detections, key=lambda obj: obj.get('confidence', 0), reverse=True)
for obj in detections_sorted:
if 'bounding_box' in obj:
x1, y1, x2, y2 = obj['bounding_box']
countgd_box = (x1, y1, x2, y2)
# Hapus duplikasi dengan deteksi YOLO
if any(iou(countgd_box, yolo_box) > 0.3 for yolo_box in nestle_boxes):
continue
# Hapus duplikasi antar deteksi CountGD
if any(iou(countgd_box, existing_box) > 0.3 for existing_box in competitor_boxes):
continue
label = obj.get('label', prompt)
# Hapus "mixed box" jika ada "cans" atau "bottle" yang lebih spesifik
if label == "mixed box" and ("cans" in competitor_class_count or "bottle" in competitor_class_count):
continue
competitor_class_count[label] = competitor_class_count.get(label, 0) + 1
competitor_boxes.append(countgd_box)
total_competitor = sum(competitor_class_count.values())
# Format Output Text
result_text = "Product Nestlé\n\n"
for class_name, count in nestle_class_count.items():
result_text += f"{class_name}: {count}\n"
result_text += f"\nTotal Products Nestlé: {total_nestle}\n\n"
if total_competitor:
result_text += f"\nTotal Unclassified Products: {total_competitor}\n"
else:
result_text += "No Unclassified Products detected\n"
# Visualisasi Bounding Box
img = cv2.imread(temp_path)
for pred in yolo_pred['predictions']:
x, y, w, h = pred['x'], pred['y'], pred['width'], pred['height']
pt1 = (int(x - w/2), int(y - h/2))
pt2 = (int(x + w/2), int(y + h/2))
cv2.rectangle(img, pt1, pt2, (0, 255, 0), 2)
cv2.putText(img, pred['class'], (pt1[0], pt1[1]-10), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0,255,0), 3)
for box in competitor_boxes:
x1, y1, x2, y2 = box
cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 2)
cv2.putText(img, "unclassified", (int(x1), int(y1)-10), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0,0,255), 3)
output_path = "/tmp/combined_output.jpg"
cv2.imwrite(output_path, img)
return output_path, result_text
except Exception as e:
return temp_path, f"Error: {str(e)}"
finally:
if os.path.exists(temp_path):
os.remove(temp_path)
# ========== Gradio Interface ==========
with gr.Blocks(theme=gr.themes.Base(primary_hue="teal", secondary_hue="teal", neutral_hue="slate")) as iface:
gr.Markdown("""<div style="text-align: center;"><h1>NESTLE - STOCK COUNTING</h1></div>""")
with gr.Row():
with gr.Column():
input_image = gr.Image(type="pil", label="Input Image")
detect_image_button = gr.Button("Detect Image")
output_image = gr.Image(label="Detect Object")
output_text = gr.Textbox(label="Counting Object")
detect_image_button.click(fn=detect_combined, inputs=input_image, outputs=[output_image, output_text])
iface.launch()
|