0d32f32db0
Замкнутый контур "поток -> CV -> механика": товары идут по конвейеру с шагом 700 мм, класс определяется стереопайплайном во время движения, пушер и плуг реагируют физически. Состав: * control_test/ - ячейка и CV. run_sorting_cv.py + cv_worker.py (два процесса, потому что torch внутри Isaac роняет сцену), cell.py (физика лент, плуга, пушера), measure_plane.py (замер габаритов), README.md и .memory.md с замерами, проблемами и ловушками * robozon_sorter/ - модули симуляции, scripts/ - утилиты, scene/ - сцены * assets/ - меши товаров, плуг, объекты Objaverse Бейзлайн CV: DEFOM-Stereo vitl, вход 480, iters 24, кроп зоны осмотра, без сегментации. На потоке 700 мм - классы 8/9, габариты MAE 32.8 мм, 469 мс на товар при такте 700 мс. Веса моделей (4.5 ГБ) и пропсы конвейера NVIDIA (274 МБ) не включены - источники и команды скачивания в MODELS.md. Выход прогонов (captures/, runtime/) не включён: воспроизводится. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
61 lines
2.0 KiB
Python
61 lines
2.0 KiB
Python
"""Background plate: the same cameras, the same lighting, no object.
|
|
|
|
In simulation this gives an EXACT object mask by image difference, which beats every
|
|
height-threshold heuristic - and the height threshold is precisely what failed: CREStereo
|
|
puts the belt a few mm above belt_z, so a z-crop returns a belt patch whose footprint is
|
|
the crop window (measured 1700x1550x64 mm for every item, i.e. the crop, not the object).
|
|
"""
|
|
import json, os, sys
|
|
REPO = "/home/dasha/robozon-sorter"
|
|
for e in (REPO, f"{REPO}/control_test"):
|
|
if e not in sys.path:
|
|
sys.path.insert(0, e)
|
|
for _m in [k for k in list(sys.modules) if k.startswith("cam_configs")]:
|
|
del sys.modules[_m]
|
|
import importlib; importlib.invalidate_caches()
|
|
|
|
import asyncio
|
|
import omni.usd, omni.timeline
|
|
import omni.kit.viewport.utility as vp
|
|
import isaacsim.core.experimental.utils.app as app_utils
|
|
from pxr import UsdGeom
|
|
|
|
import cam_configs as CC
|
|
|
|
CFG = globals().get("cfg", CC.DEFAULT)
|
|
OUT = f"{REPO}/control_test/captures/{CFG}"
|
|
os.makedirs(OUT, exist_ok=True)
|
|
|
|
stage = omni.usd.get_context().get_stage()
|
|
tl = omni.timeline.get_timeline_interface()
|
|
if tl.is_playing():
|
|
tl.stop(); await app_utils.update_app_async(steps=10)
|
|
|
|
calib = CC.apply_config(stage, CFG)
|
|
root = stage.GetPrimAtPath("/World/CapItems")
|
|
if root.IsValid():
|
|
for c in root.GetChildren():
|
|
UsdGeom.Imageable(c).MakeInvisible()
|
|
await app_utils.update_app_async(steps=25)
|
|
|
|
w = vp.get_active_viewport()
|
|
orig = w.camera_path
|
|
bg = {}
|
|
for cam_name in calib:
|
|
w.camera_path = CC._cam(stage, cam_name).GetPath()
|
|
await app_utils.update_app_async(steps=22)
|
|
await asyncio.sleep(0)
|
|
f = f"{OUT}/__background__{cam_name}.png"
|
|
vp.capture_viewport_to_file(w, file_path=f)
|
|
await app_utils.update_app_async(steps=12)
|
|
await asyncio.sleep(0)
|
|
bg[cam_name] = f
|
|
w.camera_path = orig
|
|
await app_utils.update_app_async(steps=10)
|
|
|
|
man_path = f"{OUT}/manifest.json"
|
|
man = json.load(open(man_path))
|
|
man["background"] = bg
|
|
json.dump(man, open(man_path, "w"), indent=1)
|
|
print(f"background plate: {len(bg)} views -> {man_path}")
|