Spaces:
Sleeping
Sleeping
Denny Lulak
commited on
Commit
·
c6700a6
1
Parent(s):
4c3081b
Fix
Browse files- app.py +27 -1
- inference.py +58 -42
- model.onnx +2 -2
app.py
CHANGED
|
@@ -6,7 +6,33 @@ import cv2
|
|
| 6 |
|
| 7 |
# Configuration
|
| 8 |
MODEL_ONNX_PATH = "model.onnx"
|
| 9 |
-
CLASS_NAMES = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
INPUT_SIZE = 640
|
| 11 |
|
| 12 |
# Initialize detector
|
|
|
|
| 6 |
|
| 7 |
# Configuration
|
| 8 |
MODEL_ONNX_PATH = "model.onnx"
|
| 9 |
+
CLASS_NAMES = [
|
| 10 |
+
'Butter_Dukat_Maslac_Stick_250g',
|
| 11 |
+
'Butter_Zbregov_Maslac_Stick_250g',
|
| 12 |
+
'Butter_Zdenka_Maslac_Stick_250g',
|
| 13 |
+
'Cheese_President_Gouda_Cube_250g',
|
| 14 |
+
'Chicken_Cekin_Pileca_Prsa_500g',
|
| 15 |
+
'Coffee_Franch_Crema_Bag_175g',
|
| 16 |
+
'Coffee_Franch_Crema_Box_250g',
|
| 17 |
+
'Coffee_Franch_Instant_Crema_80g',
|
| 18 |
+
'Coffee_Franch_Intense_Box_250g',
|
| 19 |
+
'Coffee_Franch_Original_Box_250g',
|
| 20 |
+
'Coffee_Franch_Sensual_Box_250g',
|
| 21 |
+
'Drink_CocaCola_Original_Bottle_1l',
|
| 22 |
+
'Flour_Mlineta_Brasno_Ostro_1kg',
|
| 23 |
+
'Juice_Vindi_Naranca_Nektar_1l',
|
| 24 |
+
'Ketchup_Zvijezda_Mild_Bottle_500g',
|
| 25 |
+
'Mayonnaise_Zvijezda_Delicate_Bottle_400g',
|
| 26 |
+
'Milk_Zbregov_Trajno_28_1l',
|
| 27 |
+
'Oil_Dijamant_Suncokretovo_Bottle_1l',
|
| 28 |
+
'Oil_Zvijezda_Suncokretovo_Ulje_1l',
|
| 29 |
+
'Pasta_Barilla_Fusilli_Box_500g',
|
| 30 |
+
'Rice_Gallo_Long_Grain_900g',
|
| 31 |
+
'Rice_Kplus_Arborio_BijeliDugi_1kg',
|
| 32 |
+
'Salt_SolanaPag_Sitna_Box_1kg',
|
| 33 |
+
'Spaghetti_PastaZara_Spaghettini_Bag_500g',
|
| 34 |
+
'Tuna_RioMare_Tonno_Oliva'
|
| 35 |
+
]
|
| 36 |
INPUT_SIZE = 640
|
| 37 |
|
| 38 |
# Initialize detector
|
inference.py
CHANGED
|
@@ -62,49 +62,65 @@ class ObjectDetector:
|
|
| 62 |
blob = canvas.astype(np.float32) / 255.0
|
| 63 |
return blob.transpose(2, 0, 1)[None, ...], scale, (pw, ph)
|
| 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 |
def predict(self, image: np.ndarray) -> List[Dict]:
|
| 110 |
"""Main prediction method"""
|
|
|
|
| 62 |
blob = canvas.astype(np.float32) / 255.0
|
| 63 |
return blob.transpose(2, 0, 1)[None, ...], scale, (pw, ph)
|
| 64 |
|
| 65 |
+
def postprocess(
|
| 66 |
+
self,
|
| 67 |
+
predictions: np.ndarray,
|
| 68 |
+
original_shape: Tuple[int, int],
|
| 69 |
+
scale: float,
|
| 70 |
+
padding: Tuple[int, int],
|
| 71 |
+
conf_threshold: float = 0.5,
|
| 72 |
+
iou_threshold: float = 0.45
|
| 73 |
+
) -> List[Dict]:
|
| 74 |
+
# Reshape and transpose predictions to (8400, 29)
|
| 75 |
+
predictions = np.squeeze(predictions).T
|
| 76 |
+
|
| 77 |
+
# Split into box coordinates, objectness score, and class probabilities
|
| 78 |
+
boxes = predictions[:, :4]
|
| 79 |
+
obj_scores = predictions[:, 4]
|
| 80 |
+
cls_scores = predictions[:, 5:5 + len(self.class_names)] # Dynamic class count
|
| 81 |
+
|
| 82 |
+
# Combine objectness and class scores
|
| 83 |
+
final_scores = obj_scores[:, None] * cls_scores # (8400, num_classes)
|
| 84 |
+
best_class_ids = np.argmax(final_scores, axis=1)
|
| 85 |
+
best_scores = np.max(final_scores, axis=1)
|
| 86 |
+
|
| 87 |
+
# Filter by confidence threshold
|
| 88 |
+
valid = best_scores > conf_threshold
|
| 89 |
+
boxes = boxes[valid]
|
| 90 |
+
best_scores = best_scores[valid]
|
| 91 |
+
best_class_ids = best_class_ids[valid]
|
| 92 |
+
|
| 93 |
+
if boxes.size == 0:
|
| 94 |
+
return []
|
| 95 |
|
| 96 |
+
# Convert from center_x, center_y, width, height to xyxy format
|
| 97 |
+
boxes[:, [0, 1]] = boxes[:, [0, 1]] - boxes[:, [2, 3]] / 2
|
| 98 |
+
boxes[:, [2, 3]] = boxes[:, [0, 1]] + boxes[:, [2, 3]]
|
| 99 |
+
|
| 100 |
+
# Adjust for padding and scale
|
| 101 |
+
pad_w, pad_h = padding
|
| 102 |
+
boxes[:, [0, 2]] = (boxes[:, [0, 2]] - pad_w) / scale
|
| 103 |
+
boxes[:, [1, 3]] = (boxes[:, [1, 3]] - pad_h) / scale
|
| 104 |
+
|
| 105 |
+
# Clip boxes to image boundaries
|
| 106 |
+
h, w = original_shape
|
| 107 |
+
boxes[:, [0, 2]] = boxes[:, [0, 2]].clip(0, w)
|
| 108 |
+
boxes[:, [1, 3]] = boxes[:, [1, 3]].clip(0, h)
|
| 109 |
+
|
| 110 |
+
# Perform NMS
|
| 111 |
+
indices = self.nms(boxes, best_scores, iou_threshold)
|
| 112 |
+
|
| 113 |
+
return [{
|
| 114 |
+
"class": self.class_names[int(best_class_ids[i])],
|
| 115 |
+
"confidence": float(best_scores[i]),
|
| 116 |
+
"bbox": boxes[i].tolist(),
|
| 117 |
+
"bbox_normalized": [
|
| 118 |
+
float((boxes[i][0] + boxes[i][2])/2 / w),
|
| 119 |
+
float((boxes[i][1] + boxes[i][3])/2 / h),
|
| 120 |
+
float((boxes[i][2] - boxes[i][0]) / w),
|
| 121 |
+
float((boxes[i][3] - boxes[i][1]) / h)
|
| 122 |
+
]
|
| 123 |
+
} for i in indices]
|
| 124 |
|
| 125 |
def predict(self, image: np.ndarray) -> List[Dict]:
|
| 126 |
"""Main prediction method"""
|
model.onnx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:47fb25ba1e7fb96e8577581ecf4811788f36a0117ea9390859635bd89e4d439d
|
| 3 |
+
size 103663101
|