Denny Lulak commited on
Commit
c6700a6
·
1 Parent(s): 4c3081b
Files changed (3) hide show
  1. app.py +27 -1
  2. inference.py +58 -42
  3. 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 = ["Coffee_Franch_Original_Box_250g", "Coffee_Franch_Instant_Crema_80g"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- 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
- predictions = np.squeeze(predictions).T
75
- scores = np.max(predictions[:, 4:], axis=1)
76
- valid = scores > conf_threshold
77
- predictions = predictions[valid]
78
-
79
- if predictions.size == 0:
80
- return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- boxes = predictions[:, :4]
83
- boxes[:, [0, 1]] = boxes[:, [0, 1]] - boxes[:, [2, 3]] / 2
84
- boxes[:, [2, 3]] = boxes[:, [0, 1]] + boxes[:, [2, 3]]
85
-
86
- pad_w, pad_h = padding
87
- boxes[:, [0, 2]] = (boxes[:, [0, 2]] - pad_w) / scale
88
- boxes[:, [1, 3]] = (boxes[:, [1, 3]] - pad_h) / scale
89
-
90
- h, w = original_shape
91
- boxes[:, [0, 2]] = boxes[:, [0, 2]].clip(0, w)
92
- boxes[:, [1, 3]] = boxes[:, [1, 3]].clip(0, h)
93
-
94
- class_ids = np.argmax(predictions[:, 4:], axis=1)
95
- indices = self.nms(boxes, scores[valid], iou_threshold)
96
-
97
- return [{
98
- "class": self.class_names[int(class_ids[i])],
99
- "confidence": float(scores[valid][i]),
100
- "bbox": boxes[i].tolist(),
101
- "bbox_normalized": [
102
- float((boxes[i][0] + boxes[i][2])/2 / w),
103
- float((boxes[i][1] + boxes[i][3])/2 / h),
104
- float((boxes[i][2] - boxes[i][0]) / w),
105
- float((boxes[i][3] - boxes[i][1]) / h)
106
- ]
107
- } for i in indices]
 
 
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:39582e24d58748bb0304397f40f5d88bff8f7c7a1584bbec11e9f9490fb12690
3
- size 37908587
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:47fb25ba1e7fb96e8577581ecf4811788f36a0117ea9390859635bd89e4d439d
3
+ size 103663101