GitHub Actions commited on
Commit
2368d87
·
1 Parent(s): c5358ec

Auto-deploy from GitHub

Browse files
Files changed (2) hide show
  1. detect.py +149 -19
  2. models/detect.pt +3 -0
detect.py CHANGED
@@ -1,50 +1,180 @@
1
  from collections import Counter
 
2
  import numpy as np
3
  from PIL import Image
4
  from io import BytesIO
5
  from ultralytics import YOLO
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  class DengueDetector:
8
- def __init__(self, model_path="./models/DetectsmallTest1.pt"):
9
  self.model = YOLO(model_path)
10
  self.names = self.model.names
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  def calculate_intensity(self, objects):
13
- weights = {"piscina": 9, "caixa_agua": 4, "carro": 1}
14
  score = sum(weights.get(obj["class"], 0) for obj in objects)
15
  return score
16
 
17
- def detect_image(self, image_bytes):
18
  img = Image.open(BytesIO(image_bytes)).convert("RGB")
19
- img_np = np.array(img)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  height, width = img_np.shape[:2]
21
 
22
- results = self.model(img_np)
23
- result = results[0]
24
- boxes = result.boxes
25
- class_ids = boxes.cls.tolist()
26
- confidences = boxes.conf.tolist()
27
- class_names = [self.names[int(cls)] for cls in class_ids]
28
- counts = Counter(class_names)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  detections = []
31
- for i in range(len(boxes)):
32
- x1, y1, x2, y2 = map(float, boxes.xyxy[i])
33
- conf = float(confidences[i])
34
- cls_id = int(class_ids[i])
 
 
 
 
 
 
 
35
  detections.append({
36
- "class": self.names[cls_id],
37
- "confidence": round(conf, 4),
38
  "box": {
39
  "x1": x1, "y1": y1, "x2": x2, "y2": y2,
40
- "original_width": width, "original_height": height
41
  }
42
  })
43
 
 
44
  intensity_score = self.calculate_intensity(detections)
45
 
46
  return {
47
- "total": len(class_ids),
48
  "contagem": counts,
49
  "objetos": detections,
50
  "intensity_score": intensity_score
 
1
  from collections import Counter
2
+ import math
3
  import numpy as np
4
  from PIL import Image
5
  from io import BytesIO
6
  from ultralytics import YOLO
7
 
8
+ def _compute_iou(box_a, box_b):
9
+ ax1, ay1, ax2, ay2 = box_a
10
+ bx1, by1, bx2, by2 = box_b
11
+ inter_x1 = max(ax1, bx1)
12
+ inter_y1 = max(ay1, by1)
13
+ inter_x2 = min(ax2, bx2)
14
+ inter_y2 = min(ay2, by2)
15
+ inter_w = max(0.0, inter_x2 - inter_x1)
16
+ inter_h = max(0.0, inter_y2 - inter_y1)
17
+ inter_area = inter_w * inter_h
18
+ area_a = max(0.0, (ax2 - ax1)) * max(0.0, (ay2 - ay1))
19
+ area_b = max(0.0, (bx2 - bx1)) * max(0.0, (by2 - by1))
20
+ union = area_a + area_b - inter_area
21
+ return inter_area / union if union > 0 else 0.0
22
+
23
+ def _nms_xyxy(boxes, scores, iou_threshold=0.5):
24
+ if len(boxes) == 0:
25
+ return []
26
+ idxs = np.argsort(scores)[::-1]
27
+ keep = []
28
+ while len(idxs) > 0:
29
+ i = idxs[0]
30
+ keep.append(i)
31
+ if len(idxs) == 1:
32
+ break
33
+ rest = idxs[1:]
34
+ ious = np.array([_compute_iou(boxes[i], boxes[j]) for j in rest])
35
+ idxs = rest[ious <= iou_threshold]
36
+ return keep
37
+
38
  class DengueDetector:
39
+ def __init__(self, model_path="./models/detect.pt"):
40
  self.model = YOLO(model_path)
41
  self.names = self.model.names
42
+
43
+ self.tile_size = 1024
44
+ self.default_overlap = 0.2
45
+ self.fast_max_side = 3072
46
+ self.batch_tiles = 8
47
+ try:
48
+ if hasattr(self.model, "fuse"):
49
+ self.model.fuse()
50
+ except Exception:
51
+ pass
52
+ print("Modelo carregado com as seguintes classes:", self.names)
53
 
54
  def calculate_intensity(self, objects):
55
+ weights = {"piscina": 9, "caixa_agua": 4}
56
  score = sum(weights.get(obj["class"], 0) for obj in objects)
57
  return score
58
 
59
+ def detect_image(self, image_bytes, fast: bool = True):
60
  img = Image.open(BytesIO(image_bytes)).convert("RGB")
61
+ orig_width, orig_height = img.size
62
+
63
+ scale = 1.0
64
+ tile_size = self.tile_size
65
+ overlap = self.default_overlap
66
+
67
+ if fast:
68
+ max_side = max(orig_width, orig_height)
69
+ if max_side > self.fast_max_side:
70
+ scale = self.fast_max_side / float(max_side)
71
+ new_w = max(1, int(round(orig_width * scale)))
72
+ new_h = max(1, int(round(orig_height * scale)))
73
+ img_resized = img.resize((new_w, new_h), resample=Image.BILINEAR)
74
+ else:
75
+ img_resized = img
76
+ else:
77
+ img_resized = img
78
+
79
+ img_np = np.array(img_resized)
80
  height, width = img_np.shape[:2]
81
 
82
+ stride = max(1, int(tile_size * (1 - overlap)))
83
+
84
+ def compute_starts(total, size, stride):
85
+ starts = list(range(0, max(total - size, 0) + 1, stride))
86
+ if len(starts) == 0:
87
+ starts = [0]
88
+ last = max(total - size, 0)
89
+ if starts[-1] != last:
90
+ starts.append(last)
91
+ return starts
92
+
93
+ x_starts = compute_starts(width, tile_size, stride)
94
+ y_starts = compute_starts(height, tile_size, stride)
95
+
96
+ tiles = []
97
+ origins = []
98
+ for y0 in y_starts:
99
+ for x0 in x_starts:
100
+ x1 = x0
101
+ y1 = y0
102
+ x2 = min(x0 + tile_size, width)
103
+ y2 = min(y0 + tile_size, height)
104
+ tile = img_np[y1:y2, x1:x2, :]
105
+ if tile.size == 0:
106
+ continue
107
+ tiles.append(tile)
108
+ origins.append((x1, y1))
109
+
110
+ all_boxes = []
111
+ all_scores = []
112
+ all_classes = []
113
+
114
+ if len(tiles) > 0:
115
+ bs = max(1, int(self.batch_tiles))
116
+ for i in range(0, len(tiles), bs):
117
+ batch = tiles[i:i+bs]
118
+ batch_origins = origins[i:i+bs]
119
+ results = self.model(batch, verbose=False)
120
+ for res, (ox, oy) in zip(results, batch_origins):
121
+ boxes = res.boxes
122
+ if boxes is None or len(boxes) == 0:
123
+ continue
124
+ class_ids = boxes.cls.tolist()
125
+ confidences = boxes.conf.tolist()
126
+ xyxy = boxes.xyxy.cpu().numpy() if hasattr(boxes.xyxy, 'cpu') else np.array(boxes.xyxy)
127
+
128
+ for j in range(len(class_ids)):
129
+ bx1, by1, bx2, by2 = map(float, xyxy[j])
130
+ all_boxes.append((bx1 + ox, by1 + oy, bx2 + ox, by2 + oy))
131
+ all_scores.append(float(confidences[j]))
132
+ all_classes.append(int(class_ids[j]))
133
+
134
+ final_indices = []
135
+ final_boxes = []
136
+ final_scores = []
137
+ final_classes = []
138
+ all_boxes_np = np.array(all_boxes, dtype=float)
139
+ all_scores_np = np.array(all_scores, dtype=float)
140
+ all_classes_np = np.array(all_classes, dtype=int)
141
+
142
+ for cls in set(all_classes_np.tolist()) if len(all_classes_np) else []:
143
+ cls_mask = (all_classes_np == cls)
144
+ boxes_cls = all_boxes_np[cls_mask]
145
+ scores_cls = all_scores_np[cls_mask]
146
+ keep = _nms_xyxy(boxes_cls, scores_cls, iou_threshold=0.5)
147
+ for k in keep:
148
+ final_boxes.append(tuple(boxes_cls[k]))
149
+ final_scores.append(float(scores_cls[k]))
150
+ final_classes.append(int(cls))
151
 
152
  detections = []
153
+ class_names = []
154
+ for b, s, c in zip(final_boxes, final_scores, final_classes):
155
+ x1, y1, x2, y2 = map(float, b)
156
+ if scale != 1.0:
157
+ inv = 1.0 / scale
158
+ x1 *= inv
159
+ y1 *= inv
160
+ x2 *= inv
161
+ y2 *= inv
162
+ cname = self.names[int(c)]
163
+ class_names.append(cname)
164
  detections.append({
165
+ "class": cname,
166
+ "confidence": round(s, 4),
167
  "box": {
168
  "x1": x1, "y1": y1, "x2": x2, "y2": y2,
169
+ "original_width": orig_width, "original_height": orig_height
170
  }
171
  })
172
 
173
+ counts = Counter(class_names)
174
  intensity_score = self.calculate_intensity(detections)
175
 
176
  return {
177
+ "total": len(detections),
178
  "contagem": counts,
179
  "objetos": detections,
180
  "intensity_score": intensity_score
models/detect.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:27a0e59e4f7573d93e1a4ead65ddbde30cc8f5b8db31fe089cfffda4baa2b43b
3
+ size 52117266