Hgodwarrior commited on
Commit
c50892b
·
verified ·
1 Parent(s): c1b6dd1

Upload folder using huggingface_hub

Browse files
.dockerignore CHANGED
@@ -1,5 +1,11 @@
1
  .git
2
  .github
 
 
 
 
 
 
3
  build
4
  build_v2
5
  __pycache__
@@ -21,4 +27,4 @@ docs/images
21
  deps/
22
  build/
23
  *.dll
24
- *.a
 
1
  .git
2
  .github
3
+ src/
4
+ CMakeLists.txt
5
+ entrypoint.sh
6
+ Cube.stl
7
+ Sphere.stl
8
+ mask_to_coco.py
9
  build
10
  build_v2
11
  __pycache__
 
27
  deps/
28
  build/
29
  *.dll
30
+ *.a
.gitattributes CHANGED
@@ -1 +1,5 @@
1
  deps/glfw-3.4.bin.WIN64.zip filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
1
  deps/glfw-3.4.bin.WIN64.zip filter=lfs diff=lfs merge=lfs -text
2
+ demo_data/rgb/frame_0010.png filter=lfs diff=lfs merge=lfs -text
3
+ demo_data/rgb/frame_0025.png filter=lfs diff=lfs merge=lfs -text
4
+ demo_data/rgb/frame_0050.png filter=lfs diff=lfs merge=lfs -text
5
+ demo_data/rgb/frame_0075.png filter=lfs diff=lfs merge=lfs -text
Dockerfile CHANGED
@@ -1,42 +1,24 @@
1
- FROM ubuntu:22.04
2
-
3
- # 1. 安装 Linux 下渲染和编译所需的所有依赖
4
- # 安装编译工具和库
5
- RUN apt-get update && apt-get install -y \
6
- cmake \
7
- build-essential \
8
- pkg-config \
9
- libglfw3-dev \
10
- libglew-dev \
11
- libgl1-mesa-dev \
12
- libglu1-mesa-dev \
13
- libosmesa6-dev \
14
- libbenchmark-dev \
15
- libgl-dev \
16
- python3-pip \
17
- git \
18
- && rm -rf /var/lib/apt/lists/*
19
 
20
  WORKDIR /app
21
 
22
- # 2. 只拷贝源码和必要文件 (删掉 COPY deps/ 这一行)
23
- COPY CMakeLists.txt .
24
- COPY src/ ./src/
25
- COPY app.py .
26
  COPY requirements.txt .
27
- # 如果你有这些脚本和模型文件,保留它们
28
- COPY mask_to_coco.py .
29
- COPY Cube.stl .
30
- COPY Sphere.stl .
 
31
 
32
- # 3. 编译 C++ 渲染器
33
- # 关键调试行:如果这里出来的列表没有 .h,说明文件根本没传上来
34
- RUN ls -R /app/src/core/
35
 
36
- # 然后再执行构建
37
- RUN mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j$(nproc)
38
- # 4. 安装 Python 依赖
39
- RUN pip3 install --no-cache-dir -r requirements.txt
40
 
41
- # 5. 启动
42
- CMD ["python3", "app.py"]
 
 
 
 
 
 
1
+ FROM python:3.10-slim
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  WORKDIR /app
4
 
 
 
 
 
5
  COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY app.py .
9
+ COPY demo_data/ ./demo_data/
10
+ COPY demo_showcase.html .
11
 
12
+ RUN useradd -m -u 1000 user
13
+ RUN chown -R user:user /app
14
+ USER user
15
 
16
+ EXPOSE 7860
 
 
 
17
 
18
+ ENTRYPOINT ["python3", "-m", "streamlit", "run", "app.py", \
19
+ "--server.port=7860", \
20
+ "--server.address=0.0.0.0", \
21
+ "--server.headless=true", \
22
+ "--server.enableCORS=false", \
23
+ "--server.enableXsrfProtection=false", \
24
+ "--browser.gatherUsageStats=false"]
README.md CHANGED
@@ -1,8 +1,18 @@
1
- ---
2
- title: Huhb3D Synthetic Data Generator
3
- emoji: 🤖
4
- colorFrom: blue
5
- colorTo: indigo
6
- sdk: docker
7
- pinned: false
8
- ---
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Huhb3D Synthetic Data Generator
3
+ emoji: 🤖
4
+ colorFrom: blue
5
+ colorTo: indigo
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
10
+ # Huhb3D Synthetic Data Generator (Demo)
11
+
12
+ 面向机器人视觉训练的合成数据生成器 — 在线 Demo 展示
13
+
14
+ ⚠️ 此在线版本为 **Demo 模式**,展示预生成的样例数据(RGB + 语义Mask + 6DoF位姿 + BOP格式)。
15
+
16
+ 要使用自己的 CAD 模型生成数据,请在本地部署:
17
+ - GitHub: https://github.com/AIminminAI/Huhb3D-Viewer
18
+ - Gitee: https://gitee.com/aiminminai/Huhb3D-Viewer
app.py CHANGED
@@ -1,716 +1,221 @@
1
- """
2
- app.py - Huhb3D Synthetic Data Generator Web UI
3
- ================================================
4
- Streamlit-based web interface for the synthetic data pipeline.
5
-
6
- Usage:
7
- streamlit run app.py
8
- """
9
-
10
- import streamlit as st
11
- import subprocess
12
- import sys
13
- import os
14
- import shutil
15
- import zipfile
16
- import json
17
- import time
18
- import tempfile
19
- import re
20
- import random
21
- import base64
22
- from pathlib import Path
23
-
24
- import requests
25
-
26
-
27
- SUPPORTED_EXTENSIONS = ["step", "stp", "iges", "igs", "stl", "obj"]
28
- SUPPORTED_UPLOAD_TYPES = [".step", ".stp", ".iges", ".igs", ".stl", ".obj"]
29
-
30
- SCRIPT_DIR = Path(__file__).parent.resolve()
31
- TEMP_DIR = SCRIPT_DIR / "temp_uploads"
32
- OUTPUT_DIR = SCRIPT_DIR / "streamlit_output"
33
-
34
-
35
- DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
36
- DEEPSEEK_PROMPT = (
37
- "你是一个工业质检专家,请描述这张3D零件图中的关键特征"
38
- "(如:法兰盘、沉头孔、中心轴等),用于训练机器人视觉模型。"
39
- "请按以下JSON格式输出:\n"
40
- '{"part_type": "零件类型", "key_features": ["特征1", "特征2", ...], '
41
- '"surfaces": ["面类型1", "面类型2", ...], '
42
- '"manufacturing_hints": ["加工提示1", ...], '
43
- '"description": "详细描述"}'
44
- )
45
-
46
-
47
- def call_deepseek_vision(image_path, api_key, model="deepseek-chat"):
48
- try:
49
- with open(image_path, "rb") as f:
50
- img_b64 = base64.b64encode(f.read()).decode("utf-8")
51
-
52
- ext = Path(image_path).suffix.lower()
53
- mime_map = {".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg"}
54
- mime_type = mime_map.get(ext, "image/png")
55
-
56
- payload = {
57
- "model": model,
58
- "messages": [
59
- {
60
- "role": "user",
61
- "content": [
62
- {"type": "text", "text": DEEPSEEK_PROMPT},
63
- {
64
- "type": "image_url",
65
- "image_url": {
66
- "url": f"data:{mime_type};base64,{img_b64}"
67
- },
68
- },
69
- ],
70
- }
71
- ],
72
- "max_tokens": 1024,
73
- "temperature": 0.3,
74
- }
75
-
76
- headers = {
77
- "Authorization": f"Bearer {api_key}",
78
- "Content-Type": "application/json",
79
- }
80
-
81
- resp = requests.post(
82
- DEEPSEEK_API_URL,
83
- headers=headers,
84
- json=payload,
85
- timeout=60,
86
- )
87
- resp.raise_for_status()
88
-
89
- result = resp.json()
90
- content = result["choices"][0]["message"]["content"]
91
-
92
- description = {
93
- "source_image": Path(image_path).name,
94
- "model": model,
95
- "prompt": DEEPSEEK_PROMPT,
96
- "raw_response": content,
97
- }
98
-
99
- try:
100
- json_start = content.index("{")
101
- json_end = content.rindex("}") + 1
102
- parsed = json.loads(content[json_start:json_end])
103
- description["parsed"] = parsed
104
- except (ValueError, json.JSONDecodeError):
105
- description["parsed"] = None
106
-
107
- return True, description
108
-
109
- except requests.exceptions.Timeout:
110
- return False, "API request timed out (60s). Please try again."
111
- except requests.exceptions.ConnectionError:
112
- return False, "Cannot connect to DeepSeek API. Check your network."
113
- except requests.exceptions.HTTPError as e:
114
- code = e.response.status_code if e.response else "unknown"
115
- detail = ""
116
- try:
117
- detail = e.response.json().get("error", {}).get("message", "")
118
- except Exception:
119
- pass
120
- return False, f"API HTTP error {code}: {detail}"
121
- except KeyError as e:
122
- return False, f"Unexpected API response format: missing {e}"
123
- except Exception as e:
124
- return False, f"Unexpected error: {type(e).__name__}: {str(e)}"
125
-
126
-
127
- def find_cpp_executable():
128
- search_paths = [
129
- SCRIPT_DIR / "build" / "Release" / "test_render.exe",
130
- SCRIPT_DIR / "build_v2" / "Release" / "test_render.exe",
131
- SCRIPT_DIR / "build" / "test_render.exe",
132
- SCRIPT_DIR / "build_v2" / "test_render.exe",
133
- ]
134
- for path in search_paths:
135
- if path.exists():
136
- return str(path.resolve())
137
- return None
138
-
139
-
140
- def convert_to_stl(input_path, output_stl_path):
141
- input_path = Path(input_path)
142
- suffix = input_path.suffix.lower()
143
-
144
- if suffix in (".stl",):
145
- if str(input_path.resolve()) != str(output_stl_path):
146
- shutil.copy2(input_path, output_stl_path)
147
- return True
148
-
149
- if suffix in (".step", ".stp", ".iges", ".igs"):
150
- try:
151
- import cadquery as cq
152
- if suffix in (".step", ".stp"):
153
- shape = cq.importers.importStep(str(input_path))
154
- else:
155
- shape = cq.importers.importStep(str(input_path))
156
- cq.exporters.export(shape, str(output_stl_path), exportType="STL")
157
- return True
158
- except ImportError:
159
- pass
160
- except Exception as e:
161
- st.warning(f"cadquery conversion failed: {e}")
162
-
163
- try:
164
- import FreeCAD
165
- FreeCAD.open(str(input_path))
166
- doc = FreeCAD.ActiveDocument
167
- if doc is None:
168
- st.error("FreeCAD failed to open the file")
169
- return False
170
- import Mesh
171
- mesh_objs = []
172
- for obj in doc.Objects:
173
- if hasattr(obj, "Shape"):
174
- mesh_data = Mesh.Mesh(obj.Shape.tessellate(0.1))
175
- mesh_objs.append(mesh_data)
176
- if mesh_objs:
177
- combined = mesh_objs[0]
178
- for m in mesh_objs[1:]:
179
- combined = combined.unite(m)
180
- combined.write(str(output_stl_path))
181
- FreeCAD.closeDocument(doc.Name)
182
- return Path(output_stl_path).exists()
183
- except ImportError:
184
- pass
185
- except Exception as e:
186
- st.warning(f"FreeCAD conversion failed: {e}")
187
-
188
- st.error(
189
- "STEP/IGES format requires a conversion library.\n\n"
190
- "Please install one of:\n"
191
- "- `pip install cadquery` (recommended)\n"
192
- "- Or use FreeCAD with Python bindings\n\n"
193
- "Alternatively, convert your file to STL first using any CAD tool."
194
- )
195
- return False
196
-
197
- if suffix in (".obj",):
198
- try:
199
- import trimesh
200
- mesh = trimesh.load(str(input_path))
201
- mesh.export(str(output_stl_path))
202
- return True
203
- except ImportError:
204
- pass
205
- except Exception as e:
206
- st.warning(f"trimesh conversion failed: {e}")
207
-
208
- st.error(
209
- "OBJ format requires `trimesh` for conversion.\n"
210
- "Install with: `pip install trimesh`"
211
- )
212
- return False
213
-
214
- st.error(f"Unsupported format: {suffix}")
215
- return False
216
-
217
-
218
- def parse_progress(line, total_count):
219
- m = re.search(r'Progress:\s+(\d+)/(\d+)\s+\((\d+\.?\d*)%', line)
220
- if m:
221
- current = int(m.group(1))
222
- total = int(m.group(2))
223
- percent = float(m.group(3))
224
- return current, total, percent / 100.0
225
- return None
226
-
227
-
228
- def run_generation(stl_path, output_dir, sample_count, camera_radius,
229
- image_width, image_height, save_mask, save_depth=False,
230
- progress_callback=None):
231
- exe_path = find_cpp_executable()
232
- if not exe_path:
233
- return False, "C++ executable not found. Please compile the project first."
234
-
235
- cmd = [
236
- exe_path,
237
- "--batch",
238
- "--input", str(stl_path),
239
- "--output", str(output_dir),
240
- "--count", str(sample_count),
241
- "--radius", str(camera_radius),
242
- "--width", str(image_width),
243
- "--height", str(image_height),
244
- ]
245
- if not save_mask:
246
- cmd.append("--no-mask")
247
-
248
- if save_depth:
249
- cmd.append("--depth")
250
-
251
- try:
252
- process = subprocess.Popen(
253
- cmd,
254
- stdout=subprocess.PIPE,
255
- stderr=subprocess.STDOUT,
256
- text=True,
257
- bufsize=1,
258
- encoding='utf-8',
259
- errors='replace',
260
- cwd=str(SCRIPT_DIR),
261
- )
262
-
263
- log_lines = []
264
- for line in process.stdout:
265
- line = line.rstrip()
266
- if line:
267
- log_lines.append(line)
268
- progress_info = parse_progress(line, sample_count)
269
- if progress_info:
270
- current, total, pct = progress_info
271
- progress_callback(pct, f"Rendering: {current}/{total}")
272
-
273
- process.wait()
274
-
275
- if process.returncode != 0:
276
- return False, "C++ generator failed.\n\nLog:\n" + "\n".join(log_lines[-20:])
277
-
278
- return True, "\n".join(log_lines[-10:])
279
-
280
- except FileNotFoundError:
281
- return False, f"Executable not found: {exe_path}"
282
- except Exception as e:
283
- return False, f"Error: {str(e)}"
284
-
285
-
286
- def package_zip(output_dir):
287
- output_path = Path(output_dir)
288
- if not output_path.exists():
289
- return None
290
-
291
- zip_path = output_path.parent / (output_path.name + ".zip")
292
-
293
- rgb_dir = output_path / "rgb"
294
- mask_dir = output_path / "mask"
295
- depth_dir = output_path / "depth"
296
- legend_file = output_path / "label_legend.txt"
297
- desc_file = output_path / "description.json"
298
- poses_file = output_path / "camera_poses.json"
299
-
300
- rgb_count = len(list(rgb_dir.glob("*.png"))) if rgb_dir.exists() else 0
301
- mask_count = len(list(mask_dir.glob("*.png"))) if mask_dir.exists() else 0
302
- depth_count = len(list(depth_dir.glob("*.png"))) if depth_dir.exists() else 0
303
-
304
- with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
305
- if rgb_dir.exists():
306
- for f in sorted(rgb_dir.glob("*.png")):
307
- zf.write(f, f"rgb/{f.name}")
308
- if mask_dir.exists():
309
- for f in sorted(mask_dir.glob("*.png")):
310
- zf.write(f, f"mask/{f.name}")
311
- if depth_dir.exists():
312
- for f in sorted(depth_dir.glob("*.png")):
313
- zf.write(f, f"depth/{f.name}")
314
- for f in sorted(depth_dir.glob("*.raw")):
315
- zf.write(f, f"depth/{f.name}")
316
- if legend_file.exists():
317
- zf.write(legend_file, legend_file.name)
318
- if desc_file.exists():
319
- zf.write(desc_file, desc_file.name)
320
- if poses_file.exists():
321
- zf.write(poses_file, poses_file.name)
322
- manifest = {
323
- "version": "2.0",
324
- "generator": "Huhb3D-SyntheticDataPipeline",
325
- "rgb_count": rgb_count,
326
- "mask_count": mask_count,
327
- "depth_count": depth_count,
328
- "has_legend": legend_file.exists(),
329
- "has_ai_description": desc_file.exists(),
330
- "has_camera_poses": poses_file.exists(),
331
- }
332
- zf.writestr("manifest.json", json.dumps(manifest, indent=2))
333
-
334
- return str(zip_path)
335
-
336
-
337
- def get_generation_stats(output_dir):
338
- output_path = Path(output_dir)
339
- rgb_dir = output_path / "rgb"
340
- mask_dir = output_path / "mask"
341
- legend_file = output_path / "label_legend.txt"
342
-
343
- stats = {
344
- "rgb_count": len(list(rgb_dir.glob("*.png"))) if rgb_dir.exists() else 0,
345
- "mask_count": len(list(mask_dir.glob("*.png"))) if mask_dir.exists() else 0,
346
- "has_legend": legend_file.exists(),
347
- }
348
-
349
- if legend_file.exists():
350
- categories = {}
351
- with open(legend_file, 'r') as f:
352
- for line in f:
353
- line = line.strip()
354
- if not line or line.startswith('#'):
355
- continue
356
- parts = line.split()
357
- if len(parts) >= 4:
358
- cat_id = parts[0]
359
- cat_name = parts[1]
360
- cat_color = parts[2:5]
361
- categories[cat_id] = {"name": cat_name, "color": cat_color}
362
- stats["categories"] = categories
363
-
364
- return stats
365
-
366
-
367
- def main():
368
- st.set_page_config(
369
- page_title="Huhb3D Synthetic Data Generator",
370
- page_icon="🤖",
371
- layout="wide",
372
- )
373
-
374
- st.title("🤖 Huhb3D Synthetic Data Generator")
375
- st.markdown("---")
376
-
377
- col_left, col_right = st.columns([1, 2])
378
-
379
- with col_left:
380
- st.subheader("📁 Upload CAD Model")
381
- uploaded_file = st.file_uploader(
382
- "Supports STEP, STP, IGES, IGS, STL, OBJ",
383
- type=SUPPORTED_EXTENSIONS,
384
- help="Upload your CAD model file. STEP/IGES files will be auto-converted to STL.",
385
- )
386
-
387
- if uploaded_file is not None:
388
- file_ext = Path(uploaded_file.name).suffix.lower()
389
- file_size_mb = uploaded_file.size / (1024 * 1024)
390
- st.success(f"✅ {uploaded_file.name} ({file_size_mb:.1f} MB)")
391
-
392
- if file_ext in (".step", ".stp", ".iges", ".igs"):
393
- st.info("🔄 STEP/IGES will be auto-converted to STL")
394
- else:
395
- st.info("👆 Please upload a CAD model file")
396
-
397
- st.markdown("---")
398
- st.subheader("⚙️ Generation Settings")
399
-
400
- sample_count = st.slider(
401
- "📊 Sample Count",
402
- min_value=100,
403
- max_value=1000,
404
- value=500,
405
- step=50,
406
- help="Number of 360° views to render",
407
- )
408
-
409
- camera_radius = st.slider(
410
- "🔭 Camera Radius",
411
- min_value=2.0,
412
- max_value=20.0,
413
- value=5.0,
414
- step=0.5,
415
- help="Distance of camera from model center",
416
- )
417
-
418
- col_w, col_h = st.columns(2)
419
- with col_w:
420
- image_width = st.selectbox("Width", [512, 640, 800, 1024, 1280], index=2)
421
- with col_h:
422
- image_height = st.selectbox("Height", [480, 600, 720, 768, 960], index=1)
423
-
424
- save_mask = st.checkbox("🏷️ Generate Semantic Masks", value=True,
425
- help="Generate pixel-level semantic segmentation masks")
426
-
427
- save_depth = st.checkbox("📏 Generate Depth Maps", value=False,
428
- help="Generate depth maps for robot grasping planning")
429
-
430
- save_camera_poses = st.checkbox("📐 Export Camera Poses (6DoF)", value=True,
431
- help="Export camera position, rotation, view/projection matrices as JSON")
432
-
433
- st.markdown("---")
434
- st.subheader("🧠 AI Description")
435
-
436
- deepseek_api_key = st.text_input(
437
- "DeepSeek API Key",
438
- type="password",
439
- help="Enter your DeepSeek API key to generate AI-powered part descriptions",
440
- )
441
-
442
- enable_ai_desc = st.checkbox(
443
- "🧠 AI Feature Description",
444
- value=False,
445
- help="Use DeepSeek-V3 to describe key features of the generated part",
446
- )
447
-
448
- if enable_ai_desc and not deepseek_api_key:
449
- st.warning("⚠️ Please enter your DeepSeek API Key")
450
-
451
- with col_right:
452
- st.subheader("🚀 Generation Pipeline")
453
-
454
- exe_path = find_cpp_executable()
455
- if exe_path:
456
- st.success(f"✅ C++ Engine: `{Path(exe_path).name}`")
457
- else:
458
- st.error("❌ C++ Engine not found! Please compile the project first.")
459
- st.code("cd build && cmake --build . --config Release", language="bash")
460
-
461
- st.markdown("---")
462
-
463
- start_button = st.button(
464
- "🚀 Start Generation",
465
- disabled=(uploaded_file is None or exe_path is None),
466
- use_container_width=True,
467
- type="primary",
468
- )
469
-
470
- if start_button and uploaded_file is not None:
471
- TEMP_DIR.mkdir(exist_ok=True)
472
- OUTPUT_DIR.mkdir(exist_ok=True)
473
-
474
- session_id = str(int(time.time()))
475
- session_output = OUTPUT_DIR / f"run_{session_id}"
476
-
477
- file_ext = Path(uploaded_file.name).suffix.lower()
478
- temp_input = TEMP_DIR / f"upload_{session_id}{file_ext}"
479
- temp_stl = TEMP_DIR / f"upload_{session_id}.stl"
480
-
481
- with open(temp_input, "wb") as f:
482
- f.write(uploaded_file.getbuffer())
483
-
484
- st.info(f"📁 File saved: {uploaded_file.name}")
485
-
486
- if file_ext not in (".stl",):
487
- with st.spinner("Converting to STL..."):
488
- conv_ok = convert_to_stl(temp_input, temp_stl)
489
- if not conv_ok:
490
- st.stop()
491
- stl_path = temp_stl
492
- st.success("✅ Conversion to STL complete")
493
- else:
494
- stl_path = temp_input
495
-
496
- progress_bar = st.progress(0.0, text="Initializing...")
497
- status_text = st.empty()
498
- log_area = st.empty()
499
-
500
- def on_progress(pct, msg):
501
- progress_bar.progress(pct, text=msg)
502
-
503
- start_time = time.time()
504
-
505
- success, log_msg = run_generation(
506
- stl_path=stl_path,
507
- output_dir=session_output,
508
- sample_count=sample_count,
509
- camera_radius=camera_radius,
510
- image_width=image_width,
511
- image_height=image_height,
512
- save_mask=save_mask,
513
- save_depth=save_depth,
514
- progress_callback=on_progress,
515
- )
516
-
517
- elapsed = time.time() - start_time
518
-
519
- if success:
520
- progress_bar.progress(1.0, text="✅ Generation Complete!")
521
-
522
- stats = get_generation_stats(session_output)
523
-
524
- st.markdown("---")
525
- st.subheader("📊 Generation Results")
526
-
527
- col_s1, col_s2, col_s3, col_s4 = st.columns(4)
528
- with col_s1:
529
- st.metric("RGB Images", stats["rgb_count"])
530
- with col_s2:
531
- st.metric("Mask Images", stats["mask_count"])
532
- with col_s3:
533
- st.metric("Time", f"{elapsed:.1f}s")
534
- with col_s4:
535
- depth_count = len(list((session_output / "depth").glob("*.png"))) if (session_output / "depth").exists() else 0
536
- st.metric("Depth Maps", depth_count)
537
-
538
- if stats.get("categories"):
539
- with st.expander("🏷️ Label Categories", expanded=False):
540
- cat_data = []
541
- for cat_id, cat_info in stats["categories"].items():
542
- r, g, b = cat_info["color"]
543
- cat_data.append({
544
- "ID": cat_id,
545
- "Category": cat_info["name"],
546
- "Color (RGB)": f"({r}, {g}, {b})",
547
- })
548
- st.table(cat_data)
549
-
550
- ai_description = None
551
- if enable_ai_desc and deepseek_api_key:
552
- rgb_dir = session_output / "rgb"
553
- if rgb_dir.exists():
554
- png_files = sorted(rgb_dir.glob("*.png"))
555
- if png_files:
556
- sample_img = random.choice(png_files)
557
- st.markdown("---")
558
- st.subheader("🧠 AI Feature Description")
559
-
560
- col_ai_img, col_ai_text = st.columns([1, 2])
561
- with col_ai_img:
562
- st.image(str(sample_img), caption=f"Sampled: {sample_img.name}",
563
- use_container_width=True)
564
-
565
- with col_ai_text:
566
- with st.spinner("Calling DeepSeek-V3 API..."):
567
- ai_ok, ai_result = call_deepseek_vision(
568
- str(sample_img), deepseek_api_key
569
- )
570
-
571
- if ai_ok:
572
- ai_description = ai_result
573
- desc_path = session_output / "description.json"
574
- with open(desc_path, "w", encoding="utf-8") as f:
575
- json.dump(ai_description, f, indent=2, ensure_ascii=False)
576
-
577
- with col_ai_text:
578
- st.success("✅ AI description generated!")
579
-
580
- if ai_description.get("parsed"):
581
- parsed = ai_description["parsed"]
582
- st.markdown(f"**Part Type:** {parsed.get('part_type', 'N/A')}")
583
-
584
- features = parsed.get("key_features", [])
585
- if features:
586
- st.markdown("**Key Features:**")
587
- for feat in features:
588
- st.markdown(f"- {feat}")
589
-
590
- surfaces = parsed.get("surfaces", [])
591
- if surfaces:
592
- st.markdown("**Surfaces:** " + ", ".join(surfaces))
593
-
594
- hints = parsed.get("manufacturing_hints", [])
595
- if hints:
596
- st.markdown("**Manufacturing Hints:**")
597
- for h in hints:
598
- st.markdown(f"- {h}")
599
-
600
- desc_text = parsed.get("description", "")
601
- if desc_text:
602
- st.markdown(f"**Description:** {desc_text}")
603
- else:
604
- st.markdown(ai_description.get("raw_response", ""))
605
-
606
- with st.expander("📋 Raw JSON", expanded=False):
607
- st.json(ai_description)
608
- else:
609
- with col_ai_text:
610
- st.warning(f"⚠️ AI description failed: {ai_result}")
611
- st.info("The dataset will be packaged without AI description.")
612
- else:
613
- st.warning("⚠️ No RGB images found for AI description.")
614
-
615
- with st.spinner("Packaging ZIP..."):
616
- zip_path = package_zip(session_output)
617
-
618
- if zip_path:
619
- zip_size_mb = Path(zip_path).stat().st_size / (1024 * 1024)
620
-
621
- st.markdown("---")
622
- st.subheader("📦 Download Dataset")
623
-
624
- with open(zip_path, "rb") as f:
625
- st.download_button(
626
- label=f"⬇️ Download Dataset ({zip_size_mb:.1f} MB)",
627
- data=f.read(),
628
- file_name=Path(zip_path).name,
629
- mime="application/zip",
630
- use_container_width=True,
631
- type="primary",
632
- )
633
-
634
- if session_output.exists():
635
- preview_rgb = session_output / "rgb"
636
- if preview_rgb.exists():
637
- png_files = sorted(preview_rgb.glob("*.png"))
638
- if png_files:
639
- with st.expander("🖼️ Preview", expanded=True):
640
- preview_cols = st.columns(min(4, len(png_files[:4])))
641
- for idx, col in enumerate(preview_cols):
642
- if idx < len(png_files):
643
- col.image(
644
- str(png_files[idx]),
645
- caption=png_files[idx].name,
646
- use_container_width=True,
647
- )
648
- if len(png_files) > 4:
649
- st.caption(f"... and {len(png_files) - 4} more images")
650
-
651
- if save_mask:
652
- preview_mask = session_output / "mask"
653
- if preview_mask.exists():
654
- mask_files = sorted(preview_mask.glob("*.png"))
655
- if mask_files:
656
- with st.expander("🏷️ Mask Preview", expanded=True):
657
- mask_cols = st.columns(min(4, len(mask_files[:4])))
658
- for idx, col in enumerate(mask_cols):
659
- if idx < len(mask_files):
660
- col.image(
661
- str(mask_files[idx]),
662
- caption=mask_files[idx].name,
663
- use_container_width=True,
664
- )
665
-
666
- st.session_state["last_output_dir"] = str(session_output)
667
- else:
668
- progress_bar.progress(0.0, text="❌ Generation Failed")
669
- st.error(f"Generation failed!\n\n{log_msg}")
670
-
671
- elif uploaded_file is None and start_button:
672
- st.warning("Please upload a CAD model file first.")
673
-
674
- st.markdown("---")
675
- with st.expander("ℹ️ About", expanded=False):
676
- st.markdown("""
677
- **Huhb3D Synthetic Data Generator** - Pipeline for generating synthetic training data from CAD models.
678
-
679
- **Workflow:**
680
- 1. Upload a CAD model (STEP/IGES/STL/OBJ)
681
- 2. Configure generation parameters
682
- 3. Click "Start Generation" to run 360° sampling
683
- 4. Download the ZIP package with RGB images + semantic masks
684
-
685
- **Output Structure:**
686
- ```
687
- dataset.zip
688
- ├── rgb/frame_0001.png ~ frame_NNNN.png
689
- ├── mask/mask_0001.png ~ mask_NNNN.png
690
- ├── depth/depth_0001.png ~ depth_NNNN.png (if enabled)
691
- ├── label_legend.txt
692
- ├── camera_poses.json (6DoF camera poses)
693
- ├── description.json (if AI description enabled)
694
- └── manifest.json
695
- ```
696
-
697
- **Semantic Categories:**
698
- | ID | Category | Description |
699
- |----|----------|-------------|
700
- | 0 | FreeSurface | General curved surface |
701
- | 1 | HorizontalPlane | Top/bottom face (Y-axis) |
702
- | 2 | LateralPlane_X | Side face (X-axis) |
703
- | 3 | LateralPlane_Z | Front/back face (Z-axis) |
704
- | 4 | NearHorizontal | Near Y-axis surface |
705
- | 5 | NearLateral_X | Near X-axis surface |
706
- | 6 | NearLateral_Z | Near Z-axis surface |
707
- | 7 | Degenerate | Degenerate triangle |
708
- | 8 | ConvexFeature_Bolt | Convex protrusion (bolt/boss) |
709
- | 9 | ConcaveFeature_Hole | Concave depression (hole) |
710
- | 10 | Flange | Flange feature |
711
- | 11 | Boss | Boss/stud feature |
712
- """)
713
-
714
-
715
- if __name__ == "__main__":
716
- main()
 
1
+ """
2
+ app.py - Huhb3D Synthetic Data Generator (HuggingFace Space Demo)
3
+ =================================================================
4
+ Demo-only version for HuggingFace Spaces.
5
+ Shows pre-generated sample data: RGB, Mask, Depth, 6DoF, BOP format.
6
+ Full data generation requires local deployment with C++ engine compiled.
7
+ """
8
+
9
+ import streamlit as st
10
+ import json
11
+ import os
12
+ from pathlib import Path
13
+ from PIL import Image
14
+ import base64
15
+ from io import BytesIO
16
+
17
+ DEMO_DIR = Path(__file__).parent / "demo_data"
18
+
19
+ GITHUB_URL = "https://github.com/AIminminAI/Huhb3D-Viewer"
20
+ GITEE_URL = "https://gitee.com/aiminminai/Huhb3D-Viewer"
21
+
22
+
23
+ def image_to_base64(img_path):
24
+ if not img_path.exists():
25
+ return None
26
+ with open(img_path, "rb") as f:
27
+ return base64.b64encode(f.read()).decode()
28
+
29
+
30
+ def load_demo_data():
31
+ data = {"rgb": [], "mask": [], "depth": [], "manifest": None, "scene_camera": None, "scene_gt": None, "gt_6dof": None, "label_legend": None, "camera_poses": None}
32
+
33
+ rgb_dir = DEMO_DIR / "rgb"
34
+ mask_dir = DEMO_DIR / "mask"
35
+ depth_dir = DEMO_DIR / "depth"
36
+
37
+ if rgb_dir.exists():
38
+ data["rgb"] = sorted(rgb_dir.glob("*.png"))
39
+ if mask_dir.exists():
40
+ data["mask"] = sorted(mask_dir.glob("*.png"))
41
+ if depth_dir.exists():
42
+ data["depth"] = sorted(depth_dir.glob("*.png"))
43
+
44
+ manifest_path = DEMO_DIR / "manifest.json"
45
+ if manifest_path.exists():
46
+ data["manifest"] = json.loads(manifest_path.read_text(encoding="utf-8"))
47
+
48
+ scene_camera_path = DEMO_DIR / "scene_camera.json"
49
+ if scene_camera_path.exists():
50
+ data["scene_camera"] = json.loads(scene_camera_path.read_text(encoding="utf-8"))
51
+
52
+ scene_gt_path = DEMO_DIR / "scene_gt.json"
53
+ if scene_gt_path.exists():
54
+ data["scene_gt"] = json.loads(scene_gt_path.read_text(encoding="utf-8"))
55
+
56
+ gt_6dof_path = DEMO_DIR / "gt_6dof.json"
57
+ if gt_6dof_path.exists():
58
+ data["gt_6dof"] = json.loads(gt_6dof_path.read_text(encoding="utf-8"))
59
+
60
+ label_legend_path = DEMO_DIR / "label_legend.txt"
61
+ if label_legend_path.exists():
62
+ data["label_legend"] = label_legend_path.read_text(encoding="utf-8")
63
+
64
+ camera_poses_path = DEMO_DIR / "camera_poses.json"
65
+ if camera_poses_path.exists():
66
+ data["camera_poses"] = json.loads(camera_poses_path.read_text(encoding="utf-8"))
67
+
68
+ return data
69
+
70
+
71
+ def main():
72
+ st.set_page_config(
73
+ page_title="Huhb3D Synthetic Data Generator - Demo",
74
+ page_icon="🤖",
75
+ layout="wide",
76
+ )
77
+
78
+ st.title("🤖 Huhb3D Synthetic Data Generator")
79
+ st.markdown("**面向机器人视觉训练的合成数据生成器** — Demo 展示")
80
+
81
+ st.warning(
82
+ "⚠️ **在线 Demo 模式** — 当前展示预生成的样例数据。"
83
+ "要使用自己的 CAD 模型生成数据,请在本地部署并编译 C++ 渲染引擎。\n\n"
84
+ f"📦 GitHub: [{GITHUB_URL}]({GITHUB_URL}) | "
85
+ f"📦 Gitee: [{GITEE_URL}]({GITEE_URL})"
86
+ )
87
+
88
+ demo = load_demo_data()
89
+
90
+ if demo["manifest"]:
91
+ st.markdown("---")
92
+ st.subheader("📊 Demo 数据概览")
93
+ m = demo["manifest"]
94
+ col1, col2, col3, col4 = st.columns(4)
95
+ with col1:
96
+ st.metric("RGB 图像", m.get("rgb_count", len(demo["rgb"])))
97
+ with col2:
98
+ st.metric("语义 Mask", m.get("mask_count", len(demo["mask"])))
99
+ with col3:
100
+ st.metric("深度图", m.get("depth_count", len(demo["depth"])))
101
+ with col4:
102
+ has_6dof = "✅" if demo["gt_6dof"] else "❌"
103
+ st.metric("6DoF 位姿", has_6dof)
104
+
105
+ st.markdown("---")
106
+ st.subheader("🖼️ 渲染效果展示")
107
+
108
+ num_images = min(len(demo["rgb"]), len(demo["mask"]))
109
+ if num_images == 0:
110
+ st.info("暂无 Demo 数据。请在本地运行完整版。")
111
+ return
112
+
113
+ selected_idx = st.slider("选择视角", 0, num_images - 1, 0, key="view_slider")
114
+
115
+ col_rgb, col_mask, col_depth = st.columns(3)
116
+
117
+ with col_rgb:
118
+ st.markdown("**📷 RGB 渲染图**")
119
+ if selected_idx < len(demo["rgb"]):
120
+ st.image(str(demo["rgb"][selected_idx]), use_container_width=True)
121
+
122
+ with col_mask:
123
+ st.markdown("**🏷️ 语义分割 Mask**")
124
+ if selected_idx < len(demo["mask"]):
125
+ st.image(str(demo["mask"][selected_idx]), use_container_width=True)
126
+
127
+ with col_depth:
128
+ st.markdown("**📏 深度图**")
129
+ if selected_idx < len(demo["depth"]):
130
+ st.image(str(demo["depth"][selected_idx]), use_container_width=True)
131
+ else:
132
+ st.info("深度图需在本地编译 C++ 引擎后生成")
133
+
134
+ if demo["label_legend"]:
135
+ with st.expander("🏷️ 语义标签分类", expanded=False):
136
+ st.text(demo["label_legend"])
137
+
138
+ st.markdown("---")
139
+ st.subheader("📐 6DoF & BOP 格式数据")
140
+
141
+ tab_6dof, tab_scene_cam, tab_scene_gt, tab_poses = st.tabs(
142
+ ["🎯 6DoF Ground Truth", "📷 scene_camera.json", "📋 scene_gt.json", "🎥 camera_poses.json"]
143
+ )
144
+
145
+ with tab_6dof:
146
+ if demo["gt_6dof"]:
147
+ st.json(demo["gt_6dof"])
148
+ else:
149
+ st.info("6DoF 数据需在本地编译 C++ 引擎后生成")
150
+
151
+ with tab_scene_cam:
152
+ if demo["scene_camera"]:
153
+ st.json(demo["scene_camera"])
154
+ else:
155
+ st.info("BOP scene_camera 数据需在本地生成")
156
+
157
+ with tab_scene_gt:
158
+ if demo["scene_gt"]:
159
+ st.json(demo["scene_gt"])
160
+ else:
161
+ st.info("BOP scene_gt 数据需在本地生成")
162
+
163
+ with tab_poses:
164
+ if demo["camera_poses"]:
165
+ st.json(demo["camera_poses"])
166
+ else:
167
+ st.info("camera_poses 数据需在本地生成")
168
+
169
+ st.markdown("---")
170
+ st.subheader("📋 完整数据格式说明")
171
+
172
+ st.markdown("""
173
+ 每次生成输出一个 ZIP 包,结构如下:
174
+
175
+ ```
176
+ run_<timestamp>/
177
+ ├── rgb/ # RGB 渲染图 (PNG)
178
+ │ ├── view_000.png
179
+ │ ├── view_001.png
180
+ │ └── ...
181
+ ├── mask/ # 语义分割 Mask (PNG)
182
+ │ ├── view_000_mask.png
183
+ │ └── ...
184
+ ├── depth/ # 深度图 (PNG可视化 + RAW float)
185
+ │ ├── view_000_depth.png
186
+ │ └── view_000_depth.raw
187
+ ├── camera_poses.json # 6DoF 相机位姿
188
+ ├── scene_camera.json # BOP 格式相机内参
189
+ ├── scene_gt.json # BOP 格式 6DoF 位姿
190
+ ├── gt_6dof.json # 完整 6DoF + 四元数
191
+ ├── label_legend.txt # 语义标签对照表
192
+ └── manifest.json # 数据集元信息
193
+ ```
194
+ """)
195
+
196
+ st.markdown("---")
197
+ st.subheader("🔧 本地部署(解锁完整功能)")
198
+
199
+ st.markdown(f"""
200
+ **要使用自己的 CAD 模型生成数据,请按以下步骤本地部署:**
201
+
202
+ 1. 克隆仓库:`git clone {GITHUB_URL}`
203
+ 2. 安装 Python 依赖:`pip install streamlit Pillow numpy opencv-python`
204
+ 3. 编译 C++ 渲染引擎:需要 Visual Studio 2019+ (Windows) 或 GCC (Linux)
205
+ 4. 启动 Web UI:`streamlit run app.py --server.port 8501`
206
+
207
+ **Docker 部署(最省心):**
208
+ ```bash
209
+ docker build -t huhb3d-synthetic .
210
+ docker run -p 7860:7860 huhb3d-synthetic
211
+ ```
212
+
213
+ 详见 [GitHub README]({GITHUB_URL}) 获取完整部署指南。
214
+ """)
215
+
216
+ st.markdown("---")
217
+ st.caption("Huhb3D Synthetic Data Generator v2.0 | AGPL-3.0 License")
218
+
219
+
220
+ if __name__ == "__main__":
221
+ main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
demo_data/camera_poses.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "frame_id": 0,
4
+ "position": [0.0, 0.0, 5.0],
5
+ "rotation_euler": [0.0, 0.0, 0.0],
6
+ "fov_degrees": 45.0,
7
+ "view_matrix": [
8
+ [1.0, 0.0, 0.0, 0.0],
9
+ [0.0, 1.0, 0.0, 0.0],
10
+ [0.0, 0.0, 1.0, -5.0],
11
+ [0.0, 0.0, 0.0, 1.0]
12
+ ],
13
+ "projection_matrix": [
14
+ [2.414, 0.0, 0.0, 0.0],
15
+ [0.0, 2.414, 0.0, 0.0],
16
+ [0.0, 0.0, -1.002, -0.200],
17
+ [0.0, 0.0, -1.0, 0.0]
18
+ ]
19
+ },
20
+ {
21
+ "frame_id": 1,
22
+ "position": [1.18, 0.0, 4.86],
23
+ "rotation_euler": [0.0, -13.6, 0.0],
24
+ "fov_degrees": 45.0,
25
+ "view_matrix": [
26
+ [0.972, 0.0, 0.236, -0.0],
27
+ [0.0, 1.0, 0.0, 0.0],
28
+ [-0.236, 0.0, 0.972, -5.0],
29
+ [0.0, 0.0, 0.0, 1.0]
30
+ ],
31
+ "projection_matrix": [
32
+ [2.414, 0.0, 0.0, 0.0],
33
+ [0.0, 2.414, 0.0, 0.0],
34
+ [0.0, 0.0, -1.002, -0.200],
35
+ [0.0, 0.0, -1.0, 0.0]
36
+ ]
37
+ }
38
+ ]
demo_data/gt_6dof.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "frame_id": 0,
4
+ "position": [0.0, 0.0, 5.0],
5
+ "rotation_euler": [0.0, 0.0, 0.0],
6
+ "rotation_quaternion": [1.0, 0.0, 0.0, 0.0],
7
+ "fov_degrees": 45.0,
8
+ "view_matrix": [
9
+ [1.0, 0.0, 0.0, 0.0],
10
+ [0.0, 1.0, 0.0, 0.0],
11
+ [0.0, 0.0, 1.0, -5.0],
12
+ [0.0, 0.0, 0.0, 1.0]
13
+ ],
14
+ "projection_matrix": [
15
+ [2.414, 0.0, 0.0, 0.0],
16
+ [0.0, 2.414, 0.0, 0.0],
17
+ [0.0, 0.0, -1.002, -0.200],
18
+ [0.0, 0.0, -1.0, 0.0]
19
+ ],
20
+ "object_poses": [
21
+ {
22
+ "obj_id": 1,
23
+ "rotation_matrix": [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
24
+ "translation": [0.0, 0.0, 0.0],
25
+ "quaternion": [1.0, 0.0, 0.0, 0.0]
26
+ }
27
+ ]
28
+ },
29
+ {
30
+ "frame_id": 1,
31
+ "position": [1.18, 0.0, 4.86],
32
+ "rotation_euler": [0.0, -13.6, 0.0],
33
+ "rotation_quaternion": [0.9929, 0.0, -0.1188, 0.0],
34
+ "fov_degrees": 45.0,
35
+ "view_matrix": [
36
+ [0.972, 0.0, 0.236, -0.0],
37
+ [0.0, 1.0, 0.0, 0.0],
38
+ [-0.236, 0.0, 0.972, -5.0],
39
+ [0.0, 0.0, 0.0, 1.0]
40
+ ],
41
+ "projection_matrix": [
42
+ [2.414, 0.0, 0.0, 0.0],
43
+ [0.0, 2.414, 0.0, 0.0],
44
+ [0.0, 0.0, -1.002, -0.200],
45
+ [0.0, 0.0, -1.0, 0.0]
46
+ ],
47
+ "object_poses": [
48
+ {
49
+ "obj_id": 1,
50
+ "rotation_matrix": [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
51
+ "translation": [0.0, 0.0, 0.0],
52
+ "quaternion": [1.0, 0.0, 0.0, 0.0]
53
+ }
54
+ ]
55
+ }
56
+ ]
demo_data/label_legend.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Semantic Label Color Legend
2
+ # Category -> (R, G, B) in 0-255 range
3
+
4
+ 0 FreeSurface 127 127 127
5
+ 1 HorizontalPlane 0 0 255
6
+ 2 LateralPlane_X 0 255 0
7
+ 3 LateralPlane_Z 255 0 0
8
+ 4 NearHorizontal 255 255 0
9
+ 5 NearLateral_X 255 0 255
10
+ 6 NearLateral_Z 0 255 255
11
+ 7 Degenerate 255 127 0
12
+ 8 Reserved1 127 0 255
13
+ 9 Reserved2 0 127 255
demo_data/manifest.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "2.0",
3
+ "generator": "Huhb3D-SyntheticDataPipeline",
4
+ "rgb_count": 6,
5
+ "mask_count": 6,
6
+ "depth_count": 0,
7
+ "instance_mask_count": 0,
8
+ "has_legend": true,
9
+ "has_camera_poses": true,
10
+ "has_bop_format": true,
11
+ "has_6dof_gt": true,
12
+ "has_topology_labels": false,
13
+ "has_ai_description": false,
14
+ "note": "Demo data contains 6 sample frames. Full generation requires C++ engine compilation."
15
+ }
demo_data/mask/mask_0001.png ADDED
demo_data/mask/mask_0010.png ADDED
demo_data/mask/mask_0025.png ADDED
demo_data/mask/mask_0050.png ADDED
demo_data/mask/mask_0075.png ADDED
demo_data/mask/mask_0100.png ADDED
demo_data/rgb/frame_0001.png ADDED
demo_data/rgb/frame_0010.png ADDED

Git LFS Details

  • SHA256: 54327ba88976406916b0e53a691f5898dd609280786d44d94c2aef1d0bc68ad0
  • Pointer size: 131 Bytes
  • Size of remote file: 114 kB
demo_data/rgb/frame_0025.png ADDED

Git LFS Details

  • SHA256: 3f1541ec5792d9539a3f5aed5738cd67bf3ed13931884818326a3fa0d010bb40
  • Pointer size: 131 Bytes
  • Size of remote file: 141 kB
demo_data/rgb/frame_0050.png ADDED

Git LFS Details

  • SHA256: f9a0fd77d81775be182ec9d26ad6b32ec922b3ffe4fc151f04405c07038e9b07
  • Pointer size: 131 Bytes
  • Size of remote file: 159 kB
demo_data/rgb/frame_0075.png ADDED

Git LFS Details

  • SHA256: 98e0bd92660bac07f711fe2df666866553b4972f4505195708de34382dae4342
  • Pointer size: 131 Bytes
  • Size of remote file: 109 kB
demo_data/rgb/frame_0100.png ADDED
demo_data/scene_camera.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "cam_K": [1234.0, 0.0, 400.0, 0.0, 1234.0, 300.0, 0.0, 0.0, 1.0],
4
+ "depth_scale": 1.0,
5
+ "model_unit": "mm",
6
+ "cam_R_w2c": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
7
+ "cam_t_w2c": [0.0, 0.0, 5000.0]
8
+ },
9
+ "2": {
10
+ "cam_K": [1234.0, 0.0, 400.0, 0.0, 1234.0, 300.0, 0.0, 0.0, 1.0],
11
+ "depth_scale": 1.0,
12
+ "model_unit": "mm",
13
+ "cam_R_w2c": [0.972, 0.0, 0.236, 0.0, 1.0, 0.0, -0.236, 0.0, 0.972],
14
+ "cam_t_w2c": [0.0, 0.0, 5000.0]
15
+ }
16
+ }
demo_data/scene_gt.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": [
3
+ {"obj_id": 1, "cam_R_m2c": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], "cam_t_m2c": [0.0, 0.0, 0.0]}
4
+ ],
5
+ "2": [
6
+ {"obj_id": 1, "cam_R_m2c": [0.972, 0.0, 0.236, 0.0, 1.0, 0.0, -0.236, 0.0, 0.972], "cam_t_m2c": [0.0, 0.0, 0.0]}
7
+ ]
8
+ }
requirements.txt CHANGED
@@ -1,4 +1,2 @@
1
- streamlit>=1.28.0
2
- requests>=2.28.0
3
- Pillow>=9.0.0
4
- numpy>=1.21.0
 
1
+ streamlit>=1.28.0
2
+ Pillow>=9.0.0