wuhp commited on
Commit
43b1849
·
verified ·
1 Parent(s): 6d361b8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -62
app.py CHANGED
@@ -1,18 +1,18 @@
1
  import os
2
  import json
3
- import math
4
  import random
5
  import shutil
6
  import tempfile
7
  from urllib.parse import urlparse
8
- from PIL import Image
9
  import cv2
10
  import numpy as np
 
11
  import gradio as gr
12
  from roboflow import Roboflow
13
 
14
 
15
- def parse_roboflow_url(url):
16
  """Extract workspace, project name, and version from a Roboflow URL."""
17
  parsed = urlparse(url)
18
  parts = parsed.path.strip('/').split('/')
@@ -25,47 +25,43 @@ def parse_roboflow_url(url):
25
  return workspace, project, version
26
 
27
 
28
- def convert_seg_to_bbox(api_key, dataset_url):
29
- # Initialize Roboflow client & download
30
  rf = Roboflow(api_key=api_key)
31
- workspace, project_name, version = parse_roboflow_url(dataset_url)
32
- version_obj = rf.workspace(workspace).project(project_name).version(version)
33
  dataset = version_obj.download("coco-segmentation")
34
- root = dataset.location
35
 
36
- # Locate annotations file
37
  ann_file = None
38
- for sub in ("coco-annotations", "annotations"):
39
- candidate = os.path.join(root, sub, "train.json")
40
- if os.path.isfile(candidate):
41
- ann_file = candidate
42
- break
43
- if ann_file is None:
44
- # fallback: walk
45
- for dp, _, files in os.walk(root):
46
- if "train.json" in files:
47
- ann_file = os.path.join(dp, "train.json")
48
  break
 
 
49
  if ann_file is None:
50
- raise FileNotFoundError(f"Could not find train.json under {root}")
51
 
52
- # Load COCO annotations
53
  with open(ann_file, 'r') as f:
54
  coco = json.load(f)
55
  images_info = {img['id']: img for img in coco['images']}
56
 
57
- # Map category IDs YOLO class indices
58
  cat_ids = sorted(c['id'] for c in coco.get('categories', []))
59
  id_to_index = {cid: idx for idx, cid in enumerate(cat_ids)}
60
 
61
- # Prepare YOLO output dirs
62
  out_root = tempfile.mkdtemp(prefix="yolov8_")
63
  img_out = os.path.join(out_root, "images")
64
  lbl_out = os.path.join(out_root, "labels")
65
  os.makedirs(img_out, exist_ok=True)
66
  os.makedirs(lbl_out, exist_ok=True)
67
 
68
- # Build YOLO annotations per image
69
  annos = {}
70
  for anno in coco['annotations']:
71
  img_id = anno['image_id']
@@ -75,79 +71,73 @@ def convert_seg_to_bbox(api_key, dataset_url):
75
  y_min, y_max = min(ys), max(ys)
76
  w, h = x_max - x_min, y_max - y_min
77
  cx, cy = x_min + w/2, y_min + h/2
 
78
  info = images_info[img_id]
79
- img_w, img_h = info['width'], info['height']
80
- line = f"{id_to_index[anno['category_id']]} " \
81
- f"{cx/img_w:.6f} {cy/img_h:.6f} {w/img_w:.6f} {h/img_h:.6f}"
 
 
82
  annos.setdefault(img_id, []).append(line)
83
 
84
- # Locate train images directory
85
- possible = [
86
- os.path.join(root, "train", "images"),
87
- os.path.join(root, "train"),
88
- os.path.join(root, "images")
89
- ]
90
  train_img_dir = None
91
- for p in possible:
92
- if os.path.isdir(p):
93
- train_img_dir = p
94
  break
95
  if train_img_dir is None:
96
- for dp, _, files in os.walk(root):
97
- if any(f.lower().endswith(('.jpg','.png','.jpeg')) for f in files):
98
- train_img_dir = dp
99
- break
100
- if train_img_dir is None:
101
- raise FileNotFoundError(f"No image directory found under {root}")
102
 
103
- # Map filenames → IDs, copy images & write labels
104
  name_to_id = {img['file_name']: img['id'] for img in coco['images']}
105
  for fname, img_id in name_to_id.items():
106
  src = os.path.join(train_img_dir, fname)
107
  if not os.path.isfile(src):
108
  continue
109
  shutil.copy(src, os.path.join(img_out, fname))
110
- with open(os.path.join(lbl_out, fname.rsplit('.',1)[0] + '.txt'), 'w') as lf:
111
- lf.write('\n'.join(annos.get(img_id, [])))
 
112
 
113
- # Build example galleries
114
- before_imgs, after_imgs = [], []
115
  sample = random.sample(list(name_to_id.keys()), min(5, len(name_to_id)))
116
  for fname in sample:
117
  src = os.path.join(train_img_dir, fname)
118
  img = cv2.cvtColor(cv2.imread(src), cv2.COLOR_BGR2RGB)
119
 
120
- # segmentation overlay
121
  seg_vis = img.copy()
122
  img_id = name_to_id[fname]
123
  for anno in coco['annotations']:
124
  if anno['image_id'] != img_id:
125
  continue
126
- pts = np.array(anno['segmentation'][0], dtype=np.int32).reshape(-1,2)
127
- cv2.polylines(seg_vis, [pts], True, (255,0,0), 2)
128
 
129
- # bounding-box overlay
130
  box_vis = img.copy()
131
  for line in annos.get(img_id, []):
132
  _, cxn, cyn, wnorm, hnorm = map(float, line.split())
133
  iw, ih = images_info[img_id]['width'], images_info[img_id]['height']
134
- w0, h0 = int(wnorm*iw), int(hnorm*ih)
135
- x0 = int(cxn*iw - w0/2)
136
- y0 = int(cyn*ih - h0/2)
137
- cv2.rectangle(box_vis, (x0,y0), (x0+w0, y0+h0), (0,255,0), 2)
138
 
139
- before_imgs.append(Image.fromarray(seg_vis))
140
- after_imgs.append(Image.fromarray(box_vis))
141
 
142
- return before_imgs, after_imgs
143
 
144
 
145
- # Gradio UI
146
  with gr.Blocks() as app:
147
  gr.Markdown("# Segmentation → YOLOv8 Converter")
148
  api_input = gr.Textbox(label="Roboflow API Key", type="password")
149
- url_input = gr.Textbox(label="Dataset URL (Segmentation)")
150
- run_btn = gr.Button("Convert")
151
 
152
  before_gallery = gr.Gallery(label="Before (Segmentation)", columns=5, height="auto")
153
  after_gallery = gr.Gallery(label="After (Bounding Boxes)", columns=5, height="auto")
@@ -159,5 +149,5 @@ with gr.Blocks() as app:
159
  )
160
 
161
  if __name__ == "__main__":
162
- # if you need a public link change to share=True:
163
  app.launch()
 
1
  import os
2
  import json
 
3
  import random
4
  import shutil
5
  import tempfile
6
  from urllib.parse import urlparse
7
+
8
  import cv2
9
  import numpy as np
10
+ from PIL import Image
11
  import gradio as gr
12
  from roboflow import Roboflow
13
 
14
 
15
+ def parse_roboflow_url(url: str):
16
  """Extract workspace, project name, and version from a Roboflow URL."""
17
  parsed = urlparse(url)
18
  parts = parsed.path.strip('/').split('/')
 
25
  return workspace, project, version
26
 
27
 
28
+ def convert_seg_to_bbox(api_key: str, dataset_url: str):
29
+ # 1) download the dataset
30
  rf = Roboflow(api_key=api_key)
31
+ ws, proj, ver = parse_roboflow_url(dataset_url)
32
+ version_obj = rf.workspace(ws).project(proj).version(ver)
33
  dataset = version_obj.download("coco-segmentation")
34
+ root = dataset.location # e.g. "/home/user/app/YourProject"
35
 
36
+ # 2) find the train JSON (anything with "train" in the name)
37
  ann_file = None
38
+ for dp, _, files in os.walk(root):
39
+ for fname in files:
40
+ if fname.lower().endswith(".json") and "train" in fname.lower():
41
+ ann_file = os.path.join(dp, fname)
 
 
 
 
 
 
42
  break
43
+ if ann_file:
44
+ break
45
  if ann_file is None:
46
+ raise FileNotFoundError(f"Could not locate any '*train*.json' under {root}")
47
 
48
+ # 3) load COCO annotations
49
  with open(ann_file, 'r') as f:
50
  coco = json.load(f)
51
  images_info = {img['id']: img for img in coco['images']}
52
 
53
+ # 4) build category→index map
54
  cat_ids = sorted(c['id'] for c in coco.get('categories', []))
55
  id_to_index = {cid: idx for idx, cid in enumerate(cat_ids)}
56
 
57
+ # 5) prepare YOLO output directories
58
  out_root = tempfile.mkdtemp(prefix="yolov8_")
59
  img_out = os.path.join(out_root, "images")
60
  lbl_out = os.path.join(out_root, "labels")
61
  os.makedirs(img_out, exist_ok=True)
62
  os.makedirs(lbl_out, exist_ok=True)
63
 
64
+ # 6) convert each segmentation annotation to a YOLO bbox line
65
  annos = {}
66
  for anno in coco['annotations']:
67
  img_id = anno['image_id']
 
71
  y_min, y_max = min(ys), max(ys)
72
  w, h = x_max - x_min, y_max - y_min
73
  cx, cy = x_min + w/2, y_min + h/2
74
+
75
  info = images_info[img_id]
76
+ iw, ih = info['width'], info['height']
77
+ line = (
78
+ f"{id_to_index[anno['category_id']]} "
79
+ f"{cx/iw:.6f} {cy/ih:.6f} {w/iw:.6f} {h/ih:.6f}"
80
+ )
81
  annos.setdefault(img_id, []).append(line)
82
 
83
+ # 7) locate your train-images folder (first folder under root with any .jpg/.png)
 
 
 
 
 
84
  train_img_dir = None
85
+ for dp, _, files in os.walk(root):
86
+ if any(f.lower().endswith((".jpg", ".png", ".jpeg")) for f in files):
87
+ train_img_dir = dp
88
  break
89
  if train_img_dir is None:
90
+ raise FileNotFoundError(f"No image files found under {root}")
 
 
 
 
 
91
 
92
+ # 8) copy images + write labels
93
  name_to_id = {img['file_name']: img['id'] for img in coco['images']}
94
  for fname, img_id in name_to_id.items():
95
  src = os.path.join(train_img_dir, fname)
96
  if not os.path.isfile(src):
97
  continue
98
  shutil.copy(src, os.path.join(img_out, fname))
99
+ lbl_path = os.path.join(lbl_out, fname.rsplit('.', 1)[0] + ".txt")
100
+ with open(lbl_path, 'w') as lf:
101
+ lf.write("\n".join(annos.get(img_id, [])))
102
 
103
+ # 9) build before/after galleries
104
+ before, after = [], []
105
  sample = random.sample(list(name_to_id.keys()), min(5, len(name_to_id)))
106
  for fname in sample:
107
  src = os.path.join(train_img_dir, fname)
108
  img = cv2.cvtColor(cv2.imread(src), cv2.COLOR_BGR2RGB)
109
 
110
+ # draw polys
111
  seg_vis = img.copy()
112
  img_id = name_to_id[fname]
113
  for anno in coco['annotations']:
114
  if anno['image_id'] != img_id:
115
  continue
116
+ pts = np.array(anno['segmentation'][0], dtype=np.int32).reshape(-1, 2)
117
+ cv2.polylines(seg_vis, [pts], True, (255, 0, 0), 2)
118
 
119
+ # draw boxes
120
  box_vis = img.copy()
121
  for line in annos.get(img_id, []):
122
  _, cxn, cyn, wnorm, hnorm = map(float, line.split())
123
  iw, ih = images_info[img_id]['width'], images_info[img_id]['height']
124
+ w0, h0 = int(wnorm * iw), int(hnorm * ih)
125
+ x0 = int(cxn * iw - w0/2)
126
+ y0 = int(cyn * ih - h0/2)
127
+ cv2.rectangle(box_vis, (x0, y0), (x0 + w0, y0 + h0), (0, 255, 0), 2)
128
 
129
+ before.append(Image.fromarray(seg_vis))
130
+ after.append(Image.fromarray(box_vis))
131
 
132
+ return before, after
133
 
134
 
135
+ # --- Gradio app ---
136
  with gr.Blocks() as app:
137
  gr.Markdown("# Segmentation → YOLOv8 Converter")
138
  api_input = gr.Textbox(label="Roboflow API Key", type="password")
139
+ url_input = gr.Textbox(label="Roboflow Dataset URL (Segmentation)")
140
+ run_btn = gr.Button("Convert")
141
 
142
  before_gallery = gr.Gallery(label="Before (Segmentation)", columns=5, height="auto")
143
  after_gallery = gr.Gallery(label="After (Bounding Boxes)", columns=5, height="auto")
 
149
  )
150
 
151
  if __name__ == "__main__":
152
+ # set share=True if you need a public link
153
  app.launch()