Instructions to use XXXpilar/Fastfill-test with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use XXXpilar/Fastfill-test with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
File size: 8,556 Bytes
e6f80f3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | """Structured3D (imChuling export, structured3d.jsonl: 22,894 rooms / 3,488 houses, official train/val/test).
Export (kits/convert_structured3d.py): meters, Z-up, room-local (floor polygon centroid, z from floor_z);
position = bbox_3d centroid (box center); the exported size/yaw come from a heuristic axis canonicalization
(row most aligned with world X), which discards the model frame. The raw bbox_3d fields are kept per object:
raw_basis rows = box axes in world, raw_coeffs = half extents (mm) along those rows. Row 2 is the model's up;
wall-contact statistics on beds / TVs / pictures / toilets put the back on raw +Y, so front = raw -Y.
Objects whose raw row 2 is not world +Z (~31k, almost all 'unknown'/'otherprop') are tilted relative to their
model pose -> tilted=True (raw_basis kept), boxed by the upright envelope of their rotated corners. Yaw follows
raw -Y when horizontal; when that front is near vertical, use raw X and mark front_known=False.
Category 'unknown' (41%: occluded in every view, or the corrupt
perspective_full_09.zip for scenes 1600-1799) keeps its box with category "unknown": build.prep drops it as a
generic label and rejects the room only if dropped floor boxes leave a real hole (hidden_floor_obstacle).
room_type 'undefined' -> None.
Boundary = floor polygon traced from annotation_3d junctions/lines.
Doors/windows: room_context.doors/windows (same room frame, position = opening centre on the wall centreline,
~0.1 m outside the floor polygon; width, height, no direction/thickness) -> structure boxes, see `openings`.
"""
import math
import os
import numpy as np
from fastfill.adapters.internscenes import tilted_bbox
from fastfill.adapters.unified import convert_room, iter_records
SOURCE = "Structured3D"
def _furniture(o):
B = np.array(o["raw_basis"], float)
ext = 2 * np.abs(np.array(o["raw_coeffs"], float)) / 1000
f = {"furniture_category": o["category"],
"furniture_instance_id": str(o["instance_id"]), "furniture_position": o["position"],
"furniture_size": {"width": ext[1], "length": ext[0], "height": ext[2]}, "raw_basis": o["raw_basis"]}
if B[2, 2] < 0.999: # model up is not world up
R = np.stack([-B[1], B[0], B[2]], axis=1) # semantic front first
size, yaw, k, _ = tilted_bbox(R, ext[[1, 0, 2]])
return {**f, "furniture_size": dict(zip(("width", "length", "height"), size)),
"furniture_rotation": {"x": None, "y": None, "z": yaw},
**({"front_known": False} if k == 0 else {})}
front = -B[1]
return {**f, "furniture_rotation": {"x": 0, "y": 0, "z": math.degrees(math.atan2(front[1], front[0]))}}
OPENING_T = 0.10 # opening box thickness (the export gives none)
SAME_M = 0.05 # an object box centred this close (xy and z) to an opening, same size, is that opening's box
def _edge_deg(poly, x, y):
"""Direction (deg) of the floor-polygon edge nearest to (x, y)."""
def dist(a, b):
dx, dy = b[0] - a[0], b[1] - a[1]
t = min(1.0, max(0.0, ((x - a[0]) * dx + (y - a[1]) * dy) / (dx * dx + dy * dy or 1)))
return math.hypot(x - a[0] - t * dx, y - a[1] - t * dy)
a, b = min(zip(poly, poly[1:] + poly[:1]), key=lambda e: dist(*e))
return math.degrees(math.atan2(b[1] - a[1], b[0] - a[0]))
def openings(rc, objs):
"""room_context doors/windows -> (structure furniture, objs without the boxes they replace). Box = [width along
the wall, OPENING_T, height] centred at the given position (z = centre -> bottom = sill), yaw = nearest floor
edge. ~15% of openings already carry an object box (unknown / otherstructure, same centre and size): that box is
replaced by the labelled opening instead of duplicated."""
out, dup = [], set()
for kind in ("door", "window"):
for k, d in enumerate(rc.get(kind + "s") or []):
p, wh = d["position"], sorted([d["width"], d["height"]])
for i, o in enumerate(objs):
q, ext = o["position"], sorted(2 * abs(c) / 1000 for c in o["raw_coeffs"])[1:]
if math.hypot(q["x"] - p["x"], q["y"] - p["y"]) < SAME_M and abs(q["z"] - p["z"]) < SAME_M \
and all(abs(u - v) < 0.3 for u, v in zip(ext, wh)):
dup.add(i)
out.append({"furniture_category": kind, "furniture_instance_id": f"{kind}_{k}", "structure": True,
"furniture_position": p,
"furniture_rotation": {"x": 0, "y": 0, "z": _edge_deg(rc["floor_polygon"], p["x"], p["y"])},
"furniture_size": {"width": d["width"], "length": OPENING_T, "height": d["height"]}})
return out, [o for i, o in enumerate(objs) if i not in dup]
def convert(rec):
rc, prov = rec["room_context"], rec["provenance"]
ops, objs = openings(rc, rec["layout"]["floor_layout"]["objects"])
room = {"room_id": rc["room_id"], "room_type": None if rc["room_type"] == "undefined" else rc["room_type"],
"room_boundary": rc["floor_polygon"], "room_height": rc["ceiling_height_m"],
"furniture": [_furniture(o) for o in objs] + ops}
return convert_room(room, source=SOURCE, uid=rec["sample_id"], group=f"structured3d:{prov['source_house_id']}",
subset=prov["split"], boundary_type="polygon", center_z=True,
extra=lambda f: {"structure": True} if f.get("structure") else
{**({"raw_basis": f["raw_basis"]} if f["furniture_rotation"]["x"] is None else {}),
**({"front_known": False} if f.get("front_known") is False else {})},
meta={"front_known": True, "room_origin_house_m": rec["room_origin_house_m"],
"n_nearest_assigned": sum(o.get("assignment_method") == "nearest" for o in objs),
"n_unknown_category": sum(o["category"] == "unknown" for o in objs)})
def load(root):
path = os.path.join(root, "imChuling__3D_Room_Collections/Structured3D_exported/structured3d.jsonl")
for rec in iter_records(path):
yield convert(rec)
if __name__ == "__main__":
# bed rotated 90 deg: raw row0 = world +Y, row1 = world -X (back on raw +Y -> world -X) -> front world +X, yaw 0
f = _furniture({"category": "bed", "instance_id": 1, "position": {"x": 0, "y": 0, "z": 0.5},
"raw_basis": [[0, 1, 0], [-1, 0, 0], [0, 0, 1]], "raw_coeffs": [800, 1000, 500]})
assert abs(f["furniture_rotation"]["z"]) < 1e-9 and f["furniture_size"]["width"] == 2.0, f
f = _furniture({"category": "unknown", "instance_id": 2, "position": {"x": 0, "y": 0, "z": 1},
"raw_basis": [[0, 0, -1], [0, 1, 0], [1, 0, 0]], "raw_coeffs": [1, 1, 1]})
assert f["furniture_category"] == "unknown" and f["furniture_rotation"]["x"] is None
# 4 x 3 room; door on the bottom wall already boxed as 'otherstructure' (replaced, not duplicated), window on the
# right wall (x = 4) 0.1 m outside the floor, centre z 1.5, height 1.4 -> sill 0.8
rec = {"sample_id": "t", "provenance": {"source_house_id": 0, "split": "train"}, "room_origin_house_m": [0, 0, 0],
"room_context": {"room_id": "r", "room_type": "undefined", "ceiling_height_m": 2.8,
"floor_polygon": [[0, 0], [4, 0], [4, 3], [0, 3]],
"doors": [{"position": {"x": 1, "y": -0.06, "z": 1.1}, "width": 0.7, "height": 2.2}],
"windows": [{"position": {"x": 4.1, "y": 1.5, "z": 1.5}, "width": 1.6, "height": 1.4}]},
"layout": {"floor_layout": {"objects": [
{"category": "otherstructure", "instance_id": 9, "position": {"x": 1, "y": -0.06, "z": 1.1},
"raw_basis": [[1, 0, 0], [0, 1, 0], [0, 0, 1]], "raw_coeffs": [350, 60, 1100]}]}}}
ir = convert(rec)
door, win = ir["objects"]
close = lambda a, b: all(abs(x - y) < 1e-6 for x, y in zip(a, b))
assert door["category"] == "door" and door["structure"] and close(door["pos"], [1, -0.06, 0]), door
assert close(door["size"], [0.7, OPENING_T, 2.2]) and abs(door["yaw"]) < 1e-9, door
assert win["category"] == "window" and close(win["pos"], [4.1, 1.5, 0.8]) and close(win["size"], [1.6, OPENING_T, 1.4])
assert abs(win["yaw"] - math.pi / 2) < 1e-9 and not win["tilted"], win
from fastfill.anchors import fixed_geometry
assert {o["category"] for o in fixed_geometry(ir)} == {"door", "window"}
print("structured3d.py self-check ok")
|