wuhp commited on
Commit
bc6cd18
·
verified ·
1 Parent(s): 53abcf4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -0
app.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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('/')
19
+ # Expect at least [workspace, project, ..., version]
20
+ workspace = parts[0]
21
+ project = parts[1]
22
+ try:
23
+ version = int(parts[-1])
24
+ except ValueError:
25
+ version = int(parts[-2])
26
+ return workspace, project, version
27
+
28
+
29
+ def convert_seg_to_bbox(api_key, dataset_url):
30
+ # Initialize Roboflow client
31
+ rf = Roboflow(api_key=api_key)
32
+ workspace, project_name, version = parse_roboflow_url(dataset_url)
33
+ project = rf.workspace(workspace).project(project_name)
34
+ version_obj = project.version(version)
35
+
36
+ # Download the segmentation dataset in COCO format
37
+ dataset = version_obj.download("coco-segmentation")
38
+ root = dataset.location # root of downloaded dataset
39
+
40
+ # Load COCO train annotations
41
+ ann_dir = os.path.join(root, "coco-annotations")
42
+ ann_file = os.path.join(ann_dir, "train.json")
43
+ with open(ann_file, 'r') as f:
44
+ coco = json.load(f)
45
+ images_info = {img['id']: img for img in coco['images']}
46
+
47
+ # Map original category IDs to contiguous YOLO class indices
48
+ categories = coco.get('categories', [])
49
+ cat_ids = sorted(cat['id'] for cat in categories)
50
+ id_to_index = {cid: idx for idx, cid in enumerate(cat_ids)}
51
+
52
+ # Prepare output directories for YOLOv8 dataset
53
+ out_root = tempfile.mkdtemp(prefix="yolov8_")
54
+ img_out = os.path.join(out_root, "images")
55
+ lbl_out = os.path.join(out_root, "labels")
56
+ os.makedirs(img_out, exist_ok=True)
57
+ os.makedirs(lbl_out, exist_ok=True)
58
+
59
+ # Build YOLO annotation strings grouped by image
60
+ annos = {}
61
+ for anno in coco['annotations']:
62
+ img_id = anno['image_id']
63
+ poly = anno['segmentation'][0]
64
+ xs = poly[0::2]
65
+ ys = poly[1::2]
66
+ x_min, x_max = min(xs), max(xs)
67
+ y_min, y_max = min(ys), max(ys)
68
+ width = x_max - x_min
69
+ height = y_max - y_min
70
+ cx = x_min + width / 2
71
+ cy = y_min + height / 2
72
+ info = images_info[img_id]
73
+ img_w, img_h = info['width'], info['height']
74
+ cxn = cx / img_w
75
+ cyn = cy / img_h
76
+ wnorm = width / img_w
77
+ hnorm = height / img_h
78
+ cls_idx = id_to_index[anno['category_id']]
79
+ line = f"{cls_idx} {cxn:.6f} {cyn:.6f} {wnorm:.6f} {hnorm:.6f}"
80
+ annos.setdefault(img_id, []).append(line)
81
+
82
+ # Determine train images directory
83
+ train_img_dir = os.path.join(root, "train", "images")
84
+ if not os.path.isdir(train_img_dir):
85
+ train_img_dir = os.path.join(root, "train")
86
+
87
+ # Map filenames to image IDs
88
+ name_to_id = {img['file_name']: img['id'] for img in coco['images']}
89
+
90
+ # Copy images and write YOLO label files
91
+ for fname, img_id in name_to_id.items():
92
+ src_img = os.path.join(train_img_dir, fname)
93
+ if not os.path.isfile(src_img):
94
+ continue
95
+ dst_img = os.path.join(img_out, fname)
96
+ shutil.copy(src_img, dst_img)
97
+ lbl_path = os.path.join(lbl_out, os.path.splitext(fname)[0] + ".txt")
98
+ with open(lbl_path, 'w') as lf:
99
+ for line in annos.get(img_id, []):
100
+ lf.write(line + '\n')
101
+
102
+ # Prepare before/after example galleries
103
+ before_imgs, after_imgs = [], []
104
+ example_files = random.sample(list(name_to_id.keys()), min(5, len(name_to_id)))
105
+
106
+ for fname in example_files:
107
+ src_img = os.path.join(train_img_dir, fname)
108
+ img = cv2.cvtColor(cv2.imread(src_img), cv2.COLOR_BGR2RGB)
109
+
110
+ # Overlay segmentation polygons
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
+ poly = anno['segmentation'][0]
117
+ pts = np.array(poly, dtype=np.int32).reshape(-1, 2)
118
+ cv2.polylines(seg_vis, [pts], True, (255, 0, 0), 2)
119
+
120
+ # Overlay bounding boxes
121
+ box_vis = img.copy()
122
+ for line in annos.get(img_id, []):
123
+ _, cxn, cyn, wnorm, hnorm = line.split()
124
+ cxn, cyn, wnorm, hnorm = map(float, (cxn, cyn, wnorm, hnorm))
125
+ iw, ih = images_info[img_id]['width'], images_info[img_id]['height']
126
+ w0 = int(wnorm * iw)
127
+ h0 = int(hnorm * ih)
128
+ x0 = int(cxn * iw - w0/2)
129
+ y0 = int(cyn * ih - h0/2)
130
+ cv2.rectangle(box_vis, (x0, y0), (x0 + w0, y0 + h0), (0, 255, 0), 2)
131
+
132
+ before_imgs.append(Image.fromarray(seg_vis))
133
+ after_imgs.append(Image.fromarray(box_vis))
134
+
135
+ return before_imgs, after_imgs
136
+
137
+
138
+ # Build Gradio interface
139
+ with gr.Blocks() as app:
140
+ gr.Markdown("# Segmentation → YOLOv8 Converter")
141
+ api_input = gr.Textbox(label="Roboflow API Key", type="password")
142
+ url_input = gr.Textbox(label="Roboflow Dataset URL (Segmentation)")
143
+ run_btn = gr.Button("Convert")
144
+ before_gallery = gr.Gallery(label="Before (Segmentation)").style(grid=[5], height="auto")
145
+ after_gallery = gr.Gallery(label="After (Bounding Boxes)").style(grid=[5], height="auto")
146
+ run_btn.click(convert_seg_to_bbox, inputs=[api_input, url_input], outputs=[before_gallery, after_gallery])
147
+
148
+ if __name__ == "__main__":
149
+ app.launch()