nolenfelten commited on
Commit
e6071d1
·
verified ·
1 Parent(s): 9565411

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -300
app.py CHANGED
@@ -34,331 +34,67 @@ from PIL import Image, ImageDraw
34
  print("import scipy")
35
  from scipy.ndimage import gaussian_filter
36
 
37
- REPO_ID = "thoucentric/Shelf_Objects_Detection_Yolov7_Pytorch"
38
- FILENAME = "best.pt"
39
-
40
- yolov7_custom_weights = hf_hub_download(repo_id=REPO_ID, filename=FILENAME)
41
-
42
- # Load YOLOv7 Custom Model
43
- print("Load YOLOv7 Custom Model")
44
- model = torch.hub.load('Owaiskhan9654/yolov7-1:main', model='custom', path_or_model=yolov7_custom_weights, force_reload=True)
45
-
46
- # Roboflow
47
  print("Initialize Roboflow")
48
  rf = Roboflow(api_key="MjzjT2w8u8tlxjmUYDAd")
49
  project = rf.workspace().project("sku-110k")
50
  model = project.version(2).model
51
 
52
-
53
- def roboflow(image, confidence, overlap, stroke_width=1, labels=False):
54
- '''
55
- Send the image to Roboflow API for inference.
56
- Returns JSON and image with bounding boxes drawn on to it.
57
- '''
58
- json_url = f"https://detect.roboflow.com/sku-110k/2?api_key=MjzjT2w8u8tlxjmUYDAd&confidence={confidence}&overlap={overlap}&format=json"
59
- image_url = f"https://detect.roboflow.com/sku-110k/2?api_key=MjzjT2w8u8tlxjmUYDAd&confidence={confidence}&overlap={overlap}&format=image&labels={str(labels).lower()}&stroke={stroke_width}"
60
-
61
- encoded_image = encode_image(image)
62
- headers = {"Content-Type": "application/x-www-form-urlencoded"}
63
-
64
- json_request = requests.post(json_url, data=encoded_image, headers=headers)
65
- image_request = requests.post(image_url, data=encoded_image, headers=headers)
66
-
67
- print("JSON Response Headers:", json_request.headers)
68
- print("Image Response Headers:", image_request.headers)
69
-
70
- json_response = {}
71
- image_response = None
72
-
73
- if json_request.status_code == 200:
74
- try:
75
- json_response = json_request.json()
76
- except json.JSONDecodeError:
77
- json_response = {"error": "Invalid JSON response"}
78
- else:
79
- json_response = {"error": f"Failed to get JSON response, status code: {json_request.status_code}"}
80
-
81
- if image_request.status_code == 200 and 'image' in image_request.headers.get('Content-Type', ''):
82
- try:
83
- image_response = Image.open(io.BytesIO(image_request.content))
84
- except Exception as e:
85
- image_response = None
86
- print(f"Failed to open image: {e}")
87
- else:
88
- print(f"Failed to retrieve image, status code: {image_request.status_code}")
89
- print("Image Response Content:", image_request.content)
90
-
91
- return {
92
- "json": json_response,
93
- "image": image_response
94
- }
95
-
96
- # Image Splitting and Merging Functionality
97
- def split_image(image, tile_size=640, overlap=160):
98
- img_width, img_height = image.size
99
- tiles = []
100
-
101
- step = tile_size - overlap
102
-
103
- for top in range(0, img_height, step):
104
- for left in range(0, img_width, step):
105
- box = (left, top, left + tile_size, top + tile_size)
106
- tile = image.crop(box)
107
- tiles.append((tile, box))
108
-
109
- return tiles
110
-
111
- def merge_bounding_boxes(results, box):
112
- adjusted_bboxes = []
113
- for idx, row in results.pandas().xyxy[0].iterrows():
114
- adjusted_bbox = {
115
- "class": row['name'],
116
- "center_x": (row['xmin'] + row['xmax']) / 2 + box[0],
117
- "center_y": (row['ymin'] + row['ymax']) / 2 + box[1],
118
- "xmin": row['xmin'] + box[0],
119
- "xmax": row['xmax'] + box[0],
120
- "ymin": row['ymin'] + box[1],
121
- "ymax": row['ymax'] + box[1],
122
- "confidence": row['confidence'],
123
- }
124
- adjusted_bboxes.append(adjusted_bbox)
125
- return adjusted_bboxes
126
-
127
- def draw_bounding_boxes(image, bounding_boxes):
128
- draw = ImageDraw.Draw(image)
129
- for bbox in bounding_boxes:
130
- color = "red"
131
- draw.rectangle([bbox['xmin'], bbox['ymin'], bbox['xmax'], bbox['ymax']], outline=color, width=3)
132
- draw.text((bbox['xmin'], bbox['ymin']), f"{bbox['class']} {bbox['confidence']:.2f}", fill=color)
133
- return image
134
-
135
- # Non-Max Suppression Implementations
136
- def soft_nms(bounding_boxes, iou_threshold=0.3, sigma=0.5, score_threshold=0.001):
137
- if not bounding_boxes:
138
- return []
139
-
140
- def iou(box1, box2):
141
- x1 = max(box1['xmin'], box2['xmin'])
142
- y1 = max(box1['ymin'], box2['ymin'])
143
- x2 = min(box1['xmax'], box2['xmax'])
144
- y2 = min(box1['ymax'], box2['ymax'])
145
-
146
- intersection = max(0, x2 - x1) * max(0, y2 - y1)
147
- box1_area = (box1['xmax'] - box1['xmin']) * (box1['ymax'] - box1['ymin'])
148
- box2_area = (box2['xmax'] - box2['xmin']) * (box2['ymax'] - box2['ymin'])
149
-
150
- union = box1_area + box2_area - intersection
151
- return intersection / union
152
-
153
- boxes = sorted(bounding_boxes, key=lambda x: x['confidence'], reverse=True)
154
- final_boxes = []
155
-
156
- while boxes:
157
- chosen_box = boxes.pop(0)
158
- final_boxes.append(chosen_box)
159
-
160
- new_boxes = []
161
- for box in boxes:
162
- iou_score = iou(chosen_box, box)
163
- if iou_score > iou_threshold:
164
- box['confidence'] *= np.exp(-(iou_score ** 2) / sigma)
165
- if box['confidence'] > score_threshold:
166
- new_boxes.append(box)
167
- boxes = new_boxes
168
-
169
- return final_boxes
170
-
171
- # Density Map Generation and Counting Functions
172
- def generate_density_map(image, bounding_boxes, sigma=4):
173
- density_map = np.zeros((image.height, image.width))
174
-
175
- for bbox in bounding_boxes:
176
- center_x = int((bbox['xmin'] + bbox['xmax']) / 2)
177
- center_y = int((bbox['ymin'] + bbox['ymax']) / 2)
178
- density_map[center_y, center_x] += 1
179
-
180
- density_map = gaussian_filter(density_map, sigma=sigma)
181
- return density_map
182
-
183
- def count_from_density_map(density_map, threshold=0.05):
184
- return np.sum(density_map > threshold)
185
-
186
- # Edge Enhancement Functions
187
- def apply_edge_enhancement(image):
188
- gray_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
189
-
190
- sobel_x = cv2.Sobel(gray_image, cv2.CV_64F, 1, 0, ksize=3)
191
- sobel_y = cv2.Sobel(gray_image, cv2.CV_64F, 0, 1, ksize=3)
192
- sobel_combined = np.sqrt(sobel_x**2 + sobel_y**2)
193
- sobel_combined = np.uint8(sobel_combined / sobel_combined.max() * 255)
194
-
195
- enhanced_image = cv2.cvtColor(sobel_combined, cv2.COLOR_GRAY2RGB)
196
- return Image.fromarray(enhanced_image)
197
-
198
- # Object Detection Functions
199
- def object_detection(image, conf_threshold=0.25, iou_threshold=0.45):
200
- image = Image.fromarray(image)
201
- model.conf = conf_threshold
202
- model.iou = iou_threshold
203
-
204
- tiles = split_image(image, tile_size=640, overlap=160)
205
- all_bounding_boxes = []
206
-
207
- for tile, box in tiles:
208
- results = model(tile)
209
- adjusted_bboxes = merge_bounding_boxes(results, box)
210
- all_bounding_boxes.extend(adjusted_bboxes)
211
-
212
- final_bounding_boxes = soft_nms(all_bounding_boxes, iou_threshold=iou_threshold)
213
- image_with_boxes = draw_bounding_boxes(image, final_bounding_boxes)
214
-
215
- json_response = json.dumps(final_bounding_boxes, indent=4)
216
- return image_with_boxes, json_response
217
-
218
-
219
- def object_detection_with_edge_enhancement(image, conf_threshold=0.25, iou_threshold=0.45):
220
- image = Image.fromarray(image)
221
- image_enhanced = apply_edge_enhancement(image)
222
-
223
- model.conf = conf_threshold
224
- model.iou = iou_threshold
225
-
226
- tiles = split_image(image_enhanced, tile_size=640, overlap=160)
227
- all_bounding_boxes = []
228
-
229
- for tile, box in tiles:
230
- results = model(tile)
231
- adjusted_bboxes = merge_bounding_boxes(results, box)
232
- all_bounding_boxes.extend(adjusted_bboxes)
233
-
234
- final_bounding_boxes = soft_nms(all_bounding_boxes, iou_threshold=iou_threshold)
235
- image_with_boxes = draw_bounding_boxes(image_enhanced, final_bounding_boxes)
236
-
237
- json_response = json.dumps(final_bounding_boxes, indent=4)
238
- return image_with_boxes, json_response
239
-
240
- def object_detection_density_edge(image, conf_threshold=0.25, iou_threshold=0.45):
241
- """Apply edge enhancement and density-based counting."""
242
- image = Image.fromarray(image)
243
- image_enhanced = apply_edge_enhancement(image)
244
-
245
- model.conf = conf_threshold
246
- model.iou = iou_threshold
247
-
248
- tiles = split_image(image_enhanced, tile_size=640, overlap=160)
249
- all_bounding_boxes = []
250
-
251
- for tile, box in tiles:
252
- results = model(tile)
253
- adjusted_bboxes = merge_bounding_boxes(results, box)
254
- all_bounding_boxes.extend(adjusted_bboxes)
255
-
256
- final_bounding_boxes = soft_nms(all_bounding_boxes, iou_threshold=iou_threshold)
257
- density_map = generate_density_map(image_enhanced, final_bounding_boxes)
258
-
259
- density_map_rescaled = cv2.applyColorMap(
260
- (density_map / np.max(density_map) * 255).astype(np.uint8),
261
- cv2.COLORMAP_JET
262
- )
263
- density_map_pil = Image.fromarray(cv2.cvtColor(density_map_rescaled, cv2.COLOR_BGR2RGB))
264
- image_with_density = Image.blend(image_enhanced, density_map_pil, alpha=0.5)
265
-
266
- json_response = json.dumps(final_bounding_boxes, indent=4)
267
- object_count = count_from_density_map(density_map)
268
-
269
- summary = json.dumps({"object_count": int(object_count)}, indent=4)
270
- return image_with_density, json_response, summary
271
-
272
-
273
-
274
-
275
- # Function to resize and encode an image
276
  def resize_image(image, max_size=1500):
277
- print("resize_image initialized")
278
  if max(image.size) > max_size:
279
-
280
- print("Image size is over the max size, resizing")
281
  ratio = max_size / float(max(image.size))
282
- print("Ratio is: " + str(ratio))
283
-
284
  new_size = tuple([int(x * ratio) for x in image.size])
285
- print("New size is: " + str(new_size))
286
-
287
- print("Resizing image")
288
  image = image.resize(new_size, Image.LANCZOS)
289
-
290
-
291
-
292
- print("Create io.BytesIO instance")
293
  buffer = io.BytesIO()
294
-
295
- print("Save image to BytesIO")
296
  image.save(buffer, format="PNG")
297
  buffered = buffer.getvalue()
298
-
299
- print("Return base64 encoded image")
300
  return base64.b64encode(buffered).decode("utf-8")
301
 
302
-
303
- def infer(image, model, version, api_key, confidence=0.4, overlap=0.20, format="json", labels=False, stroke=1):
304
-
305
  base_url = f"https://detect.roboflow.com/{model}/{version}?api_key={api_key}&confidence={confidence}&overlap={overlap}&format={format}"
306
-
307
- if format == "image":
308
- if labels:
309
- base_url += "&labels=on"
310
- base_url += f"&stroke={stroke}"
311
-
312
- print(base_url)
313
-
314
-
315
  image_data = resize_image(image)
316
-
317
  response = requests.post(base_url, data=image_data, headers={"Content-Type": "application/x-www-form-urlencoded"})
318
-
319
  if format == "json":
320
- print(json.dumps(response.json(), indent=4))
321
- return json.dumps(response.json(), indent=4)
322
  elif format == "image":
323
  return Image.open(io.BytesIO(response.content))
324
 
325
-
326
- def gradio_infer(image, model, version, api_key, confidence, overlap, format, labels, stroke):
327
- result_json = infer(image, model, version, api_key, confidence, overlap, "json", labels, stroke)
328
- result_image = infer(image, model, version, api_key, confidence, overlap, "image", labels, stroke)
329
-
330
- return result_image, result_json
331
-
332
-
333
-
334
-
335
  title = "<center>Cigarette Pack Counter</center>"
336
  description = "<center><a href='http://counttek.online'><img width='25%' height='25%' src='https://mvp-83056e96f7ab.herokuapp.com/static/countteklogo2.png'></a><br><a href='https://nolenfelten.github.io'>Project by Nolen Felten</a></center>"
337
  footer = ("<center><b>Item Classes it will detect (Total 140 Classes)</b></center>")
338
 
339
- interface = gr.Interface(
340
- fn=gradio_infer,
341
- inputs=[
342
- gr.Image(type="pil", label="Input Image"),
343
- gr.Textbox(value="sku-110k", label="Model Name"),
344
- gr.Textbox(value="2", label="Model Version"),
345
- gr.Textbox(value="gHiUgOSq9GqTnRy5mErk", label="API Key"),
346
- gr.Slider(0.0, 1.0, value=0.40, label="Confidence Threshold"),
347
- gr.Slider(0.0, 1.0, value=0.20, label="Overlap Threshold"),
348
- gr.Radio(["json", "image"], value="image", label="Output Format"),
349
- gr.Checkbox(False, label="Include Labels"),
350
- gr.Slider(1, 10, value=5, step=1, label="Stroke Width"),
351
- ],
352
- outputs=[
353
- gr.Image(label="Roboflow Output Image"),
354
- gr.Textbox(label="Roboflow JSON Result"),
355
- ],
356
- title=title,
357
- description=description,
358
- article=footer,
359
- cache_examples=False,
360
- allow_flagging="never"
361
- )
 
 
 
 
 
 
 
362
 
363
- # Launch Gradio Interfaces
364
  interface.launch(debug=True)
 
34
  print("import scipy")
35
  from scipy.ndimage import gaussian_filter
36
 
 
 
 
 
 
 
 
 
 
 
37
  print("Initialize Roboflow")
38
  rf = Roboflow(api_key="MjzjT2w8u8tlxjmUYDAd")
39
  project = rf.workspace().project("sku-110k")
40
  model = project.version(2).model
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  def resize_image(image, max_size=1500):
 
43
  if max(image.size) > max_size:
 
 
44
  ratio = max_size / float(max(image.size))
 
 
45
  new_size = tuple([int(x * ratio) for x in image.size])
 
 
 
46
  image = image.resize(new_size, Image.LANCZOS)
 
 
 
 
47
  buffer = io.BytesIO()
 
 
48
  image.save(buffer, format="PNG")
49
  buffered = buffer.getvalue()
 
 
50
  return base64.b64encode(buffered).decode("utf-8")
51
 
52
+ def gradio_infer(image, model="sku-110k", version="2", api_key="gHiUgOSq9GqTnRy5mErk", confidence=0.4, overlap=0.2, format="json", labels=False, stroke=1):
 
 
53
  base_url = f"https://detect.roboflow.com/{model}/{version}?api_key={api_key}&confidence={confidence}&overlap={overlap}&format={format}"
54
+ if format == "image" and labels:
55
+ base_url += "&labels=on"
56
+ base_url += f"&stroke={stroke}"
 
 
 
 
 
 
57
  image_data = resize_image(image)
 
58
  response = requests.post(base_url, data=image_data, headers={"Content-Type": "application/x-www-form-urlencoded"})
 
59
  if format == "json":
60
+ return response.json()
 
61
  elif format == "image":
62
  return Image.open(io.BytesIO(response.content))
63
 
 
 
 
 
 
 
 
 
 
 
64
  title = "<center>Cigarette Pack Counter</center>"
65
  description = "<center><a href='http://counttek.online'><img width='25%' height='25%' src='https://mvp-83056e96f7ab.herokuapp.com/static/countteklogo2.png'></a><br><a href='https://nolenfelten.github.io'>Project by Nolen Felten</a></center>"
66
  footer = ("<center><b>Item Classes it will detect (Total 140 Classes)</b></center>")
67
 
68
+ def create_interface(shelf_number):
69
+ return gr.Interface(
70
+ fn=gradio_infer,
71
+ inputs=[
72
+ gr.Image(type="pil", label=f"Shelf {shelf_number}"),
73
+ gr.Textbox(value="sku-110k", label=f"Model Name - Shelf {shelf_number}"),
74
+ gr.Textbox(value="2", label="Model Version"),
75
+ gr.Slider(0.0, 1.0, value=0.40, label="Confidence Threshold"),
76
+ gr.Slider(0.0, 1.0, value=0.20, label="Overlap Threshold"),
77
+ gr.Textbox(value="gHiUgOSq9GqTnRy5mErk", label="API Key"),
78
+ gr.Radio(["json", "image"], value="image", label="Output Format"),
79
+ gr.Checkbox(False, label="Include Labels"),
80
+ gr.Slider(1, 10, value=5, step=1, label="Stroke Width")
81
+ ],
82
+ outputs=[
83
+ gr.Image(label=f"Roboflow Output Image - Shelf {shelf_number}"),
84
+ gr.JSON(label=f"Roboflow JSON Result - Shelf {shelf_number}")
85
+ ],
86
+ title=title,
87
+ description=description,
88
+ article=footer,
89
+ cache_examples=False,
90
+ allow_flagging="never"
91
+ )
92
+
93
+ # Create a list of interfaces
94
+ interfaces = [create_interface(i) for i in range(1, 12)]
95
+
96
+ # Combine all interfaces into one layout
97
+ interface = gr.TabbedInterface(interfaces, tab_names=[f"Shelf {i}" for i in range(1, 12)])
98
 
99
+ # Launch the combined interface
100
  interface.launch(debug=True)