ibsocr1 commited on
Commit
e0560e9
·
verified ·
1 Parent(s): e7889c3

Upload 5 files

Browse files
Files changed (3) hide show
  1. README.md +7 -9
  2. app.py +26 -23
  3. training/classes.txt +7 -9
README.md CHANGED
@@ -146,15 +146,13 @@ The result image also shows the detected bounding boxes and confidence values.
146
  ## Default classes
147
 
148
  ```text
149
- Carnavalita
150
- Kimo-COno
151
- Squizz
152
- Oreo
153
- Moro
154
- Dulce
155
- KitKat
156
- Cadbury
157
- Mega
158
  other
159
  ```
160
 
 
146
  ## Default classes
147
 
148
  ```text
149
+ cornetto
150
+ magnum
151
+ correto
152
+ cone
153
+ cup
154
+ sandwich
155
+ stick
 
 
156
  other
157
  ```
158
 
app.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import io
2
  import json
3
  import os
@@ -168,7 +170,7 @@ def annotation_canvas_html(image_id):
168
  return """<div class="anno-wrap">
169
  <div class="anno-toolbar"><b>Draw boxes directly on the image</b><span>Click + drag + release = create box</span><span>Choose the class first</span></div>
170
  <div class="anno-canvas-wrap"><canvas id="anno-canvas"></canvas></div>
171
- <div class="anno-help">Drag from one corner of the object to the opposite corner, then release. Repeat for every object.</div>
172
  </div>
173
  <script>
174
  (function(){
@@ -182,6 +184,7 @@ function setField(id,val){const box=document.querySelector('#'+id);const el=box?
182
  canvas.addEventListener('pointerdown',e=>{e.preventDefault();canvas.setPointerCapture(e.pointerId);const p=pos(e);sx=p.x;sy=p.y;drawing=true;current={x:sx,y:sy,w:0,h:0};redraw();});
183
  canvas.addEventListener('pointermove',e=>{if(!drawing)return;const p=pos(e);current={x:Math.min(sx,p.x),y:Math.min(sy,p.y),w:Math.abs(p.x-sx),h:Math.abs(p.y-sy)};redraw();});
184
  canvas.addEventListener('pointerup',e=>{if(!drawing)return;drawing=false;const p=pos(e),sc=+canvas.dataset.scale||1;const x=Math.min(sx,p.x)/sc,y=Math.min(sy,p.y)/sc,w=Math.abs(p.x-sx)/sc,h=Math.abs(p.y-sy)/sc;current=null;redraw();if(w<3||h<3)return;setField('anno-x',Math.round(x));setField('anno-y',Math.round(y));setField('anno-w',Math.round(w));setField('anno-h',Math.round(h));const hint=document.getElementById('anno-hint');if(hint)hint.textContent='Box created. Click “Save Box” to store it.';});
 
185
  img.onload=fit;img.src=imgSrc;window.addEventListener('resize',fit);
186
  })();</script>""" % (json.dumps(src), int(item["width"]), int(item["height"]), boxes)
187
 
@@ -235,11 +238,11 @@ def draw_annotations(image_id):
235
 
236
 
237
  def add_annotation(image_id, cls, x, y, w, h):
238
- if not image_id:return None,"Select an image first.",[]
239
- if not cls:return annotation_preview_with_boxes(image_id),"Select a class first.",[]
240
  try:x,y,w,h=map(float,[x,y,w,h])
241
- except:return annotation_preview_with_boxes(image_id),"Enter box coordinates first.",[]
242
- if w<=0 or h<=0:return annotation_preview_with_boxes(image_id),"Box must have a width and height.",[]
243
  data=load_dataset()
244
  item=next((z for z in data["images"] if z["id"]==image_id),None)
245
  if not item:return None,"Image not found.",[]
@@ -247,29 +250,29 @@ def add_annotation(image_id, cls, x, y, w, h):
247
  w=min(w,item["width"]-x); h=min(h,item["height"]-y)
248
  item.setdefault("annotations",[]).append({"class":cls,"box":[x,y,w,h]})
249
  save_dataset(data)
250
- return annotation_preview_with_boxes(image_id),f"Saved {cls}: [{x:.0f}, {y:.0f}, {w:.0f}, {h:.0f}]",item["annotations"]
251
 
252
 
253
  def remove_annotation(image_id,index):
254
- if not image_id:return None,"Select an image first.",[]
255
  data=load_dataset()
256
  item=next((z for z in data["images"] if z["id"]==image_id),None)
257
  if not item:return None,"Image not found.",[]
258
  try:idx=int(index)-1
259
- except:return annotation_preview_with_boxes(image_id),"Enter an annotation number.",item.get("annotations",[])
260
  anns=item.get("annotations",[])
261
- if idx<0 or idx>=len(anns):return annotation_preview_with_boxes(image_id),"Annotation number not found.",anns
262
  deleted=anns.pop(idx);save_dataset(data)
263
- return annotation_preview_with_boxes(image_id),f"Deleted annotation {index}: {deleted['class']}",anns
264
 
265
 
266
  def clear_annotations(image_id):
267
- if not image_id:return None,"Select an image first.",[]
268
  data=load_dataset()
269
  item=next((z for z in data["images"] if z["id"]==image_id),None)
270
  if not item:return None,"Image not found.",[]
271
  item["annotations"]=[];save_dataset(data)
272
- return annotation_preview_image(image_id),"Annotations cleared.",[]
273
 
274
 
275
  def save_classes(text):
@@ -277,11 +280,11 @@ def save_classes(text):
277
  if not classes:
278
  return "At least one class is required.", gr.update(choices=[]), dataset_status()
279
  if len(set(classes)) != len(classes):
280
- return "Classes must be unique.", gr.update(choices=classes), dataset_status()
281
  CLASSES_FILE.write_text("\n".join(classes) + "\n", encoding="utf-8")
282
  data = load_dataset()
283
  save_dataset(data)
284
- return f"Saved {len(classes)} classes.", gr.update(choices=classes, value=classes[0]), dataset_status()
285
 
286
 
287
  def build_coco():
@@ -460,14 +463,14 @@ with gr.Blocks(title="Ice Cream Dataset + Counter") as demo:
460
  gr.Markdown("The actual uploaded photo is displayed below. Select a class and enter the box coordinates in the original image pixels, then click **Save Box**. Saved boxes appear in red.")
461
  with gr.Row():
462
  with gr.Column(scale=3):
463
- annotation_preview = gr.Image(label="Training image", type="pil", interactive=False, height=650)
464
  editor_info = gr.Markdown()
465
  with gr.Column(scale=1):
466
  ann_class = gr.Dropdown(choices=read_classes(), value=(read_classes()[0] if read_classes() else None), label="Class")
467
- x = gr.Number(label="X (left)", value=0, precision=0)
468
- y = gr.Number(label="Y (top)", value=0, precision=0)
469
- w = gr.Number(label="Width", value=0, precision=0)
470
- h = gr.Number(label="Height", value=0, precision=0)
471
  add_btn = gr.Button("💾 Save Box", variant="primary")
472
  gr.Markdown("Example: X=120, Y=80, Width=180, Height=300.")
473
  delete_index = gr.Number(label="Annotation # to delete", value=1, precision=0)
@@ -475,10 +478,10 @@ with gr.Blocks(title="Ice Cream Dataset + Counter") as demo:
475
  clear_btn = gr.Button("Clear All Boxes")
476
  annotations = gr.JSON(label="Saved annotations")
477
  ann_msg = gr.Markdown()
478
- image_select.change(refresh_editor, image_select, [annotation_preview, editor_info, annotations])
479
- add_btn.click(add_annotation, [image_select, ann_class, x, y, w, h], [annotation_preview, ann_msg, annotations])
480
- delete_btn.click(remove_annotation, [image_select, delete_index], [annotation_preview, ann_msg, annotations])
481
- clear_btn.click(clear_annotations, image_select, [annotation_preview, ann_msg, annotations])
482
 
483
  with gr.Tab("3 · Training"):
484
  gr.Markdown("### Train RT-DETR")
 
1
+ CLASSES = ['Carnavalita', 'Kimo-COno', 'Squizz', 'Oreo', 'Moro', 'Dulce', 'KitKat', 'Cadbury', 'Mega', 'other']
2
+
3
  import io
4
  import json
5
  import os
 
170
  return """<div class="anno-wrap">
171
  <div class="anno-toolbar"><b>Draw boxes directly on the image</b><span>Click + drag + release = create box</span><span>Choose the class first</span></div>
172
  <div class="anno-canvas-wrap"><canvas id="anno-canvas"></canvas></div>
173
+ <div class="anno-help" id="anno-hint">Drag from one corner of the object to the opposite corner, then release. The coordinates are filled automatically; click <b>Save Box</b>. Repeat for every object.</div>
174
  </div>
175
  <script>
176
  (function(){
 
184
  canvas.addEventListener('pointerdown',e=>{e.preventDefault();canvas.setPointerCapture(e.pointerId);const p=pos(e);sx=p.x;sy=p.y;drawing=true;current={x:sx,y:sy,w:0,h:0};redraw();});
185
  canvas.addEventListener('pointermove',e=>{if(!drawing)return;const p=pos(e);current={x:Math.min(sx,p.x),y:Math.min(sy,p.y),w:Math.abs(p.x-sx),h:Math.abs(p.y-sy)};redraw();});
186
  canvas.addEventListener('pointerup',e=>{if(!drawing)return;drawing=false;const p=pos(e),sc=+canvas.dataset.scale||1;const x=Math.min(sx,p.x)/sc,y=Math.min(sy,p.y)/sc,w=Math.abs(p.x-sx)/sc,h=Math.abs(p.y-sy)/sc;current=null;redraw();if(w<3||h<3)return;setField('anno-x',Math.round(x));setField('anno-y',Math.round(y));setField('anno-w',Math.round(w));setField('anno-h',Math.round(h));const hint=document.getElementById('anno-hint');if(hint)hint.textContent='Box created. Click “Save Box” to store it.';});
187
+ canvas.addEventListener('pointercancel',()=>{drawing=false;current=null;redraw();});
188
  img.onload=fit;img.src=imgSrc;window.addEventListener('resize',fit);
189
  })();</script>""" % (json.dumps(src), int(item["width"]), int(item["height"]), boxes)
190
 
 
238
 
239
 
240
  def add_annotation(image_id, cls, x, y, w, h):
241
+ if not image_id:return annotation_canvas_html(image_id),"Select an image first.",[]
242
+ if not cls:return annotation_canvas_html(image_id),"Select a class first.",[]
243
  try:x,y,w,h=map(float,[x,y,w,h])
244
+ except:return annotation_canvas_html(image_id),"Enter box coordinates first.",[]
245
+ if w<=0 or h<=0:return annotation_canvas_html(image_id),"Box must have a width and height.",[]
246
  data=load_dataset()
247
  item=next((z for z in data["images"] if z["id"]==image_id),None)
248
  if not item:return None,"Image not found.",[]
 
250
  w=min(w,item["width"]-x); h=min(h,item["height"]-y)
251
  item.setdefault("annotations",[]).append({"class":cls,"box":[x,y,w,h]})
252
  save_dataset(data)
253
+ return annotation_canvas_html(image_id),f"Saved {cls}: [{x:.0f}, {y:.0f}, {w:.0f}, {h:.0f}]",item["annotations"]
254
 
255
 
256
  def remove_annotation(image_id,index):
257
+ if not image_id:return annotation_canvas_html(image_id),"Select an image first.",[]
258
  data=load_dataset()
259
  item=next((z for z in data["images"] if z["id"]==image_id),None)
260
  if not item:return None,"Image not found.",[]
261
  try:idx=int(index)-1
262
+ except:return annotation_canvas_html(image_id),"Enter an annotation number.",item.get("annotations",[])
263
  anns=item.get("annotations",[])
264
+ if idx<0 or idx>=len(anns):return annotation_canvas_html(image_id),"Annotation number not found.",anns
265
  deleted=anns.pop(idx);save_dataset(data)
266
+ return annotation_canvas_html(image_id),f"Deleted annotation {index}: {deleted['class']}",anns
267
 
268
 
269
  def clear_annotations(image_id):
270
+ if not image_id:return annotation_canvas_html(image_id),"Select an image first.",[]
271
  data=load_dataset()
272
  item=next((z for z in data["images"] if z["id"]==image_id),None)
273
  if not item:return None,"Image not found.",[]
274
  item["annotations"]=[];save_dataset(data)
275
+ return annotation_canvas_html(image_id),"Annotations cleared.",[]
276
 
277
 
278
  def save_classes(text):
 
280
  if not classes:
281
  return "At least one class is required.", gr.update(choices=[]), dataset_status()
282
  if len(set(classes)) != len(classes):
283
+ return "Classes must be unique.", gr.update(choices=CLASSES), dataset_status()
284
  CLASSES_FILE.write_text("\n".join(classes) + "\n", encoding="utf-8")
285
  data = load_dataset()
286
  save_dataset(data)
287
+ return f"Saved {len(classes)} classes.", gr.update(choices=CLASSES, value=classes[0]), dataset_status()
288
 
289
 
290
  def build_coco():
 
463
  gr.Markdown("The actual uploaded photo is displayed below. Select a class and enter the box coordinates in the original image pixels, then click **Save Box**. Saved boxes appear in red.")
464
  with gr.Row():
465
  with gr.Column(scale=3):
466
+ annotation_canvas = gr.HTML(value='<div class="anno-empty">Select an image.</div>', label="Training image")
467
  editor_info = gr.Markdown()
468
  with gr.Column(scale=1):
469
  ann_class = gr.Dropdown(choices=read_classes(), value=(read_classes()[0] if read_classes() else None), label="Class")
470
+ x = gr.Number(label="X (left)", value=0, precision=0, elem_id="anno-x")
471
+ y = gr.Number(label="Y (top)", value=0, precision=0, elem_id="anno-y")
472
+ w = gr.Number(label="Width", value=0, precision=0, elem_id="anno-w")
473
+ h = gr.Number(label="Height", value=0, precision=0, elem_id="anno-h")
474
  add_btn = gr.Button("💾 Save Box", variant="primary")
475
  gr.Markdown("Example: X=120, Y=80, Width=180, Height=300.")
476
  delete_index = gr.Number(label="Annotation # to delete", value=1, precision=0)
 
478
  clear_btn = gr.Button("Clear All Boxes")
479
  annotations = gr.JSON(label="Saved annotations")
480
  ann_msg = gr.Markdown()
481
+ image_select.change(lambda image_id: (draw_annotations(image_id), refresh_editor(image_id)[1], refresh_editor(image_id)[2]), image_select, [annotation_canvas, editor_info, annotations])
482
+ add_btn.click(add_annotation, [image_select, ann_class, x, y, w, h], [annotation_canvas, ann_msg, annotations])
483
+ delete_btn.click(remove_annotation, [image_select, delete_index], [annotation_canvas, ann_msg, annotations])
484
+ clear_btn.click(clear_annotations, image_select, [annotation_canvas, ann_msg, annotations])
485
 
486
  with gr.Tab("3 · Training"):
487
  gr.Markdown("### Train RT-DETR")
training/classes.txt CHANGED
@@ -1,10 +1,8 @@
1
- Carnavalita
2
- Kimo-COno
3
- Squizz
4
- Oreo
5
- Moro
6
- Dulce
7
- KitKat
8
- Cadbury
9
- Mega
10
  other
 
1
+ cornetto
2
+ magnum
3
+ correto
4
+ cone
5
+ cup
6
+ sandwich
7
+ stick
 
 
8
  other