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>
72 lines
3.5 KiB
Python
72 lines
3.5 KiB
Python
"""Какая камера сдвинута: сверка живой сцены с тем, что записано в файле.
|
|
|
|
В сцене несколько камер разного назначения - шесть стереокамер стенда в /RigRS, корпуса
|
|
камер в /World/CameraBodies и служебная перспектива вьюпорта. Сдвиг любой из них
|
|
выглядит одинаково, а чинятся они по-разному, поэтому сначала находится ТА САМАЯ.
|
|
|
|
Живая сцена читается из памяти, эталон - из слоя на диске: несовпадение и есть правка,
|
|
сделанная мышью во вьюпорте.
|
|
"""
|
|
import sys
|
|
REPO = "/home/dasha/robozon-sorter"
|
|
if REPO not in sys.path:
|
|
sys.path.insert(0, REPO)
|
|
|
|
import omni.usd
|
|
from pxr import Usd, UsdGeom, Gf
|
|
|
|
live = omni.usd.get_context().get_stage()
|
|
path = live.GetRootLayer().identifier
|
|
print(f"живая сцена: {path}\n")
|
|
|
|
disk = Usd.Stage.Open(path)
|
|
cache_l = UsdGeom.XformCache()
|
|
cache_d = UsdGeom.XformCache()
|
|
|
|
cams = [p for p in live.Traverse() if p.IsA(UsdGeom.Camera)]
|
|
print(f"камер в сцене: {len(cams)}\n")
|
|
print(f" {'камера':44s} {'положение сейчас':>34s} расхождение с файлом")
|
|
print(" " + "-" * 104)
|
|
moved = []
|
|
for c in cams:
|
|
p = str(c.GetPath())
|
|
Ml = cache_l.GetLocalToWorldTransform(c)
|
|
tl_ = Ml.ExtractTranslation()
|
|
d = disk.GetPrimAtPath(p)
|
|
if not d or not d.IsValid():
|
|
print(f" {p:44s} ({tl_[0]:+7.3f},{tl_[1]:+7.3f},{tl_[2]:+7.3f}) нет в файле")
|
|
continue
|
|
Md = cache_d.GetLocalToWorldTransform(d)
|
|
td = Md.ExtractTranslation()
|
|
dt = (tl_ - td).GetLength()
|
|
# угловое расхождение по направлению взгляда камеры (-Z в её системе)
|
|
vl = Ml.TransformDir(Gf.Vec3d(0, 0, -1)); vd = Md.TransformDir(Gf.Vec3d(0, 0, -1))
|
|
vl = vl / (vl.GetLength() or 1); vd = vd / (vd.GetLength() or 1)
|
|
import math
|
|
ang = math.degrees(math.acos(max(-1.0, min(1.0, vl[0]*vd[0] + vl[1]*vd[1] + vl[2]*vd[2]))))
|
|
flag = "СДВИНУТА" if (dt > 0.001 or ang > 0.1) else "совпадает"
|
|
print(f" {p:44s} ({tl_[0]:+7.3f},{tl_[1]:+7.3f},{tl_[2]:+7.3f}) "
|
|
f"{dt*1000:7.1f} мм / {ang:5.2f}° {flag}")
|
|
if flag == "СДВИНУТА":
|
|
moved.append((p, td, tl_, dt, ang))
|
|
|
|
# служебная перспектива вьюпорта - её в файле обычно нет, она хранится в сессии
|
|
persp = live.GetPrimAtPath("/OmniverseKit_Persp")
|
|
if persp.IsValid():
|
|
M = cache_l.GetLocalToWorldTransform(persp)
|
|
t = M.ExtractTranslation()
|
|
print(f"\n перспектива вьюпорта /OmniverseKit_Persp: "
|
|
f"({t[0]:+.2f}, {t[1]:+.2f}, {t[2]:+.2f})")
|
|
|
|
print()
|
|
if moved:
|
|
print(f"СДВИНУТО КАМЕР: {len(moved)}")
|
|
for p, td, tlv, dt, ang in moved:
|
|
print(f" {p}")
|
|
print(f" было в файле: ({td[0]:+7.3f},{td[1]:+7.3f},{td[2]:+7.3f})")
|
|
print(f" стало сейчас: ({tlv[0]:+7.3f},{tlv[1]:+7.3f},{tlv[2]:+7.3f})")
|
|
print(f" расхождение {dt*1000:.1f} мм, поворот {ang:.2f}°")
|
|
else:
|
|
print("Ни одна камера-прем не сдвинута относительно файла.")
|
|
print("Значит двигали перспективу вьюпорта - она в файл не пишется и на прогоны не влияет.")
|