diff --git a/claude-notes/plans/2026-06-24-fma-torso-bodyparts3d-splat.md b/claude-notes/plans/2026-06-24-fma-torso-bodyparts3d-splat.md index 1ae80c020..d1e1e7b93 100644 --- a/claude-notes/plans/2026-06-24-fma-torso-bodyparts3d-splat.md +++ b/claude-notes/plans/2026-06-24-fma-torso-bodyparts3d-splat.md @@ -58,3 +58,53 @@ Notes: ~6.6 s/frame on the scalar path (no AVX target-cpu in the scratchpad project); correctness verified by viewing the rendered frames. - Colours: golden-angle hue per structure at S=0.34 V=0.78 (muted, per request). +- Brush: splat3d render uses gaussian scale 0.0025 (was 0.008 — the big isotropic + brush blobbed the detail into a "Warhol" look; 0.0025 at 810x1080 restores the + ribcage/vertebrae). Frames re-rendered. + +## Follow-up PR — anisotropic + GUID-tag + map (branch claude/torso-anisotropic-map) + +- [x] **SPL2 format** (supersedes SPL1): hdr 40B [`SPL2`|count|node_count|radius| + bbox]; body 21B [pos 3f | normal 3i8 | rgb 3u8 | opacity u8 | node_row u16]. + Helix-orderable + residual-ready (the codec PR slots in here). +- [x] **Anisotropic surface-fit gaussians** ("connect the dots"): bake reads OBJ + `vn` (BodyParts3D ships normals — free, no face traversal); render driver + orients each gaussian flat-to-surface (`scale=[t,t,thin]`, `quat` aligns + local-z to the normal). Tangent 0.004 connects within a structure while + rib gaps stay visible. NOT voxels (continuous surfaces, not a discrete grid). +- [x] **Per-node SoA + O(1) switch** (the GUID/value-tenant backbone): bake emits + `torso.nodes.json` — one row per FMA structure (178 rows, 91 own meshes): + fma id, name, depth, HHTL tier-ranks, colour, gaussian RANGE (start+count), + OBJ-geometry tenant (centroid + bbox + FJ handles). Each gaussian carries + its node_row. Consumers build the switch (row -> node) once -> O(1) tenant + reads. Position = real BodyParts3D coordinate; identity = the FMA node. +- [x] **/torso-map page**: click a gaussian -> node_row -> node SoA -> FMA label + + partonomy breadcrumb; structure list (graph -> splat) highlights gaussians. + Realises the osint-cad-splat thesis: graph and splat, one node at one address. +- [x] tsc clean. Browser pick-interaction not exercised here (raycast-on-Points + logic is standard; geometry verified via the CPU frames). + +## Helix-anchor codec — MEASURED (branch claude/torso-helix-codec) + +`tools/spl_codec.py` encodes SPL2 -> SPL3 and round-trips it. The x265-for- +gaussians design, mapped to signals already in SPL2 + the node SoA: + helix = 3D Morton (Z-order) of position = identity/GUID order (locality-preserving) + anchor = FMA node (SoA centroid + per-node colour) = the I-frame, random-access + motion = gaussian offset from its node anchor (the motion vector) + residual = helix-ordered zig-zag delta of (motion, normal) + colour = ANCHOR-PREDICTED -> 0 per-gaussian bytes (a 178-entry node palette) + +Measured on the real torso (231,515 gaussians): +- SPL2 21.0 B/g -> SPL3 7.47 B/g => **2.8x smaller** (zlib entropy stand-in) +- colour: **exact, 887 B total** for ALL colour (crisp by construction, no bleed) +- position round-trip RMSE **0.00001** (16-bit quant, effectively lossless) +- node_row RLE 35 KB / 231K gaussians (structures contiguous in helix order) +- stream split: motion 1.02 MB, normal 671 KB (the optimization target -> octahedral + + range coder), rows 35 KB, palette 887 B + +Validates the design before wiring it into the render. Next increments: +- [ ] octahedral normals + range coder (the 671 KB normal stream) +- [ ] decode SPL3 at cockpit load; anisotropic/edge-aware reconstruction + (node_row-bounded + normal-oriented = crisp colours in the render) +- [ ] animation: deform node anchors -> motion-skinned gaussians follow + (Motion-Blender GS; the partonomy is the rig) diff --git a/cockpit/public/torso-frames/torso_000.jpg b/cockpit/public/torso-frames/torso_000.jpg index bf2e52348..9c0af3e03 100644 Binary files a/cockpit/public/torso-frames/torso_000.jpg and b/cockpit/public/torso-frames/torso_000.jpg differ diff --git a/cockpit/public/torso-frames/torso_001.jpg b/cockpit/public/torso-frames/torso_001.jpg index 194cc4e17..3bbd92b9b 100644 Binary files a/cockpit/public/torso-frames/torso_001.jpg and b/cockpit/public/torso-frames/torso_001.jpg differ diff --git a/cockpit/public/torso-frames/torso_002.jpg b/cockpit/public/torso-frames/torso_002.jpg index 0f578e671..14704359e 100644 Binary files a/cockpit/public/torso-frames/torso_002.jpg and b/cockpit/public/torso-frames/torso_002.jpg differ diff --git a/cockpit/public/torso-frames/torso_003.jpg b/cockpit/public/torso-frames/torso_003.jpg index 58eec237a..7f6d27e5e 100644 Binary files a/cockpit/public/torso-frames/torso_003.jpg and b/cockpit/public/torso-frames/torso_003.jpg differ diff --git a/cockpit/public/torso-frames/torso_004.jpg b/cockpit/public/torso-frames/torso_004.jpg index 15b52f3e0..97d55ac61 100644 Binary files a/cockpit/public/torso-frames/torso_004.jpg and b/cockpit/public/torso-frames/torso_004.jpg differ diff --git a/cockpit/public/torso-frames/torso_005.jpg b/cockpit/public/torso-frames/torso_005.jpg index 18c60aef5..839b22edc 100644 Binary files a/cockpit/public/torso-frames/torso_005.jpg and b/cockpit/public/torso-frames/torso_005.jpg differ diff --git a/cockpit/public/torso-frames/torso_006.jpg b/cockpit/public/torso-frames/torso_006.jpg index fff4e708f..90dd2f336 100644 Binary files a/cockpit/public/torso-frames/torso_006.jpg and b/cockpit/public/torso-frames/torso_006.jpg differ diff --git a/cockpit/public/torso-frames/torso_007.jpg b/cockpit/public/torso-frames/torso_007.jpg index bfaaa5c2a..d0f15be4d 100644 Binary files a/cockpit/public/torso-frames/torso_007.jpg and b/cockpit/public/torso-frames/torso_007.jpg differ diff --git a/cockpit/public/torso-frames/torso_008.jpg b/cockpit/public/torso-frames/torso_008.jpg index f8220759e..e6c9f8146 100644 Binary files a/cockpit/public/torso-frames/torso_008.jpg and b/cockpit/public/torso-frames/torso_008.jpg differ diff --git a/cockpit/public/torso-frames/torso_009.jpg b/cockpit/public/torso-frames/torso_009.jpg index 7073d5bd1..7e1f44d58 100644 Binary files a/cockpit/public/torso-frames/torso_009.jpg and b/cockpit/public/torso-frames/torso_009.jpg differ diff --git a/cockpit/public/torso-frames/torso_010.jpg b/cockpit/public/torso-frames/torso_010.jpg index 053244925..bc852a363 100644 Binary files a/cockpit/public/torso-frames/torso_010.jpg and b/cockpit/public/torso-frames/torso_010.jpg differ diff --git a/cockpit/public/torso-frames/torso_011.jpg b/cockpit/public/torso-frames/torso_011.jpg index e7a5b09da..d6e48cb79 100644 Binary files a/cockpit/public/torso-frames/torso_011.jpg and b/cockpit/public/torso-frames/torso_011.jpg differ diff --git a/cockpit/public/torso-frames/torso_012.jpg b/cockpit/public/torso-frames/torso_012.jpg index b3bf3dabb..fc6c967a0 100644 Binary files a/cockpit/public/torso-frames/torso_012.jpg and b/cockpit/public/torso-frames/torso_012.jpg differ diff --git a/cockpit/public/torso-frames/torso_013.jpg b/cockpit/public/torso-frames/torso_013.jpg index a590c190a..ee60e32c3 100644 Binary files a/cockpit/public/torso-frames/torso_013.jpg and b/cockpit/public/torso-frames/torso_013.jpg differ diff --git a/cockpit/public/torso-frames/torso_014.jpg b/cockpit/public/torso-frames/torso_014.jpg index 7b63ac6d9..94c05405e 100644 Binary files a/cockpit/public/torso-frames/torso_014.jpg and b/cockpit/public/torso-frames/torso_014.jpg differ diff --git a/cockpit/public/torso-frames/torso_015.jpg b/cockpit/public/torso-frames/torso_015.jpg index 2b928111e..317b3ccc6 100644 Binary files a/cockpit/public/torso-frames/torso_015.jpg and b/cockpit/public/torso-frames/torso_015.jpg differ diff --git a/cockpit/public/torso-frames/torso_016.jpg b/cockpit/public/torso-frames/torso_016.jpg index cc535e5bc..dd22f0410 100644 Binary files a/cockpit/public/torso-frames/torso_016.jpg and b/cockpit/public/torso-frames/torso_016.jpg differ diff --git a/cockpit/public/torso-frames/torso_017.jpg b/cockpit/public/torso-frames/torso_017.jpg index 9f96a8d38..486df3ad2 100644 Binary files a/cockpit/public/torso-frames/torso_017.jpg and b/cockpit/public/torso-frames/torso_017.jpg differ diff --git a/cockpit/public/torso-frames/torso_018.jpg b/cockpit/public/torso-frames/torso_018.jpg index b1a4c29d8..fe3552fe7 100644 Binary files a/cockpit/public/torso-frames/torso_018.jpg and b/cockpit/public/torso-frames/torso_018.jpg differ diff --git a/cockpit/public/torso-frames/torso_019.jpg b/cockpit/public/torso-frames/torso_019.jpg index 1e462d46d..be0cf010e 100644 Binary files a/cockpit/public/torso-frames/torso_019.jpg and b/cockpit/public/torso-frames/torso_019.jpg differ diff --git a/cockpit/public/torso.manifest.json b/cockpit/public/torso.manifest.json index 712cebbef..d2e184d07 100644 --- a/cockpit/public/torso.manifest.json +++ b/cockpit/public/torso.manifest.json @@ -1,42 +1,23 @@ { - "source": "BodyParts3D 4.0 (DBCLS) part-of OBJ, decimated 99%", - "license": "CC-BY 4.0", - "attribution": "BodyParts3D, (c) The Database Center for Life Science licensed under CC Attribution 4.0 International", + "source": "BodyParts3D 4.0 (DBCLS) part-of OBJ, decimated 99%, with vn normals", + "license": "CC-BY 4.0 (site) / CC-BY-SA 2.1 JP (2013 files)", + "attribution": "BodyParts3D, (c) The Database Center for Life Science. Current site licence: CC-BY 4.0; 2013 mesh files embed CC-BY-SA 2.1 Japan.", + "format": "SPL2 (anisotropic + node-row tags); node SoA in torso.nodes.json", "root_fma": "FMA7181", "root_name": "trunk", - "concepts": 102, + "concepts": 178, "meshes": 577, - "vertices_total": 693959, - "gaussians": 231320, - "radius": 0.0045, + "gaussians": 231515, + "radius": 0.0035, "bbox_min": [ - -0.5499420475739409, - -0.2690260109315338, + -0.5499102767007714, + -0.269514341019139, -0.9999999999999999 ], "bbox_max": [ - 0.5499420475739409, - 0.2690260109315338, + 0.5499102767007714, + 0.269514341019139, 1.0000000000000002 ], - "regions": [ - { - "fma": "FMA259209", - "name": "thoracic segment of trunk" - }, - { - "fma": "FMA259211", - "name": "abdominal segment of trunk" - }, - { - "fma": "FMA10427", - "name": "body wall" - }, - { - "fma": "FMA9579", - "name": "perineum" - } - ], - "generated_by": "crates/osint-bake/tools/bake_torso_splat.py", - "format": "SPL1: hdr[magic4|count u32|radius f32|bbox_min 3f|bbox_max 3f]; body count*[pos 3f|rgb 3u8|opacity u8]; little-endian" + "owners": 91 } \ No newline at end of file diff --git a/cockpit/public/torso.nodes.json b/cockpit/public/torso.nodes.json new file mode 100644 index 000000000..d2a3dcd77 --- /dev/null +++ b/cockpit/public/torso.nodes.json @@ -0,0 +1 @@ +{"attribution": "BodyParts3D, (c) The Database Center for Life Science. Current site licence: CC-BY 4.0; 2013 mesh files embed CC-BY-SA 2.1 Japan.", "root": "FMA7181", "radius": 0.0035, "count": 231515, "nodes": [{"row": 0, "fma": "FMA7181", "name": "trunk", "depth": 0, "parent": null, "tiers": [2, 2], "rgb": [198, 131, 131], "g_start": 0, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 1, "fma": "FMA10427", "name": "body wall", "depth": 1, "parent": 0, "tiers": [2, 2, 1], "rgb": [131, 151, 198], "g_start": 0, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 2, "fma": "FMA259209", "name": "thoracic segment of trunk", "depth": 1, "parent": 0, "tiers": [2, 2, 2], "rgb": [170, 198, 131], "g_start": 0, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 3, "fma": "FMA259211", "name": "abdominal segment of trunk", "depth": 1, "parent": 0, "tiers": [2, 2, 3], "rgb": [198, 131, 190], "g_start": 0, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 4, "fma": "FMA9579", "name": "perineum", "depth": 1, "parent": 0, "tiers": [2, 2, 4], "rgb": [131, 198, 187], "g_start": 0, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 5, "fma": "FMA87598", "name": "skeletal system of trunk", "depth": 2, "parent": 1, "tiers": [2, 2, 1, 1], "rgb": [198, 167, 131], "g_start": 0, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 6, "fma": "FMA24217", "name": "back of thorax", "depth": 2, "parent": 2, "tiers": [2, 2, 2, 1], "rgb": [148, 131, 198], "g_start": 0, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 7, "fma": "FMA9576", "name": "thorax", "depth": 2, "parent": 2, "tiers": [2, 2, 2, 2], "rgb": [134, 198, 131], "g_start": 0, "g_count": 44704, "fj": ["FJ1654", "FJ1654M", "FJ1655", "FJ1656", "FJ1656M", "FJ1657", "FJ1658", "FJ1658M", "FJ1661", "FJ1661M", "FJ1662", "FJ1663", "FJ1672", "FJ1675", "FJ1675M", "FJ1677", "FJ1677M", "FJ1678", "FJ1678M", "FJ1680", "FJ1680M", "FJ1682", "FJ1682M", "FJ1684", "FJ1684M", "FJ1687", "FJ1687M", "FJ1689", "FJ1689M", "FJ1691", "FJ1691M", "FJ1692", "FJ1695", "FJ1695M", "FJ1700", "FJ1701", "FJ1702", "FJ1703", "FJ1704", "FJ1705", "FJ1706", "FJ1707", "FJ1708", "FJ1709", "FJ1710", "FJ1711", "FJ1713", "FJ1713M", "FJ1715", "FJ1720", "FJ1720M", "FJ1723", "FJ1723M", "FJ1725", "FJ1726", "FJ1726M", "FJ1727", "FJ1727M", "FJ1844", "FJ1935", "FJ1936", "FJ1937", "FJ1938", "FJ1969", "FJ1986", "FJ2041", "FJ2044", "FJ2209", "FJ2263", "FJ2264", "FJ2266", "FJ2267", "FJ2273", "FJ2275", "FJ2276", "FJ2277", "FJ2278", "FJ2282", "FJ2283", "FJ2284", "FJ2288", "FJ2291", "FJ2292", "FJ2293", "FJ2294", "FJ2295", "FJ2298", "FJ2303", "FJ2304", "FJ2305", "FJ2307", "FJ2308", "FJ2309", "FJ2310", "FJ2311", "FJ2361", "FJ2373", "FJ2441", "FJ2442", "FJ2443", "FJ2444", "FJ2445", "FJ2446", "FJ2447", "FJ2448", "FJ2449", "FJ2451", "FJ2452", "FJ2453", "FJ2454", "FJ2455", "FJ2456", "FJ2457", "FJ2458", "FJ2459", "FJ2460", "FJ2461", "FJ2462", "FJ2463", "FJ2464", "FJ2465", "FJ2466", "FJ2467", "FJ2468", "FJ2469", "FJ2470", "FJ2471", "FJ2472", "FJ2473", "FJ2474", "FJ2475", "FJ2476", "FJ2477", "FJ2478", "FJ2479", "FJ2480", "FJ2481", "FJ2482", "FJ2483", "FJ2484", "FJ2485", "FJ2486", "FJ2487", "FJ2488", "FJ2489", "FJ2490", "FJ2491", "FJ2492", "FJ2493", "FJ2494", "FJ2495", "FJ2496", "FJ2497", "FJ2498", "FJ2499", "FJ2500", "FJ2501", "FJ2502", "FJ2503", "FJ2504", "FJ2505", "FJ2506", "FJ2507", "FJ2508", "FJ2509", "FJ2510", "FJ2511", "FJ2512", "FJ2513", "FJ2514", "FJ2515", "FJ2516", "FJ2517", "FJ2518", "FJ2519", "FJ2520", "FJ2521", "FJ2522", "FJ2523", "FJ2524", "FJ2525", "FJ2526", "FJ2527", "FJ2528", "FJ2529", "FJ2530", "FJ2531", "FJ2532", "FJ2533", "FJ2534", "FJ2535", "FJ2536", "FJ2537", "FJ2538", "FJ2540", "FJ2881", "FJ2882", "FJ2883", "FJ2884", "FJ2885", "FJ2886", "FJ2887", "FJ2888", "FJ2889", "FJ2890", "FJ2891", "FJ2892", "FJ2893", "FJ2894", "FJ2895", "FJ2896", "FJ2897", "FJ2898", "FJ2899", "FJ2900", "FJ2901", "FJ2902", "FJ2903", "FJ2904", "FJ2905", "FJ2906", "FJ2907", "FJ2908", "FJ2909", "FJ2910", "FJ2911", "FJ2912", "FJ2913", "FJ2914", "FJ2915", "FJ2916", "FJ2917", "FJ2918", "FJ2919", "FJ2920", "FJ2921", "FJ2922", "FJ2923", "FJ2926", "FJ2927", "FJ2928", "FJ2929", "FJ2930", "FJ2931", "FJ2932", "FJ2934", "FJ2935", "FJ2936", "FJ2937", "FJ2938", "FJ2939", "FJ2940", "FJ2941", "FJ2942", "FJ2943", "FJ2945", "FJ2946", "FJ2947", "FJ2948", "FJ2949", "FJ2951", "FJ2952", "FJ2953", "FJ2954", "FJ2956", "FJ2957", "FJ2958", "FJ2959", "FJ2960", "FJ2961", "FJ2962", "FJ2963", "FJ2964", "FJ2965", "FJ2967", "FJ2968", "FJ2969", "FJ2970", "FJ2971", "FJ2972", "FJ2973", "FJ2974", "FJ2975", "FJ2976", "FJ2977", "FJ2978", "FJ2979", "FJ2980", "FJ2981", "FJ2982", "FJ2983", "FJ2984", "FJ2985", "FJ2986", "FJ2987", "FJ2988", "FJ2989", "FJ2990", "FJ2991", "FJ2992", "FJ2993", "FJ2994", "FJ2995", "FJ2996", "FJ2997", "FJ2998", "FJ2999", "FJ3000", "FJ3001", "FJ3002", "FJ3003", "FJ3004", "FJ3005", "FJ3006", "FJ3007", "FJ3008", "FJ3009", "FJ3010", "FJ3011", "FJ3012", "FJ3013", "FJ3014", "FJ3015", "FJ3016", "FJ3017", "FJ3018", "FJ3021", "FJ3022", "FJ3023", "FJ3024", "FJ3025", "FJ3026", "FJ3027", "FJ3028", "FJ3029", "FJ3030", "FJ3031", "FJ3032", "FJ3033", "FJ3034", "FJ3035", "FJ3036", "FJ3037", "FJ3038", "FJ3039", "FJ3041", "FJ3042", "FJ3043", "FJ3044", "FJ3045", "FJ3046", "FJ3047", "FJ3048", "FJ3049", "FJ3050", "FJ3051", "FJ3052", "FJ3053", "FJ3054", "FJ3055", "FJ3056", "FJ3057", "FJ3058", "FJ3059", "FJ3060", "FJ3061", "FJ3062", "FJ3063", "FJ3064", "FJ3065", "FJ3066", "FJ3067", "FJ3068", "FJ3069", "FJ3070", "FJ3417", "FJ3483", "FJ3564", "FJ3579"], "centroid": [0.010317096692664904, 0.05375881115695667, 0.2949866923091599], "bbox": [[-0.5499102767007714, -0.23159168544482167, -0.8869192254967141], [0.40302058634911486, 0.269514341019139, 1.0000000000000002]]}, {"row": 8, "fma": "FMA61681", "name": "back of abdomen", "depth": 2, "parent": 3, "tiers": [2, 2, 3, 1], "rgb": [198, 131, 153], "g_start": 44704, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 9, "fma": "FMA9577", "name": "abdomen", "depth": 2, "parent": 3, "tiers": [2, 2, 3, 2], "rgb": [131, 173, 198], "g_start": 44704, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 10, "fma": "FMA20347", "name": "anal part of perineum", "depth": 2, "parent": 4, "tiers": [2, 2, 4, 1], "rgb": [193, 198, 131], "g_start": 44704, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 11, "fma": "FMA7481", "name": "skeletal system of thorax", "depth": 3, "parent": 5, "tiers": [2, 2, 1, 1, 1], "rgb": [184, 131, 198], "g_start": 44704, "g_count": 7582, "fj": ["FJ3203", "FJ3204", "FJ3205", "FJ3206", "FJ3207", "FJ3208", "FJ3209", "FJ3210", "FJ3222", "FJ3223", "FJ3224"], "centroid": [0.10540595668456156, 0.10160013955383282, 0.095417055813201], "bbox": [[0.0589850971070855, 0.01840225455529603, -0.16116657939482334], [0.15355239546500205, 0.1745725699694647, 0.45801243770849653]]}, {"row": 12, "fma": "FMA13295", "name": "diaphragm", "depth": 3, "parent": 7, "tiers": [2, 2, 2, 2, 1], "rgb": [131, 198, 164], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 13, "fma": "FMA24816", "name": "anterior chest", "depth": 3, "parent": 7, "tiers": [2, 2, 2, 2, 2], "rgb": [198, 145, 131], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 14, "fma": "FMA50060", "name": "chest wall", "depth": 3, "parent": 7, "tiers": [2, 2, 2, 2, 3], "rgb": [131, 137, 198], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 15, "fma": "FMA87552", "name": "posterior chest", "depth": 3, "parent": 7, "tiers": [2, 2, 2, 2, 4], "rgb": [156, 198, 131], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 16, "fma": "FMA259054", "name": "wall of abdomen", "depth": 3, "parent": 9, "tiers": [2, 2, 3, 2, 1], "rgb": [198, 131, 176], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 17, "fma": "FMA61680", "name": "abdomen proper", "depth": 3, "parent": 9, "tiers": [2, 2, 3, 2, 2], "rgb": [131, 196, 198], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 18, "fma": "FMA85031", "name": "compartment of abdomen", "depth": 3, "parent": 9, "tiers": [2, 2, 3, 2, 3], "rgb": [198, 181, 131], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 19, "fma": "FMA9578", "name": "pelvis", "depth": 3, "parent": 9, "tiers": [2, 2, 3, 2, 4], "rgb": [162, 131, 198], "g_start": 52286, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 20, "fma": "FMA21930", "name": "external anal sphincter", "depth": 3, "parent": 10, "tiers": [2, 2, 4, 1, 1], "rgb": [131, 198, 142], "g_start": 52286, "g_count": 332, "fj": ["FJ1450", "FJ1450M", "FJ2543", "FJ2548"], "centroid": [0.10759787637018985, 0.18149805607197625, -0.9315997839694041], "bbox": [[0.07302852906740721, 0.15579880800390666, -0.9566362882206546], [0.1427632422764419, 0.20683483264398386, -0.9066971823942295]]}, {"row": 21, "fma": "FMA25572", "name": "right bony pectoral girdle", "depth": 4, "parent": 11, "tiers": [2, 2, 1, 1, 1, 1], "rgb": [198, 131, 139], "g_start": 52618, "g_count": 4373, "fj": ["FJ3384"], "centroid": [-0.17205331943675098, 0.1390846283529045, 0.33510217680692106], "bbox": [[-0.28390569934163695, 0.004649467249524938, 0.05607559114416352], [-0.026468196767607834, 0.258532703407132, 0.4465043214271005]]}, {"row": 22, "fma": "FMA25573", "name": "left bony pectoral girdle", "depth": 4, "parent": 11, "tiers": [2, 2, 1, 1, 1, 2], "rgb": [131, 159, 198], "g_start": 56991, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 23, "fma": "FMA9838", "name": "anterior mediastinum", "depth": 4, "parent": 13, "tiers": [2, 2, 2, 2, 2, 1], "rgb": [179, 198, 131], "g_start": 56991, "g_count": 402, "fj": ["FJ3150", "FJ3151"], "centroid": [0.10697354144923718, -0.07017674645476252, 0.3053723890856548], "bbox": [[0.049571975736466496, -0.12719024281183997, 0.2295680926297461], [0.15886354409973702, -0.03509001159048521, 0.3988715456529796]]}, {"row": 24, "fma": "FMA9839", "name": "middle mediastinum", "depth": 4, "parent": 13, "tiers": [2, 2, 2, 2, 2, 2], "rgb": [198, 131, 198], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 25, "fma": "FMA10428", "name": "thoracic wall", "depth": 4, "parent": 14, "tiers": [2, 2, 2, 2, 3, 1], "rgb": [131, 198, 178], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 26, "fma": "FMA25558", "name": "right lateral chest wall", "depth": 4, "parent": 14, "tiers": [2, 2, 2, 2, 3, 2], "rgb": [198, 159, 131], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 27, "fma": "FMA25559", "name": "left lateral chest wall", "depth": 4, "parent": 14, "tiers": [2, 2, 2, 2, 3, 3], "rgb": [139, 131, 198], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 28, "fma": "FMA50061", "name": "superficial chest wall", "depth": 4, "parent": 14, "tiers": [2, 2, 2, 2, 3, 4], "rgb": [142, 198, 131], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 29, "fma": "FMA87543", "name": "anterior chest wall", "depth": 4, "parent": 14, "tiers": [2, 2, 2, 2, 3, 5], "rgb": [198, 131, 162], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 30, "fma": "FMA73103", "name": "posterior thoracic wall", "depth": 4, "parent": 15, "tiers": [2, 2, 2, 2, 4, 1], "rgb": [131, 182, 198], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 31, "fma": "FMA9840", "name": "posterior mediastinum", "depth": 4, "parent": 15, "tiers": [2, 2, 2, 2, 4, 2], "rgb": [198, 195, 131], "g_start": 57393, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 32, "fma": "FMA10429", "name": "wall of abdomen proper", "depth": 4, "parent": 16, "tiers": [2, 2, 3, 2, 1, 1], "rgb": [176, 131, 198], "g_start": 57393, "g_count": 11843, "fj": ["FJ3131"], "centroid": [0.09271094508710954, 0.0019799681604802887, -0.10843146742313232], "bbox": [[-0.18002200427141743, -0.23646557272882385, -0.4100878405808185], [0.3922231962675108, 0.1856128307259645, 0.07631481405213957]]}, {"row": 33, "fma": "FMA10430", "name": "pelvic wall", "depth": 4, "parent": 16, "tiers": [2, 2, 3, 2, 1, 2], "rgb": [131, 198, 156], "g_start": 69236, "g_count": 1765, "fj": ["FJ3393"], "centroid": [0.10712398189690238, 0.1778520843882526, -0.6819352651875388], "bbox": [[-0.031948084039843026, 0.05515244723975833, -0.8879264798460877], [0.24480375602322807, 0.2632651279365995, -0.5484488165349743]]}, {"row": 34, "fma": "FMA16580", "name": "bony pelvis", "depth": 4, "parent": 16, "tiers": [2, 2, 3, 2, 1, 3], "rgb": [198, 136, 131], "g_start": 71001, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 35, "fma": "FMA86917", "name": "musculature of abdomen", "depth": 4, "parent": 16, "tiers": [2, 2, 3, 2, 1, 4], "rgb": [131, 145, 198], "g_start": 71001, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 36, "fma": "FMA259248", "name": "content of abdomen", "depth": 4, "parent": 18, "tiers": [2, 2, 3, 2, 3, 1], "rgb": [165, 198, 131], "g_start": 71001, "g_count": 409, "fj": ["FJ1932"], "centroid": [0.12609382263086505, -0.021932898091838685, -0.3146349896225359], "bbox": [[0.1058450052068931, -0.0656653585696047, -0.4976060058717279], [0.15478228126636348, 0.05261148340560228, -0.057005183359122316]]}, {"row": 37, "fma": "FMA20218", "name": "mons pubis", "depth": 4, "parent": 19, "tiers": [2, 2, 3, 2, 4, 1], "rgb": [198, 131, 185], "g_start": 71410, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 38, "fma": "FMA24228", "name": "posterior part of pelvis", "depth": 4, "parent": 19, "tiers": [2, 2, 3, 2, 4, 2], "rgb": [131, 198, 192], "g_start": 71410, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 39, "fma": "FMA24164", "name": "skeleton of left pectoral girdle", "depth": 5, "parent": 22, "tiers": [2, 2, 1, 1, 1, 2, 1], "rgb": [198, 173, 131], "g_start": 71410, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 40, "fma": "FMA79278", "name": "content of middle mediastinum", "depth": 5, "parent": 24, "tiers": [2, 2, 2, 2, 2, 2, 1], "rgb": [153, 131, 198], "g_start": 71410, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 41, "fma": "FMA7480", "name": "rib cage", "depth": 5, "parent": 25, "tiers": [2, 2, 2, 2, 3, 1, 1], "rgb": [131, 198, 133], "g_start": 71410, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 42, "fma": "FMA50071", "name": "right lateral superficial chest wall", "depth": 5, "parent": 26, "tiers": [2, 2, 2, 2, 3, 2, 1], "rgb": [198, 131, 148], "g_start": 71410, "g_count": 9489, "fj": ["FJ1459"], "centroid": [-0.15132494873970093, 0.084778338787786, 0.1604318239323867], "bbox": [[-0.2319826789906276, -0.12412141180346775, -0.19291391858419543], [-0.028041678678802355, 0.25907695023151556, 0.44302129236851906]]}, {"row": 43, "fma": "FMA50072", "name": "left lateral superficial chest wall", "depth": 5, "parent": 27, "tiers": [2, 2, 2, 2, 3, 3, 1], "rgb": [131, 168, 198], "g_start": 80899, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 44, "fma": "FMA13373", "name": "right pectoralis major", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 1], "rgb": [188, 198, 131], "g_start": 80899, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 45, "fma": "FMA13374", "name": "left pectoralis major", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 2], "rgb": [190, 131, 198], "g_start": 80899, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 46, "fma": "FMA13375", "name": "right pectoralis minor", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 3], "rgb": [131, 198, 170], "g_start": 80899, "g_count": 2247, "fj": ["FJ1456"], "centroid": [-0.13396469000688158, -0.0841125871369635, 0.2168011126451053], "bbox": [[-0.19841145634152516, -0.16053789264974966, 0.050662775715286254], [-0.056287161625492015, 0.05761692563850633, 0.39192902151594167]]}, {"row": 47, "fma": "FMA13376", "name": "left pectoralis minor", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 4], "rgb": [198, 150, 131], "g_start": 83146, "g_count": 2249, "fj": ["FJ1456M"], "centroid": [0.3495712751061257, -0.08429256463596761, 0.2165747509436634], "bbox": [[0.27194549530202927, -0.16053789264974966, 0.050662775715286254], [0.4140697900180624, 0.05761692563850633, 0.39192902151594167]]}, {"row": 48, "fma": "FMA13398", "name": "right serratus anterior", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 5], "rgb": [131, 131, 198], "g_start": 85395, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 49, "fma": "FMA13411", "name": "left subclavius", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 6], "rgb": [151, 198, 131], "g_start": 85395, "g_count": 386, "fj": ["FJ1460M"], "centroid": [0.2599042520628282, -0.022090888414151463, 0.387791979491539], "bbox": [[0.18852247789276744, -0.07042628274900423, 0.3559926338642211], [0.354175810598528, 0.07228965622738533, 0.42986579747833414]]}, {"row": 50, "fma": "FMA13412", "name": "right subclavius", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 7], "rgb": [198, 131, 171], "g_start": 85781, "g_count": 385, "fj": ["FJ1460"], "centroid": [-0.04447500710412921, -0.021779024942886156, 0.38798924986126077], "bbox": [[-0.13851747692199076, -0.07070163031647318, 0.3561338377449743], [0.027135855783769803, 0.07228965622738533, 0.4298422634982086]]}, {"row": 51, "fma": "FMA50063", "name": "anterior superficial chest wall", "depth": 5, "parent": 28, "tiers": [2, 2, 2, 2, 3, 4, 8], "rgb": [131, 190, 198], "g_start": 86166, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 52, "fma": "FMA24866", "name": "sternal part of chest", "depth": 5, "parent": 29, "tiers": [2, 2, 2, 2, 3, 5, 1], "rgb": [198, 187, 131], "g_start": 86166, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 53, "fma": "FMA61472", "name": "right pectoral part of chest", "depth": 5, "parent": 29, "tiers": [2, 2, 2, 2, 3, 5, 2], "rgb": [167, 131, 198], "g_start": 86166, "g_count": 195, "fj": ["FJ3362"], "centroid": [-0.0772423576039573, 0.009080901224717386, 0.41432130188771193], "bbox": [[-0.23307936246447844, -0.09877060841222116, 0.34989733301170234], [0.08509145893026294, 0.1186563038707514, 0.4592362046750253]]}, {"row": 54, "fma": "FMA61473", "name": "left pectoral part of chest", "depth": 5, "parent": 29, "tiers": [2, 2, 2, 2, 3, 5, 3], "rgb": [131, 198, 147], "g_start": 86361, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 55, "fma": "FMA87542", "name": "anterior thoracic wall", "depth": 5, "parent": 29, "tiers": [2, 2, 2, 2, 3, 5, 4], "rgb": [198, 131, 134], "g_start": 86361, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 56, "fma": "FMA10014", "name": "ninth thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 1], "rgb": [131, 154, 198], "g_start": 86361, "g_count": 481, "fj": ["FJ3175"], "centroid": [0.10635821247189149, 0.16812081572346818, 0.009432367860768821], "bbox": [[0.027385551312901924, 0.06444742803014707, -0.0787270470150085], [0.18548659445657098, 0.2322229138597493, 0.057934775574082185]]}, {"row": 57, "fma": "FMA10037", "name": "tenth thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 2], "rgb": [174, 198, 131], "g_start": 86842, "g_count": 528, "fj": ["FJ3154"], "centroid": [0.1054165245865017, 0.15724402749482028, -0.06181436111216585], "bbox": [[0.029301217295122, 0.04888911376914344, -0.14205698753287394], [0.18354598245541784, 0.22828287844110917, -0.007066077532697118]]}, {"row": 58, "fma": "FMA10059", "name": "eleventh thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 3], "rgb": [198, 131, 193], "g_start": 87370, "g_count": 531, "fj": ["FJ3155"], "centroid": [0.10767446927800119, 0.13858985228737827, -0.12314541793683946], "bbox": [[0.04492566204027841, 0.028945006971941644, -0.19846793789382644], [0.16798037266057533, 0.21600296528149587, -0.07291415392399665]]}, {"row": 59, "fma": "FMA10081", "name": "twelfth thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 4], "rgb": [131, 198, 184], "g_start": 87901, "g_count": 531, "fj": ["FJ3156"], "centroid": [0.10518985635374861, 0.11749873298214296, -0.19239417661633812], "bbox": [[0.05523754611189231, 0.008325474945136434, -0.25857372313449073], [0.1572091052969106, 0.1936157960074603, -0.13892696817617545]]}, {"row": 60, "fma": "FMA9165", "name": "first thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 5], "rgb": [198, 164, 131], "g_start": 88432, "g_count": 360, "fj": ["FJ3158"], "centroid": [0.10426215412468949, 0.10489091411862304, 0.47574117328657967], "bbox": [[0.019852088934910892, 0.042266416422011364, 0.4405502244553355], [0.1923542805368101, 0.20649876740779097, 0.5100225337859702]]}, {"row": 61, "fma": "FMA9187", "name": "second thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 6], "rgb": [144, 131, 198], "g_start": 88792, "g_count": 387, "fj": ["FJ3160"], "centroid": [0.10653181583432172, 0.1172337787595156, 0.43885748060320384], "bbox": [[0.024057375843546103, 0.052405090399901176, 0.39178781763518794], [0.18811133925997403, 0.21767246583160263, 0.4704619131949144]]}, {"row": 62, "fma": "FMA9209", "name": "third thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 7], "rgb": [137, 198, 131], "g_start": 89179, "g_count": 392, "fj": ["FJ3163"], "centroid": [0.10797081352646726, 0.14482364499807474, 0.3877983877542616], "bbox": [[0.030246812616566754, 0.06611951731806764, 0.3344119740890881], [0.18276347761624318, 0.24327282354810056, 0.42765360334653196]]}, {"row": 63, "fma": "FMA9248", "name": "fourth thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 8], "rgb": [198, 131, 157], "g_start": 89571, "g_count": 404, "fj": ["FJ3166"], "centroid": [0.10775638428997311, 0.1650159713356121, 0.33153517802844307], "bbox": [[0.024373672536433546, 0.08351630610647953, 0.27677725676160686], [0.1885083575046921, 0.2462448451758283, 0.37955014796990044]]}, {"row": 64, "fma": "FMA9922", "name": "fifth thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 9], "rgb": [131, 176, 198], "g_start": 89975, "g_count": 441, "fj": ["FJ3169"], "centroid": [0.10478815114178434, 0.17852420872841962, 0.27013170904043854], "bbox": [[0.02275029858737285, 0.09136512381815297, 0.18741873422487906], [0.18993851747692203, 0.24675422852671405, 0.32252731412568353]]}, {"row": 65, "fma": "FMA9945", "name": "sixth thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 10], "rgb": [196, 198, 131], "g_start": 90416, "g_count": 451, "fj": ["FJ3171"], "centroid": [0.1036646007712702, 0.18604635158276528, 0.2053113427509346], "bbox": [[0.022233257044014423, 0.09325231368442113, 0.11594603658357248], [0.1902778774703325, 0.24367353662769836, 0.256302694052375]]}, {"row": 66, "fma": "FMA9968", "name": "seventh thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 11], "rgb": [181, 131, 198], "g_start": 90867, "g_count": 493, "fj": ["FJ3173"], "centroid": [0.10727095992305208, 0.18627719470803827, 0.13716294599652093], "bbox": [[0.02022086640347832, 0.08908185706637171, 0.045391164167162185], [0.19329752246024232, 0.24468484352844969, 0.1921725982102409]]}, {"row": 67, "fma": "FMA9991", "name": "eighth thoracic vertebra", "depth": 5, "parent": 30, "tiers": [2, 2, 2, 2, 4, 1, 12], "rgb": [131, 198, 161], "g_start": 91360, "g_count": 464, "fj": ["FJ3174"], "centroid": [0.10516632130466301, 0.17705906476165859, 0.07132028468812315], "bbox": [[0.0297648367035954, 0.07738641030317651, -0.015020562815134555], [0.18233280577994554, 0.24399089234969143, 0.1245359393293993]]}, {"row": 68, "fma": "FMA79277", "name": "content of posterior mediastinum", "depth": 5, "parent": 31, "tiers": [2, 2, 2, 2, 4, 2, 1], "rgb": [198, 141, 131], "g_start": 91824, "g_count": 1623, "fj": ["FJ2450", "FJ2539"], "centroid": [0.11358744153594004, 0.06080176046351601, 0.23852420034665772], "bbox": [[-0.01080609765425054, 0.014917813457906548, 0.10347302711702855], [0.2780913942118176, 0.10237973253631591, 0.3244571004959788]]}, {"row": 69, "fma": "FMA14627", "name": "anterior abdominal wall", "depth": 5, "parent": 32, "tiers": [2, 2, 3, 2, 1, 1, 1], "rgb": [131, 140, 198], "g_start": 93447, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 70, "fma": "FMA14628", "name": "posterior abdominal wall", "depth": 5, "parent": 32, "tiers": [2, 2, 3, 2, 1, 1, 2], "rgb": [160, 198, 131], "g_start": 93447, "g_count": 9091, "fj": ["FJ3157", "FJ3159", "FJ3162", "FJ3165", "FJ3168", "FJ3212", "FJ3214", "FJ3215", "FJ3216", "FJ3217"], "centroid": [0.10517823453900285, 0.057656409138780555, -0.4189088003628912], "bbox": [[-0.011652850259167964, -0.026132978754699443, -0.6243717898180233], [0.22355727876587814, 0.20377282648984807, -0.2075049862620389]]}, {"row": 71, "fma": "FMA22324", "name": "right obturator internus", "depth": 5, "parent": 33, "tiers": [2, 2, 3, 2, 1, 2, 1], "rgb": [198, 131, 179], "g_start": 102538, "g_count": 628, "fj": ["FJ1426"], "centroid": [-0.009570533343321553, 0.07048854114393664, -0.8466625687062], "bbox": [[-0.172333452964399, -0.005328940323709889, -0.9172592326745779], [0.05715274141450988, 0.17693185147705145, -0.7828307847994022]]}, {"row": 72, "fma": "FMA22325", "name": "left obturator internus", "depth": 5, "parent": 33, "tiers": [2, 2, 3, 2, 1, 2, 2], "rgb": [131, 198, 198], "g_start": 103166, "g_count": 628, "fj": ["FJ1426M"], "centroid": [0.22532133232756826, 0.0703288552191418, -0.8459958862752643], "bbox": [[0.15850559226202734, -0.005328940323709889, -0.9172592326745779], [0.38799178664093625, 0.17693185147705145, -0.7828307847994022]]}, {"row": 73, "fma": "FMA22340", "name": "right piriformis", "depth": 5, "parent": 33, "tiers": [2, 2, 3, 2, 1, 2, 3], "rgb": [198, 178, 131], "g_start": 103794, "g_count": 266, "fj": ["FJ1428"], "centroid": [-0.05446942796635761, 0.14827187940197692, -0.7522252240826404], "bbox": [[-0.21437455506068825, 0.07727886001400273, -0.8332829313925643], [0.04785846664352492, 0.21827634776162436, -0.6771420334535526]]}, {"row": 74, "fma": "FMA22341", "name": "left piriformis", "depth": 5, "parent": 33, "tiers": [2, 2, 3, 2, 1, 2, 4], "rgb": [158, 131, 198], "g_start": 104060, "g_count": 266, "fj": ["FJ1428M"], "centroid": [0.26956288241888265, 0.14860560893487898, -0.7514912204761904], "bbox": [[0.16779492489718595, 0.07727886001400273, -0.8332829313925643], [0.4300328887372255, 0.21827634776162436, -0.6771420334535526]]}, {"row": 75, "fma": "FMA20226", "name": "right side of bony pelvis", "depth": 5, "parent": 34, "tiers": [2, 2, 3, 2, 1, 3, 1], "rgb": [131, 198, 139], "g_start": 104326, "g_count": 428, "fj": ["FJ3152"], "centroid": [-0.055713648097384924, 0.07465645464218484, -0.7477616902984299], "bbox": [[-0.23311231003665422, -0.07995519130184096, -0.9599616396123954], [0.10126248036383534, 0.24181028081921788, -0.4763995363805914]]}, {"row": 76, "fma": "FMA20227", "name": "left side of bony pelvis", "depth": 5, "parent": 34, "tiers": [2, 2, 3, 2, 1, 3, 2], "rgb": [198, 131, 143], "g_start": 104754, "g_count": 419, "fj": ["FJ3288"], "centroid": [0.2699648865433979, 0.07833254707466522, -0.7440618495464504], "bbox": [[0.1143017409261798, -0.08004226702830546, -0.9604064318367683], [0.4484929427477099, 0.24233362946924994, -0.4756958703748374]]}, {"row": 77, "fma": "FMA54319", "name": "pubic hair", "depth": 5, "parent": 37, "tiers": [2, 2, 3, 2, 4, 1, 1], "rgb": [131, 162, 198], "g_start": 105173, "g_count": 1841, "fj": ["FJ2815"], "centroid": [0.1309293797763671, -0.1703883078405796, -0.811799654485762], "bbox": [[-0.03763201091976678, -0.1938620085075338, -0.9292898033147611], [0.24893255749645524, -0.10594141215647745, -0.7795219071937494]]}, {"row": 78, "fma": "FMA13323", "name": "left clavicle", "depth": 6, "parent": 39, "tiers": [2, 2, 1, 1, 1, 2, 1, 1], "rgb": [182, 198, 131], "g_start": 107014, "g_count": 201, "fj": ["FJ3237"], "centroid": [0.2883733534812302, 0.009957588079652708, 0.4116891347389736], "bbox": [[0.12780527984844117, -0.09942249966169904, 0.3492383815681869], [0.44658198356151496, 0.11804253766907698, 0.4590243988538955]]}, {"row": 79, "fma": "FMA13396", "name": "left scapula", "depth": 6, "parent": 39, "tiers": [2, 2, 1, 1, 1, 2, 1, 2], "rgb": [195, 131, 198], "g_start": 107215, "g_count": 4690, "fj": ["FJ3279"], "centroid": [0.3868638152172092, 0.13926570151449089, 0.3337721157787016], "bbox": [[0.2422032512193544, 0.004698888607788603, 0.05605205716403799], [0.4995852136002872, 0.258652467831991, 0.4465043214271005]]}, {"row": 80, "fma": "FMA4838", "name": "azygos vein", "depth": 6, "parent": 40, "tiers": [2, 2, 2, 2, 2, 2, 1, 1], "rgb": [131, 198, 175], "g_start": 111905, "g_count": 3044, "fj": ["FJ3416"], "centroid": [0.08084882972606411, 0.06420998076251745, 0.08978612351333239], "bbox": [[0.065125583201445, -0.019291650732200932, -0.20329240381956484], [0.0945992104349668, 0.10581969441126811, 0.30868933381185765]]}, {"row": 81, "fma": "FMA7088", "name": "heart", "depth": 6, "parent": 40, "tiers": [2, 2, 2, 2, 2, 2, 1, 2], "rgb": [198, 155, 131], "g_start": 114949, "g_count": 12310, "fj": ["FJ2417", "FJ2419", "FJ2421", "FJ2423", "FJ2424", "FJ2427", "FJ2430", "FJ2433", "FJ2434", "FJ2436", "FJ2437", "FJ2439", "FJ2655", "FJ2667", "FJ2668", "FJ2670", "FJ2671", "FJ2672", "FJ2673", "FJ2674", "FJ2675", "FJ2676", "FJ2677", "FJ2692", "FJ2693", "FJ2694", "FJ2695", "FJ2696", "FJ2697", "FJ2698", "FJ2699", "FJ2700", "FJ2714", "FJ2715", "FJ2716", "FJ2717", "FJ2718", "FJ2719", "FJ2720", "FJ2721", "FJ2722", "FJ2723", "FJ2724", "FJ2727", "FJ2728", "FJ2729", "FJ2731"], "centroid": [0.12148518416250885, -0.07009765312258254, 0.13437674289877566], "bbox": [[0.02253331529061525, -0.16861240123082719, 0.034942076991416174], [0.2810218454170516, 0.054928403748963045, 0.2809192372637043]]}, {"row": 82, "fma": "FMA8612", "name": "pulmonary trunk", "depth": 6, "parent": 40, "tiers": [2, 2, 2, 2, 2, 2, 1, 3], "rgb": [136, 131, 198], "g_start": 127259, "g_count": 291, "fj": ["FJ2966"], "centroid": [0.1700755560049388, -0.07051633459391758, 0.2638934944254494], "bbox": [[0.13436302341042675, -0.12715964863767673, 0.2267910829749306], [0.20684838821653617, -0.027587378726458656, 0.31398447934010726]]}, {"row": 83, "fma": "FMA20224", "name": "right side of rib cage", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 1], "rgb": [146, 198, 131], "g_start": 127550, "g_count": 14332, "fj": ["FJ3330", "FJ3331", "FJ3332", "FJ3334", "FJ3336", "FJ3338", "FJ3340", "FJ3342", "FJ3344", "FJ3346", "FJ3347", "FJ3348"], "centroid": [-0.06003854357563291, 0.08344842183341099, 0.10223856542453355], "bbox": [[-0.21476286573275988, -0.21844089735066222, -0.3578165173239509], [0.07564291891955498, 0.23805063335824017, 0.4947489806844858]]}, {"row": 84, "fma": "FMA20225", "name": "left side of rib cage", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 2], "rgb": [198, 131, 165], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 85, "fma": "FMA7857", "name": "right first rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 3], "rgb": [131, 185, 198], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 86, "fma": "FMA7882", "name": "right second rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 4], "rgb": [198, 192, 131], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 87, "fma": "FMA7909", "name": "right third rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 5], "rgb": [172, 131, 198], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 88, "fma": "FMA7957", "name": "right fourth rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 6], "rgb": [131, 198, 153], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 89, "fma": "FMA8066", "name": "right fifth rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 7], "rgb": [198, 133, 131], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 90, "fma": "FMA8175", "name": "right sixth rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 8], "rgb": [131, 148, 198], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 91, "fma": "FMA8229", "name": "right seventh rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 9], "rgb": [168, 198, 131], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 92, "fma": "FMA8283", "name": "right eighth rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 10], "rgb": [198, 131, 188], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 93, "fma": "FMA8364", "name": "right ninth rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 11], "rgb": [131, 198, 189], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 94, "fma": "FMA8445", "name": "right tenth rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 12], "rgb": [198, 169, 131], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 95, "fma": "FMA8531", "name": "right eleventh rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 13], "rgb": [150, 131, 198], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 96, "fma": "FMA8533", "name": "right twelfth rib", "depth": 6, "parent": 41, "tiers": [2, 2, 2, 2, 3, 1, 1, 14], "rgb": [132, 198, 131], "g_start": 141882, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 97, "fma": "FMA13399", "name": "left serratus anterior", "depth": 6, "parent": 43, "tiers": [2, 2, 2, 2, 3, 3, 1, 1], "rgb": [198, 131, 151], "g_start": 141882, "g_count": 9484, "fj": ["FJ1459M"], "centroid": [0.3669847818003871, 0.08471221100533585, 0.1605305564599925], "bbox": [[0.2437000123553396, -0.12416612636570631, -0.19291391858419543], [0.44764101266716483, 0.2590990015708932, 0.44302129236851906]]}, {"row": 98, "fma": "FMA45874", "name": "abdominal part of right pectoralis major", "depth": 6, "parent": 44, "tiers": [2, 2, 2, 2, 3, 4, 1, 1], "rgb": [131, 171, 198], "g_start": 151366, "g_count": 340, "fj": ["FJ1446"], "centroid": [-0.15390160858215038, -0.13921912108198184, 0.04661361599950738], "bbox": [[-0.3178911200409491, -0.2555939917748739, -0.1302664634899715], [-0.005975983573281866, 0.054305223955238395, 0.27724793636411804]]}, {"row": 99, "fma": "FMA79979", "name": "sternocostal part of right pectoralis major", "depth": 6, "parent": 44, "tiers": [2, 2, 2, 2, 3, 4, 1, 2], "rgb": [191, 198, 131], "g_start": 151706, "g_count": 1827, "fj": ["FJ1464"], "centroid": [-0.0828016602173157, -0.14345401292344645, 0.1964864914100704], "bbox": [[-0.33425194302423417, -0.269514341019139, -0.045944212700112466], [0.0964962139709473, 0.05608533421193528, 0.360793565809834]]}, {"row": 100, "fma": "FMA45875", "name": "abdominal part of left pectoralis major", "depth": 6, "parent": 45, "tiers": [2, 2, 2, 2, 3, 4, 2, 1], "rgb": [186, 131, 198], "g_start": 153533, "g_count": 340, "fj": ["FJ1446M"], "centroid": [0.369559944335215, -0.139219162612535, 0.046611747124615056], "bbox": [[0.2216343172498191, -0.2555939917748739, -0.1302664634899715], [0.5335494537174864, 0.054305223955238395, 0.27724793636411804]]}, {"row": 101, "fma": "FMA79980", "name": "sternocostal part of left pectoralis major", "depth": 6, "parent": 45, "tiers": [2, 2, 2, 2, 3, 4, 2, 2], "rgb": [131, 198, 167], "g_start": 153873, "g_count": 1822, "fj": ["FJ1464M"], "centroid": [0.29844246571864685, -0.14369975521237802, 0.19550954092677067], "bbox": [[0.11916211970558993, -0.269514341019139, -0.045944212700112466], [0.5499102767007714, 0.05608533421193528, 0.360793565809834]]}, {"row": 102, "fma": "FMA7485", "name": "sternum", "depth": 6, "parent": 52, "tiers": [2, 2, 2, 2, 3, 5, 1, 1], "rgb": [198, 147, 131], "g_start": 155695, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 103, "fma": "FMA9761", "name": "right transversus thoracis", "depth": 6, "parent": 55, "tiers": [2, 2, 2, 2, 3, 5, 4, 1], "rgb": [131, 134, 198], "g_start": 155695, "g_count": 1583, "fj": ["FJ1461"], "centroid": [0.03745993200322515, -0.19347359376858944, 0.12248909259302164], "bbox": [[-0.10297457741796939, -0.24637573175969452, -0.038954620602822926], [0.10201050792212607, -0.11928047209164129, 0.30188801355557293]]}, {"row": 104, "fma": "FMA9762", "name": "left transversus thoracis", "depth": 6, "parent": 55, "tiers": [2, 2, 2, 2, 3, 5, 4, 2], "rgb": [154, 198, 131], "g_start": 157278, "g_count": 1582, "fj": ["FJ1461M"], "centroid": [0.1783290889433229, -0.1934155144580503, 0.12273126090654779], "bbox": [[0.11331496113951532, -0.24637573175969452, -0.038954620602822926], [0.3186329110945066, -0.11928047209164129, 0.30188801355557293]]}, {"row": 105, "fma": "FMA4944", "name": "hemiazygos vein", "depth": 6, "parent": 68, "tiers": [2, 2, 2, 2, 4, 2, 1, 1], "rgb": [198, 131, 174], "g_start": 158860, "g_count": 712, "fj": ["FJ3434"], "centroid": [0.13743531088652178, 0.08932562381739265, -0.043449346380060566], "bbox": [[0.07067607241405685, 0.06842208193355181, -0.21143516094300654], [0.16440061894367733, 0.11702728176646057, 0.03322409644225071]]}, {"row": 106, "fma": "FMA78435", "name": "musculature of anterior abdominal wall", "depth": 6, "parent": 69, "tiers": [2, 2, 3, 2, 1, 1, 1, 1], "rgb": [131, 194, 198], "g_start": 159572, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 107, "fma": "FMA22342", "name": "right psoas major", "depth": 6, "parent": 70, "tiers": [2, 2, 3, 2, 1, 1, 2, 1], "rgb": [198, 183, 131], "g_start": 159572, "g_count": 1211, "fj": ["FJ1431"], "centroid": [0.00901594668614861, 0.05214731791550914, -0.4737275978821296], "bbox": [[-0.15988868427400613, -0.034675813540275456, -0.9999999999999999], [0.09023706954879478, 0.12166300517159216, -0.1444809874858059]]}, {"row": 108, "fma": "FMA22343", "name": "left psoas major", "depth": 6, "parent": 70, "tiers": [2, 2, 3, 2, 1, 1, 2, 2], "rgb": [164, 131, 198], "g_start": 160783, "g_count": 1212, "fj": ["FJ1431M"], "centroid": [0.20657124861026716, 0.05224140846133193, -0.4737421286652014], "bbox": [[0.12542126412774246, -0.034675813540275456, -0.9999999999999999], [0.3755446645525308, 0.12166300517159216, -0.1444809874858059]]}, {"row": 109, "fma": "FMA7166", "name": "left side of heart", "depth": 7, "parent": 81, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1], "rgb": [131, 198, 144], "g_start": 161995, "g_count": 2822, "fj": ["FJ2631", "FJ2632", "FJ2633", "FJ2634", "FJ2635", "FJ2636", "FJ2637", "FJ2638", "FJ2639", "FJ2640", "FJ2641", "FJ2642", "FJ2643", "FJ2644", "FJ2645", "FJ2646", "FJ2647", "FJ2648", "FJ2649", "FJ2650", "FJ2651", "FJ2652", "FJ2653", "FJ2654", "FJ2656", "FJ2737"], "centroid": [0.24249216026371986, -0.08117421853144415, 0.13298977530707348], "bbox": [[0.1630055246018345, -0.1598765878082216, 0.045461766107538784], [0.29466849447245647, 0.05391361852594919, 0.23695776238916968]]}, {"row": 110, "fma": "FMA9465", "name": "cavity of left atrium", "depth": 7, "parent": 81, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 2], "rgb": [198, 131, 137], "g_start": 164817, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 111, "fma": "FMA9466", "name": "cavity of left ventricle", "depth": 7, "parent": 81, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 3], "rgb": [131, 157, 198], "g_start": 164817, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 112, "fma": "FMA9496", "name": "fibrous skeleton of heart", "depth": 7, "parent": 81, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 4], "rgb": [177, 198, 131], "g_start": 164817, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 113, "fma": "FMA7875", "name": "right first costal cartilage", "depth": 7, "parent": 83, "tiers": [2, 2, 2, 2, 3, 1, 1, 1, 1], "rgb": [198, 131, 197], "g_start": 164817, "g_count": 146, "fj": ["FJ3333"], "centroid": [0.01603040106657289, -0.06817569276743565, 0.3526419431459341], "bbox": [[-0.024402148652385457, -0.10808065094989028, 0.32193896462254473], [0.06166397006477729, -0.04080876876099476, 0.3767496043349594]]}, {"row": 114, "fma": "FMA7886", "name": "right second costal cartilage", "depth": 7, "parent": 83, "tiers": [2, 2, 2, 2, 3, 1, 1, 1, 2], "rgb": [131, 198, 180], "g_start": 164963, "g_count": 128, "fj": ["FJ3335"], "centroid": [0.044471507704436725, -0.15016369133420013, 0.2812698567957312], "bbox": [[-0.0055740231927374085, -0.17280850988721339, 0.2588443639059346], [0.08364000070601942, -0.12452619626162727, 0.30097018833067607]]}, {"row": 115, "fma": "FMA7913", "name": "right third costal cartilage", "depth": 7, "parent": 83, "tiers": [2, 2, 2, 2, 3, 1, 1, 1, 3], "rgb": [198, 161, 131], "g_start": 165091, "g_count": 129, "fj": ["FJ3337"], "centroid": [0.0342434680548796, -0.17953058083368023, 0.21714160382159026], "bbox": [[-0.011545064630192928, -0.20043269575858844, 0.1937729088587787], [0.0767299534615543, -0.1567112674813346, 0.23465143233686536]]}, {"row": 116, "fma": "FMA7976", "name": "right fourth costal cartilage", "depth": 7, "parent": 83, "tiers": [2, 2, 2, 2, 3, 1, 1, 1, 4], "rgb": [141, 131, 198], "g_start": 165220, "g_count": 131, "fj": ["FJ3339"], "centroid": [0.02282591272657015, -0.20443570002385286, 0.1474274956921366], "bbox": [[-0.03315537722028394, -0.2200012002329864, 0.12020568698629759], [0.07413086069648814, -0.18693595815658337, 0.17727558879076552]]}, {"row": 117, "fma": "FMA8070", "name": "right fifth costal cartilage", "depth": 7, "parent": 83, "tiers": [2, 2, 2, 2, 3, 1, 1, 1, 5], "rgb": [140, 198, 131], "g_start": 165351, "g_count": 218, "fj": ["FJ3341"], "centroid": [-0.01025655546843064, -0.22310208279502508, 0.06951889149771828], "bbox": [[-0.08553966358175412, -0.24523433372360517, 0.027011125689104274], [0.06610859755128938, -0.1988606258862014, 0.12971341495702124]]}, {"row": 118, "fma": "FMA8194", "name": "right sixth costal cartilage", "depth": 7, "parent": 83, "tiers": [2, 2, 2, 2, 3, 1, 1, 1, 6], "rgb": [198, 131, 160], "g_start": 165569, "g_count": 324, "fj": ["FJ3343"], "centroid": [-0.0335370635127647, -0.22293267705488512, 0.00016815174071207177], "bbox": [[-0.11267810810333773, -0.2523745432936982, -0.052957338777527], [0.07519812669518201, -0.18807970959068526, 0.08728164879064781]]}, {"row": 119, "fma": "FMA8248", "name": "right seventh costal cartilage", "depth": 7, "parent": 83, "tiers": [2, 2, 2, 2, 3, 1, 1, 1, 7], "rgb": [131, 180, 198], "g_start": 165893, "g_count": 513, "fj": ["FJ3345"], "centroid": [-0.019852297575342907, -0.22419818969330704, -0.047865282781472236], "bbox": [[-0.1508304553236805, -0.2547797160625298, -0.1354910070778445], [0.22447604534997975, -0.15519097236522386, 0.06177081433454771]]}, {"row": 120, "fma": "FMA7987", "name": "left first rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 1], "rgb": [198, 197, 131], "g_start": 166406, "g_count": 547, "fj": ["FJ3228"], "centroid": [0.20352596975244663, 0.03437397135774797, 0.43537072671241933], "bbox": [[0.14030700077073785, -0.060219595568551505, 0.3528626145075221], [0.2686836856566275, 0.09500371248536482, 0.494866650585114]]}, {"row": 121, "fma": "FMA8005", "name": "left first costal cartilage", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 2], "rgb": [178, 131, 198], "g_start": 166953, "g_count": 140, "fj": ["FJ3239"], "centroid": [0.20159231918128642, -0.06687930850442396, 0.35291237206550186], "bbox": [[0.15370913177263823, -0.10806417716380239, 0.32203310054304685], [0.2398006671883366, -0.04122061341319195, 0.37682020627533597]]}, {"row": 122, "fma": "FMA8012", "name": "left second rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 3], "rgb": [131, 198, 158], "g_start": 167093, "g_count": 954, "fj": ["FJ3229"], "centroid": [0.23276521244554316, 0.03313070270552828, 0.3937889213393861], "bbox": [[0.14252601975677634, -0.14660577641542183, 0.26686945112874866], [0.3329575741173287, 0.1275184947666312, 0.4680849812022335]]}, {"row": 123, "fma": "FMA8031", "name": "left second costal cartilage", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 4], "rgb": [198, 138, 131], "g_start": 168047, "g_count": 110, "fj": ["FJ3242"], "centroid": [0.170701247354433, -0.15071301220504296, 0.2810655758310304], "bbox": [[0.13210164326016227, -0.17277085551901253, 0.26025640271346817], [0.22050092076697242, -0.1245332564556649, 0.30094665435055057]]}, {"row": 124, "fma": "FMA8039", "name": "left third rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 5], "rgb": [131, 143, 198], "g_start": 168157, "g_count": 1213, "fj": ["FJ3230"], "centroid": [0.24812440779748626, 0.044824211029257904, 0.33514763893525523], "bbox": [[0.13777450916942702, -0.17513131372560553, 0.1971147340366075], [0.3609277094965494, 0.1599278448169351, 0.4138156230327066]]}, {"row": 125, "fma": "FMA8058", "name": "left third costal cartilage", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 6], "rgb": [163, 198, 131], "g_start": 169370, "g_count": 110, "fj": ["FJ3245"], "centroid": [0.1773439443057663, -0.18158276927553302, 0.21616591883879077], "bbox": [[0.13930468855719053, -0.20042328216653824, 0.19400824866003402], [0.22692781539945991, -0.157767943188972, 0.2350044420387489]]}, {"row": 126, "fma": "FMA8093", "name": "left fifth rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 7], "rgb": [198, 131, 183], "g_start": 169480, "g_count": 1638, "fj": ["FJ3232"], "centroid": [0.2824299022694, 0.06895205811444854, 0.2000416111802441], "bbox": [[0.140811804644431, -0.21845737113675004, 0.028352562556261222], [0.4037383727429443, 0.21676899633458263, 0.30873640177210876]]}, {"row": 127, "fma": "FMA8112", "name": "left fifth costal cartilage", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 8], "rgb": [131, 198, 194], "g_start": 171118, "g_count": 198, "fj": ["FJ3251"], "centroid": [0.22535246622145852, -0.22142129764583532, 0.0704440368786979], "bbox": [[0.1495436172904152, -0.2451896191613666, 0.027011125689104274], [0.30088687804103154, -0.19884650549812607, 0.1295486770961425]]}, {"row": 128, "fma": "FMA8148", "name": "left fourth rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 9], "rgb": [198, 175, 131], "g_start": 171316, "g_count": 1482, "fj": ["FJ3231"], "centroid": [0.2677318338218026, 0.04231314391766478, 0.26535200168688805], "bbox": [[0.13820141556890456, -0.20560075779416004, 0.12004094912541886], [0.3813952120117435, 0.19213080186153786, 0.36528855601381444]]}, {"row": 129, "fma": "FMA8167", "name": "left fourth costal cartilage", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 10], "rgb": [155, 131, 198], "g_start": 172798, "g_count": 124, "fj": ["FJ3248"], "centroid": [0.19121377831028677, -0.20483320841977481, 0.14865883832857896], "bbox": [[0.14148675919443188, -0.22035185653685715, 0.11989974524466514], [0.248507769155189, -0.18708186883336175, 0.1775344625721464]]}, {"row": 130, "fma": "FMA8202", "name": "left sixth rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 11], "rgb": [131, 198, 135], "g_start": 172922, "g_count": 1724, "fj": ["FJ3233"], "centroid": [0.30250458308564526, 0.07290182983111362, 0.11905087021328029], "bbox": [[0.1378947678078686, -0.20866017521048205, -0.052227785393634964], [0.42079109474192056, 0.23807204928015444, 0.2511016844446275]]}, {"row": 131, "fma": "FMA8221", "name": "left sixth costal cartilage", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 12], "rgb": [198, 131, 146], "g_start": 174646, "g_count": 272, "fj": ["FJ3254"], "centroid": [0.23431650832566484, -0.22689568736353322, 0.00726845245738029], "bbox": [[0.1404524407679138, -0.25230864814934667, -0.052769066936522745], [0.3264727858937323, -0.18907284355198362, 0.08732871675089889]]}, {"row": 132, "fma": "FMA8256", "name": "left seventh rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 13], "rgb": [131, 166, 198], "g_start": 174918, "g_count": 1685, "fj": ["FJ3234"], "centroid": [0.29461515194806837, 0.09735551793882, 0.05845384997845382], "bbox": [[0.1369701177287356, -0.17737645542958339, -0.12930157030482362], [0.4273264810227868, 0.23609691293015708, 0.18850129731065463]]}, {"row": 133, "fma": "FMA8275", "name": "left seventh costal cartilage", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 14], "rgb": [185, 198, 131], "g_start": 176603, "g_count": 456, "fj": ["FJ3255"], "centroid": [0.2342974209441483, -0.22404976218809855, -0.04866981918781124], "bbox": [[0.11566353468614497, -0.25500093547571, -0.13518506533621205], [0.3630716550859873, -0.15549456070884346, 0.06179434831467324]]}, {"row": 134, "fma": "FMA8310", "name": "left eighth rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 15], "rgb": [192, 131, 198], "g_start": 177059, "g_count": 1404, "fj": ["FJ3235"], "centroid": [0.29309921951164103, 0.10390062667938381, -0.017028661689095632], "bbox": [[0.1370028299611101, -0.13611668147346245, -0.2011743456082648], [0.41762577441503357, 0.2358971565068514, 0.12034689086705078]]}, {"row": 135, "fma": "FMA8391", "name": "left ninth rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 16], "rgb": [131, 198, 172], "g_start": 178463, "g_count": 1269, "fj": ["FJ3236"], "centroid": [0.2850743298461552, 0.12909325457851004, -0.07771671785562317], "bbox": [[0.1421699506374767, -0.07239372348750048, -0.2588561308959971], [0.408466349350168, 0.22883272635276264, 0.05929974642136413]]}, {"row": 136, "fma": "FMA8472", "name": "left tenth rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 17], "rgb": [198, 152, 131], "g_start": 179732, "g_count": 1140, "fj": ["FJ3225"], "centroid": [0.27023867687834946, 0.1333068986869381, -0.14206450189144046], "bbox": [[0.14447227991315964, -0.030319673819035452, -0.3226332170362482], [0.39562385639565334, 0.2199889154953609, -0.002688757229344349]]}, {"row": 137, "fma": "FMA8532", "name": "left eleventh rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 18], "rgb": [132, 131, 198], "g_start": 180872, "g_count": 812, "fj": ["FJ3226"], "centroid": [0.25643055283319144, 0.1300751350718588, -0.2098630794775256], "bbox": [[0.14625709696588163, 0.020756829266857693, -0.3578871192643278], [0.3668064977319127, 0.20436046997358315, -0.09039990115728327]]}, {"row": 138, "fma": "FMA8534", "name": "left twelfth rib", "depth": 7, "parent": 84, "tiers": [2, 2, 2, 2, 3, 1, 1, 2, 19], "rgb": [149, 198, 131], "g_start": 181684, "g_count": 471, "fj": ["FJ3227"], "centroid": [0.22389717189637562, 0.13161607149493257, -0.24919430781973817], "bbox": [[0.1478489353815741, 0.0912220372189896, -0.35007383786264384], [0.30835067983785086, 0.18077848052857323, -0.16702654044608628]]}, {"row": 139, "fma": "FMA7486", "name": "manubrium", "depth": 7, "parent": 102, "tiers": [2, 2, 2, 2, 3, 5, 1, 1, 1], "rgb": [198, 131, 169], "g_start": 182155, "g_count": 482, "fj": ["FJ3290"], "centroid": [0.10795033721679001, -0.11661535625892906, 0.3265136871699799], "bbox": [[0.04322909741302724, -0.173578071037319, 0.28284902363399955], [0.17227532403348886, -0.06125273729606336, 0.3883989244971086]]}, {"row": 140, "fma": "FMA7487", "name": "body of sternum", "depth": 7, "parent": 102, "tiers": [2, 2, 2, 2, 3, 5, 1, 1, 2], "rgb": [131, 188, 198], "g_start": 182637, "g_count": 1231, "fj": ["FJ3178"], "centroid": [0.10982416365785949, -0.20924799515127346, 0.15017381139551952], "bbox": [[0.05225390811157461, -0.2565165237957957, 0.045932445710049966], [0.16420622826784026, -0.14199076291280072, 0.3047826931110161]]}, {"row": 141, "fma": "FMA7488", "name": "xiphoid process", "depth": 7, "parent": 102, "tiers": [2, 2, 2, 2, 3, 5, 1, 1, 3], "rgb": [198, 189, 131], "g_start": 183868, "g_count": 165, "fj": ["FJ3153"], "centroid": [0.10797700728715433, -0.23954883791167297, 0.04033207159108084], "bbox": [[0.08350020886407362, -0.2553939529438068, 0.009195902734060206], [0.13271446810263168, -0.22069074585066514, 0.0566168726870513]]}, {"row": 142, "fma": "FMA13336", "name": "right external oblique", "depth": 7, "parent": 106, "tiers": [2, 2, 3, 2, 1, 1, 1, 1, 1], "rgb": [169, 131, 198], "g_start": 184033, "g_count": 21303, "fj": ["FJ1452"], "centroid": [-0.0391725066066287, -0.15675069948639986, -0.3563221855911362], "bbox": [[-0.22348926556331522, -0.2679893391070032, -0.8625356686886277], [0.0997132855201304, 0.15926418657739447, 0.12107644425094283]]}, {"row": 143, "fma": "FMA13337", "name": "left external oblique", "depth": 7, "parent": 106, "tiers": [2, 2, 3, 2, 1, 1, 1, 1, 2], "rgb": [131, 198, 149], "g_start": 205336, "g_count": 21298, "fj": ["FJ1452M"], "centroid": [0.2548252333989089, -0.15682180112072763, -0.3563581713386508], "bbox": [[0.11594502462242673, -0.2679893391070032, -0.8625380220866403], [0.43914524584183995, 0.15916628522007217, 0.12107644425094283]]}, {"row": 144, "fma": "FMA7097", "name": "left atrium", "depth": 8, "parent": 109, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 1], "rgb": [198, 131, 132], "g_start": 226634, "g_count": 196, "fj": ["FJ2425"], "centroid": [0.15173547533776968, 0.028166487300115804, 0.19648532013957587], "bbox": [[0.05985608971153225, -0.051608512240611394, 0.109003512446534], [0.22063882989050818, 0.07961037142504136, 0.2545141115628329]]}, {"row": 145, "fma": "FMA7101", "name": "left ventricle", "depth": 8, "parent": 109, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2], "rgb": [131, 152, 198], "g_start": 226830, "g_count": 293, "fj": ["FJ2422"], "centroid": [0.1914220888210562, -0.03486986124650456, 0.14558085969348292], "bbox": [[0.12398597374784519, -0.12635478651738277, 0.05633446492554438], [0.2731466696476375, 0.0431251713567928, 0.21467108321027017]]}, {"row": 146, "fma": "FMA73704", "name": "wall of left side of heart", "depth": 8, "parent": 109, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3], "rgb": [172, 198, 131], "g_start": 227123, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 147, "fma": "FMA9551", "name": "outflow part of left atrium", "depth": 9, "parent": 144, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1], "rgb": [198, 131, 191], "g_start": 227123, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 148, "fma": "FMA9473", "name": "outflow part of left ventricle", "depth": 9, "parent": 145, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1], "rgb": [131, 198, 186], "g_start": 227123, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 149, "fma": "FMA9564", "name": "inflow part of left ventricle", "depth": 9, "parent": 145, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2], "rgb": [198, 166, 131], "g_start": 227123, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 150, "fma": "FMA9531", "name": "wall of left atrium", "depth": 9, "parent": 146, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 1], "rgb": [146, 131, 198], "g_start": 227123, "g_count": 1428, "fj": ["FJ2438"], "centroid": [0.15896136549756018, 0.01588171600751825, 0.18549226041060954], "bbox": [[0.05421734807344956, -0.10861957909476543, 0.0924826583983953], [0.256327640071308, 0.08116455547253293, 0.2641865773944358]]}, {"row": 151, "fma": "FMA9556", "name": "wall of left ventricle", "depth": 9, "parent": 146, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2], "rgb": [135, 198, 131], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 152, "fma": "FMA7235", "name": "mitral valve", "depth": 10, "parent": 147, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1], "rgb": [198, 131, 155], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 153, "fma": "FMA7236", "name": "aortic valve", "depth": 10, "parent": 148, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1], "rgb": [131, 174, 198], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 154, "fma": "FMA9348", "name": "subaortic curtain of left ventricle", "depth": 10, "parent": 148, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2], "rgb": [194, 198, 131], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 155, "fma": "FMA49214", "name": "wall of inflow part of left ventricle", "depth": 10, "parent": 151, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 1], "rgb": [183, 131, 198], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 156, "fma": "FMA84850", "name": "free wall of left ventricle", "depth": 10, "parent": 151, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 2], "rgb": [131, 198, 163], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 157, "fma": "FMA9558", "name": "myocardium of left ventricle", "depth": 10, "parent": 151, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 3], "rgb": [198, 143, 131], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 158, "fma": "FMA9560", "name": "anterior wall of left ventricle", "depth": 10, "parent": 151, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 4], "rgb": [131, 138, 198], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 159, "fma": "FMA9561", "name": "inferior wall of left ventricle", "depth": 10, "parent": 151, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 5], "rgb": [158, 198, 131], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 160, "fma": "FMA9563", "name": "lateral wall of left ventricle", "depth": 10, "parent": 151, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 6], "rgb": [198, 131, 177], "g_start": 228551, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 161, "fma": "FMA7242", "name": "anterior leaflet of mitral valve", "depth": 11, "parent": 152, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1], "rgb": [131, 197, 198], "g_start": 228551, "g_count": 1351, "fj": ["FJ2420"], "centroid": [0.17762002470310184, -0.019064633877180936, 0.1377219709088217], "bbox": [[0.13542911271011432, -0.08653058534892065, 0.10446145428230198], [0.21582165949860857, 0.027604040784387586, 0.17835815187654108]]}, {"row": 162, "fma": "FMA7243", "name": "posterior leaflet of mitral valve", "depth": 11, "parent": 152, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 2], "rgb": [198, 180, 131], "g_start": 229902, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 163, "fma": "FMA9498", "name": "fibrous ring of mitral valve", "depth": 11, "parent": 152, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 3], "rgb": [160, 131, 198], "g_start": 229902, "g_count": 248, "fj": ["FJ2426", "FJ2431"], "centroid": [0.16064394483027725, -0.025832085431384495, 0.203737271960003], "bbox": [[0.12116761488994925, -0.051088411279836675, 0.17278059858678455], [0.18374884536410013, -0.0010763501150223144, 0.22344925779710179]]}, {"row": 164, "fma": "FMA7252", "name": "right posterior cusp of aortic valve", "depth": 11, "parent": 153, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1], "rgb": [131, 198, 141], "g_start": 230150, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 165, "fma": "FMA7253", "name": "anterior cusp of aortic valve", "depth": 11, "parent": 153, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2], "rgb": [198, 131, 141], "g_start": 230150, "g_count": 170, "fj": ["FJ2435"], "centroid": [0.15083969241087974, -0.05119468796538012, 0.1952572108288151], "bbox": [[0.12428469055757885, -0.06483931586719777, 0.17548700630122346], [0.17056181494054728, -0.033800349479604856, 0.21780110256696922]]}, {"row": 166, "fma": "FMA7254", "name": "left posterior cusp of aortic valve", "depth": 11, "parent": 153, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 3], "rgb": [131, 160, 198], "g_start": 230320, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 167, "fma": "FMA83448", "name": "myocardium of left ventricle proper", "depth": 11, "parent": 157, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 3, 1], "rgb": [180, 198, 131], "g_start": 230320, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 168, "fma": "FMA87179", "name": "myocardium of inferior wall of left ventricle", "depth": 11, "parent": 159, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 5, 1], "rgb": [197, 131, 198], "g_start": 230320, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 169, "fma": "FMA7265", "name": "anterolateral head of lateral papillary muscle of left ventricle", "depth": 11, "parent": 160, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 6, 1], "rgb": [131, 198, 177], "g_start": 230320, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 170, "fma": "FMA87178", "name": "myocardium of lateral wall of left ventricle", "depth": 11, "parent": 160, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 6, 2], "rgb": [198, 157, 131], "g_start": 230320, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 171, "fma": "FMA84932", "name": "myocardium of free wall of left ventricle", "depth": 12, "parent": 167, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 3, 1, 1], "rgb": [138, 131, 198], "g_start": 230320, "g_count": 854, "fj": ["FJ2432"], "centroid": [0.19760776292860496, 0.003227842616480373, 0.12454743074592435], "bbox": [[0.13998905669924164, -0.0432704230821277, 0.09300040596115754], [0.25573317173333654, 0.045625421405331656, 0.16807380256167379]]}, {"row": 172, "fma": "FMA86056", "name": "myocardial zone 4", "depth": 12, "parent": 168, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 5, 1, 1], "rgb": [144, 198, 131], "g_start": 231174, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 173, "fma": "FMA86063", "name": "myocardial zone 11", "depth": 12, "parent": 170, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 6, 2, 1], "rgb": [198, 131, 163], "g_start": 231174, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 174, "fma": "FMA86064", "name": "myocardial zone 12", "depth": 12, "parent": 170, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 6, 2, 2], "rgb": [131, 183, 198], "g_start": 231174, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 175, "fma": "FMA84857", "name": "subendocardial layer of myocardium of left ventricle", "depth": 13, "parent": 171, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 3, 1, 1, 1], "rgb": [198, 194, 131], "g_start": 231174, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 176, "fma": "FMA7264", "name": "lateral papillary muscle of left ventricle", "depth": 13, "parent": 173, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 6, 2, 1, 1], "rgb": [174, 131, 198], "g_start": 231174, "g_count": 0, "fj": [], "centroid": null, "bbox": null}, {"row": 177, "fma": "FMA9352", "name": "papillary muscle of left ventricle", "depth": 14, "parent": 175, "tiers": [2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 2, 3, 1, 1, 1, 1], "rgb": [131, 198, 155], "g_start": 231174, "g_count": 341, "fj": ["FJ2418", "FJ2429"], "centroid": [0.23348574323043947, -0.07200597183372506, 0.10447215154599546], "bbox": [[0.1823553984008661, -0.12984252237198984, 0.06843093071007926], [0.28172386404419686, -0.00045034624368257104, 0.15145881259303295]]}]} \ No newline at end of file diff --git a/cockpit/public/torso.splat b/cockpit/public/torso.splat index 2c7136a06..519babe1d 100644 Binary files a/cockpit/public/torso.splat and b/cockpit/public/torso.splat differ diff --git a/cockpit/src/TorsoMap.tsx b/cockpit/src/TorsoMap.tsx new file mode 100644 index 000000000..55b6c0a58 --- /dev/null +++ b/cockpit/src/TorsoMap.tsx @@ -0,0 +1,272 @@ +// FMA torso · map view — the splat AS the GUID substrate. +// +// Renders the same torso.splat (SPL2: real BodyParts3D geometry, per-vertex +// normal, per-gaussian node-row tag) but treats it as the value-tenant SoA it +// is: click a gaussian -> its node row -> O(1) into torso.nodes.json (the node +// SoA) -> the FMA structure's identity (concept id, name, partonomy path, +// gaussian range). Click a structure in the list -> its gaussians highlight. +// Geometry, graph, and splat are three tenants of one identity, switch-selected. +// +// Geometry: BodyParts3D, (c) The Database Center for Life Science (CC-BY 4.0 / +// CC-BY-SA 2.1 JP). Attribution shown in-view. +import { useEffect, useMemo, useRef, useState } from 'react'; +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +interface NodeRow { + row: number; + fma: string; + name: string; + depth: number; + parent: number | null; + tiers: number[]; + rgb: [number, number, number]; + g_start: number; + g_count: number; + centroid: [number, number, number] | null; +} +interface NodesDoc { attribution: string; root: string; nodes: NodeRow[] } + +interface Spl2 { + count: number; + positions: Float32Array; + colors: Float32Array; // 0..1 rgb + rows: Float32Array; // node_row per gaussian +} + +function decodeSpl2(buf: ArrayBuffer): Spl2 { + const dv = new DataView(buf); + const magic = String.fromCharCode(dv.getUint8(0), dv.getUint8(1), dv.getUint8(2), dv.getUint8(3)); + if (magic !== 'SPL2') throw new Error(`bad magic "${magic}" (expected SPL2)`); + const count = dv.getUint32(4, true); + const off = 40; + const positions = new Float32Array(count * 3); + const colors = new Float32Array(count * 3); + const rows = new Float32Array(count); + for (let i = 0; i < count; i++) { + const b = off + i * 21; + // upright: (x,y,z) -> (x,z,-y) + positions[i * 3] = dv.getFloat32(b, true); + positions[i * 3 + 1] = dv.getFloat32(b + 8, true); + positions[i * 3 + 2] = -dv.getFloat32(b + 4, true); + colors[i * 3] = dv.getUint8(b + 15) / 255; + colors[i * 3 + 1] = dv.getUint8(b + 16) / 255; + colors[i * 3 + 2] = dv.getUint8(b + 17) / 255; + rows[i] = dv.getUint16(b + 19, true); + } + return { count, positions, colors, rows }; +} + +const VERT = ` +attribute vec3 aColor; +attribute float aRow; +uniform float uSelected; +uniform float uSize; +varying vec3 vColor; +varying float vDim; +void main() { + vColor = aColor; + vDim = (uSelected < 0.0 || abs(aRow - uSelected) < 0.5) ? 1.0 : 0.16; + vec4 mv = modelViewMatrix * vec4(position, 1.0); + gl_Position = projectionMatrix * mv; + gl_PointSize = uSize * (1.0 / -mv.z); +}`; +const FRAG = ` +precision mediump float; +varying vec3 vColor; +varying float vDim; +void main() { + vec2 c = gl_PointCoord - 0.5; + if (dot(c, c) > 0.25) discard; + float a = smoothstep(0.25, 0.05, dot(c, c)); + gl_FragColor = vec4(vColor * vDim, a); +}`; + +function mount( + container: HTMLDivElement, + splat: Spl2, + onPick: (row: number) => void, + apiRef: { current: { select: (row: number) => void } | null }, +): () => void { + let w = container.clientWidth || window.innerWidth; + let h = container.clientHeight || window.innerHeight; + const scene = new THREE.Scene(); + scene.background = new THREE.Color(0x0a0e17); + const camera = new THREE.PerspectiveCamera(45, w / h, 0.01, 100); + camera.position.set(0, 0.05, 3.0); + const renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize(w, h); + renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); + container.appendChild(renderer.domElement); + + const geom = new THREE.BufferGeometry(); + geom.setAttribute('position', new THREE.BufferAttribute(splat.positions, 3)); + geom.setAttribute('aColor', new THREE.BufferAttribute(splat.colors, 3)); + geom.setAttribute('aRow', new THREE.BufferAttribute(splat.rows, 1)); + const mat = new THREE.ShaderMaterial({ + vertexShader: VERT, + fragmentShader: FRAG, + uniforms: { uSelected: { value: -1 }, uSize: { value: 4.2 } }, + transparent: true, + depthWrite: true, + }); + const points = new THREE.Points(geom, mat); + scene.add(points); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.enableDamping = true; + controls.dampingFactor = 0.08; + controls.target.set(0, 0, 0); + controls.minDistance = 0.6; + controls.maxDistance = 12; + + const ray = new THREE.Raycaster(); + ray.params.Points = { threshold: 0.02 }; + const ndc = new THREE.Vector2(); + let downAt = { x: 0, y: 0 }; + renderer.domElement.addEventListener('pointerdown', (e) => { downAt = { x: e.clientX, y: e.clientY }; }); + renderer.domElement.addEventListener('pointerup', (e) => { + if (Math.hypot(e.clientX - downAt.x, e.clientY - downAt.y) > 5) return; // drag, not click + const r = renderer.domElement.getBoundingClientRect(); + ndc.x = ((e.clientX - r.left) / r.width) * 2 - 1; + ndc.y = -((e.clientY - r.top) / r.height) * 2 + 1; + ray.setFromCamera(ndc, camera); + const hit = ray.intersectObject(points, false); + if (hit.length && hit[0].index != null) onPick(splat.rows[hit[0].index]); + }); + + apiRef.current = { select: (row: number) => { mat.uniforms.uSelected.value = row; } }; + + let raf = 0; + const tick = () => { raf = requestAnimationFrame(tick); controls.update(); renderer.render(scene, camera); }; + tick(); + const onResize = () => { + w = container.clientWidth || window.innerWidth; h = container.clientHeight || window.innerHeight; + camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setSize(w, h); + }; + const ro = new ResizeObserver(onResize); ro.observe(container); + return () => { + cancelAnimationFrame(raf); ro.disconnect(); controls.dispose(); + geom.dispose(); mat.dispose(); renderer.dispose(); + if (renderer.domElement.parentNode === container) container.removeChild(renderer.domElement); + }; +} + +export function TorsoMap() { + const ref = useRef(null); + const apiRef = useRef<{ select: (row: number) => void } | null>(null); + const [splat, setSplat] = useState(null); + const [doc, setDoc] = useState(null); + const [sel, setSel] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + let cancelled = false; + fetch('/torso.splat') + .then((r) => { if (!r.ok) throw new Error(`HTTP ${r.status} torso.splat`); return r.arrayBuffer(); }) + .then((b) => !cancelled && setSplat(decodeSpl2(b))) + .catch((e) => !cancelled && setError(String(e))); + fetch('/torso.nodes.json') + .then((r) => (r.ok ? r.json() : null)) + .then((d) => !cancelled && d && setDoc(d as NodesDoc)) + .catch(() => {}); + return () => { cancelled = true; }; + }, []); + + useEffect(() => { + const c = ref.current; + if (!c || !splat) return; + return mount(c, splat, (row) => setSel(row), apiRef); + }, [splat]); + + useEffect(() => { apiRef.current?.select(sel ?? -1); }, [sel]); + + // the "switch": row -> node, built once (O(1) lookup) + const byRow = useMemo(() => { + const m = new Map(); + doc?.nodes.forEach((n) => m.set(n.row, n)); + return m; + }, [doc]); + + // partonomy breadcrumb (walk parent links) for the selected node + const path = useMemo(() => { + if (sel == null) return []; + const out: NodeRow[] = []; + let cur: number | null = sel; + for (let i = 0; i < 24 && cur != null; i++) { + const n = byRow.get(cur); + if (!n) break; + out.push(n); + cur = n.parent; + } + return out.reverse(); + }, [sel, byRow]); + + const owners = useMemo( + () => (doc?.nodes ?? []).filter((n) => n.g_count > 0).sort((a, b) => b.g_count - a.g_count), + [doc], + ); + + const selNode = sel != null ? byRow.get(sel) : undefined; + const css = (rgb: [number, number, number]) => `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`; + + return ( +
+
+ +
+
FMA torso · map
+
+ click a structure — splat ↔ FMA, one node at one address + {doc ? ` · ${owners.length} structures` : ''} +
+
+ + {error && ( +
{error}
+ )} + + {/* selected structure + partonomy path */} + {selNode && ( +
+
+ + {selNode.name} +
+
+ {selNode.fma} · {selNode.g_count.toLocaleString()} gaussians · depth {selNode.depth} +
+
HHTL tiers [{selNode.tiers.join(', ')}]
+
+ {path.map((n, i) => ( +
setSel(n.row)}> + {i > 0 ? '└ ' : ''}{n.name} +
+ ))} +
+
+ )} + + {/* structure list (graph -> splat) */} +
+ {owners.map((n) => ( +
setSel(n.row)} + style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '2px 4px', borderRadius: 3, cursor: 'pointer', background: n.row === sel ? '#1d2b40' : 'transparent', color: n.row === sel ? '#fff' : '#9fb2c9' }} + > + + {n.name} +
+ ))} +
+ + +
+ {doc?.attribution ?? 'BodyParts3D, (c) The Database Center for Life Science (CC-BY 4.0 / CC-BY-SA 2.1 JP)'} +
+
+ ); +} diff --git a/cockpit/src/TorsoSplat.tsx b/cockpit/src/TorsoSplat.tsx index 45faf4ce0..0829b367d 100644 --- a/cockpit/src/TorsoSplat.tsx +++ b/cockpit/src/TorsoSplat.tsx @@ -27,32 +27,36 @@ interface Spl1 { colors: Uint8Array; } -// Decode the SPL1 wire (mirrors bake_torso_splat.py): little-endian -// header 36 B: magic "SPL1" | count u32 | radius f32 | bbox_min 3f | bbox_max 3f -// body count x 16 B: pos 3f (12) | rgb 3u8 (3) | opacity u8 (1) +// Decode the SPL2 wire (mirrors bake_torso_splat.py): little-endian +// header 40 B: magic "SPL2" | count u32 | node_count u32 | radius f32 +// | bbox_min 3f | bbox_max 3f +// body count x 21 B: pos 3f (12) | normal 3i8 (3) | rgb 3u8 (3) | opacity u8 (1) +// | node_row u16 (2) +// The live-orbit view renders points: it reads pos + rgb and ignores the normal +// and node-row tags (those drive the /torso splat3d render and the /torso-map view). function decodeSpl1(buf: ArrayBuffer): Spl1 { const dv = new DataView(buf); const magic = String.fromCharCode(dv.getUint8(0), dv.getUint8(1), dv.getUint8(2), dv.getUint8(3)); - if (magic !== 'SPL1') throw new Error(`bad magic "${magic}" (expected SPL1)`); + if (magic !== 'SPL2') throw new Error(`bad magic "${magic}" (expected SPL2)`); const count = dv.getUint32(4, true); - const radius = dv.getFloat32(8, true); + const radius = dv.getFloat32(12, true); const bboxMin: [number, number, number] = [ - dv.getFloat32(12, true), dv.getFloat32(16, true), dv.getFloat32(20, true), + dv.getFloat32(16, true), dv.getFloat32(20, true), dv.getFloat32(24, true), ]; const bboxMax: [number, number, number] = [ - dv.getFloat32(24, true), dv.getFloat32(28, true), dv.getFloat32(32, true), + dv.getFloat32(28, true), dv.getFloat32(32, true), dv.getFloat32(36, true), ]; - const off = 36; + const off = 40; const positions = new Float32Array(count * 3); const colors = new Uint8Array(count * 3); for (let i = 0; i < count; i++) { - const b = off + i * 16; + const b = off + i * 21; positions[i * 3] = dv.getFloat32(b, true); positions[i * 3 + 1] = dv.getFloat32(b + 4, true); positions[i * 3 + 2] = dv.getFloat32(b + 8, true); - colors[i * 3] = dv.getUint8(b + 12); - colors[i * 3 + 1] = dv.getUint8(b + 13); - colors[i * 3 + 2] = dv.getUint8(b + 14); + colors[i * 3] = dv.getUint8(b + 15); + colors[i * 3 + 1] = dv.getUint8(b + 16); + colors[i * 3 + 2] = dv.getUint8(b + 17); } return { count, radius, bboxMin, bboxMax, positions, colors }; } diff --git a/cockpit/src/main.tsx b/cockpit/src/main.tsx index 830e8c217..0b11700b2 100644 --- a/cockpit/src/main.tsx +++ b/cockpit/src/main.tsx @@ -10,6 +10,7 @@ import { OsintGraph } from './OsintGraph'; import { FmaGraph } from './FmaGraph'; import { TorsoSplat } from './TorsoSplat'; import { TorsoRender } from './TorsoRender'; +import { TorsoMap } from './TorsoMap'; import { ReasoningPage } from './ReasoningPage'; import { ErrorBoundary } from './components/ErrorBoundary'; import './styles/cockpit.css'; @@ -85,6 +86,9 @@ createRoot(document.getElementById('root')!).render( /torso = splat3d CPU render (turntable), /torso-live = three.js orbit */} } /> } /> + {/* FMA torso map — splat AS the GUID/value-tenant SoA: click a gaussian → its + FMA node (O(1) switch into the node SoA) → label + partonomy ↔ graph */} + } /> {/* The Palantir JSON-graph cockpit (221 aiwar nodes) stays reachable at /palantir and as the catch-all for its own sub-routes. */} } /> diff --git a/crates/osint-bake/tools/bake_torso_splat.py b/crates/osint-bake/tools/bake_torso_splat.py index 22b9f0dee..eb8dd7726 100644 --- a/crates/osint-bake/tools/bake_torso_splat.py +++ b/crates/osint-bake/tools/bake_torso_splat.py @@ -1,33 +1,37 @@ #!/usr/bin/env python3 -"""Bake a REAL-anatomy gaussian-splat asset for the cockpit /torso pages from -BodyParts3D (the FMA-keyed 3D mesh database). - -FMA itself has zero geometry (it is a symbolic ontology). BodyParts3D (DBCLS) -realises FMA concepts as OBJ meshes in one shared whole-body coordinate frame and -keys each concept on its FMA id — so a torso splat needs no synthesized -positions: we read the real vertices. The FMA `part_of` tree (which IS the -mereotopological containment of those meshes, per BodyParts3D NAR 2009 Table 1) -selects the torso subtree and colours it. - -Inputs (BodyParts3D 4.0, external — NOT committed; download once): - partof_inclusion_relation_list.txt FMA part-of tree (parent_id name child_id name) - partof_element_parts.txt FMA concept -> FJ element OBJ files - partof_parts_list_e.txt FMA concept -> English name - partof_BP3D_4.0_obj_99/FJ####.obj the meshes (decimated 99%, shared frame) - https://dbarchive.biosciencedbc.jp/data/bodyparts3d/LATEST/ - -Output: cockpit/public/torso.splat (SPL1 binary) + cockpit/public/torso.manifest.json - -LICENSE / ATTRIBUTION (required, CC-BY 4.0): - "BodyParts3D, (c) The Database Center for Life Science - licensed under CC Attribution 4.0 International" - -SPL1 binary layout (little-endian), the cockpit decoder mirrors this: - header 36 B: magic "SPL1"(4) | count u32 | radius f32 | bbox_min 3xf32 | bbox_max 3xf32 - body count x 16 B: pos 3xf32 (12) | r,g,b u8 (3) | opacity u8 (1) -positions are in the NORMALIZED frame (centroid at origin, max half-extent = 1.0). - -Usage: python3 bake_torso_splat.py [root_fma] [budget] +"""Bake the REAL-anatomy torso gaussian splat from BodyParts3D — v2: anisotropic +(surface normals) + per-node SoA with O(1) tenant tags. + +v1 emitted flat points (pos+rgb). v2 adds, in one pass over the meshes: + - the per-vertex SURFACE NORMAL (BodyParts3D OBJ ships `vn`) -> orientation, so + consumers can render oriented surface-tangent gaussians ("connect the dots") + instead of isotropic blobs; + - a per-gaussian NODE-ROW tag + a NODE SoA (one row per FMA structure) carrying + the value-tenants of that node's identity: fma id, name, partonomy depth + + HHTL tier-ranks, colour, the gaussian RANGE (start+count), and the OBJ-geometry + summary (centroid + bbox + FJ mesh handles). A consumer builds the "switch" + (identity -> row hashtable) once and reads any tenant in O(1). Geometry, graph, + and splat become three tenants of one identity. + +Source: BodyParts3D 4.0 (DBCLS), FMA-keyed OBJ meshes in one shared whole-body +frame. concept id == FMA id. Pairwise inputs (the user-supplied text files): + partof_inclusion_relation_list.txt FMA parent<->child (the partonomy / HHTL cascade) + partof_element_parts.txt FMA concept<->FJ mesh (geometry binding) + partof_parts_list_e.txt FMA<->repr-id<->name (labels) + partof_BP3D_4.0_obj_99/FJ####.obj meshes (v + vn, shared frame) + +LICENCE / ATTRIBUTION (required): BodyParts3D, (c) The Database Center for Life +Science. The 2013 OBJ files embed CC-BY-SA 2.1 JP; the current DBCLS site relicenses +to CC-BY 4.0 -- both are carried below to be safe. + +Outputs (cockpit/public/): + torso.splat SPL2 binary (hdr 40B: "SPL2"|count u32|node_count u32|radius f32| + bbox_min 3f|bbox_max 3f; body count*21B: + pos 3f|normal 3i8|rgb 3u8|opacity u8|node_row u16) + torso.nodes.json the node SoA (one row per FMA structure) + torso.manifest.json summary + attribution + +Usage: python3 bake_torso_splat.py [root_fma] [budget] """ import collections import colorsys @@ -37,9 +41,10 @@ import sys ROOT_DEFAULT = "FMA7181" # trunk (synonym: Torso) -BUDGET_DEFAULT = 250_000 # ~4 MB asset; downsample vertices to this many gaussians -ATTRIBUTION = ("BodyParts3D, (c) The Database Center for Life Science " - "licensed under CC Attribution 4.0 International") +BUDGET_DEFAULT = 250_000 +ATTRIBUTION = ("BodyParts3D, (c) The Database Center for Life Science. " + "Current site licence: CC-BY 4.0; 2013 mesh files embed " + "CC-BY-SA 2.1 Japan.") def load_tree(bp_dir): @@ -57,6 +62,8 @@ def load_tree(bp_dir): for line in f: cid, _nm, fj = line.rstrip("\n").split("\t") elems[cid].append(fj) + for v in children.values(): + v.sort() # deterministic sibling order -> stable tier ranks return parent, children, name, elems @@ -72,31 +79,38 @@ def bfs(root, children): return order, depth -def region_of(cid, root, parent): - """The depth-1 ancestor under `root` (thoracic/abdominal segment, body wall, - perineum) — the gross torso region the concept belongs to.""" - cur, prev = cid, cid - while cur in parent and cur != root: - prev, cur = cur, parent[cur] - return prev if cur == root else cid +def tier_ranks(node, parent, children): + """The sibling-rank chain root->node (the HHTL tier address / GUID content).""" + chain = [] + cur = node + while cur in parent: + sibs = children[parent[cur]] + chain.append(sibs.index(cur) + 1) # 1-based rank under parent + cur = parent[cur] + chain.reverse() + return chain -def read_obj_vertices(path): - out = [] +def read_obj_v_vn(path): + """Return parallel (positions, normals). BodyParts3D OBJ ships `vn`; faces are + `v//vn` with v_idx == vn_idx, so vertex i pairs with normal i.""" + vs, ns = [], [] with open(path, "rb") as f: for ln in f: if ln[:2] == b"v ": p = ln.split() - out.append((float(p[1]), float(p[2]), float(p[3]))) - return out + vs.append((float(p[1]), float(p[2]), float(p[3]))) + elif ln[:3] == b"vn ": + p = ln.split() + ns.append((float(p[1]), float(p[2]), float(p[3]))) + if len(ns) != len(vs): + ns = [(0.0, 0.0, 1.0)] * len(vs) # fallback: no usable normals + return vs, ns def concept_color(idx): - """Deterministic distinct hue per concept (golden-angle walk) so each - anatomical structure reads as its own colour — muted/pastel (low saturation) - so the splat is soft, not neon.""" h = (idx * 0.6180339887498949) % 1.0 - r, g, b = colorsys.hsv_to_rgb(h, 0.34, 0.78) + r, g, b = colorsys.hsv_to_rgb(h, 0.34, 0.78) # muted pastel per structure return (int(r * 255), int(g * 255), int(b * 255)) @@ -105,100 +119,123 @@ def main(bp_dir, obj_dir, out_path, root=ROOT_DEFAULT, budget=BUDGET_DEFAULT): if root not in children and root not in name: sys.exit(f"root {root} not in BodyParts3D part-of tree") order, depth = bfs(root, children) - - # gather (x,y,z, r,g,b) per vertex; colour each mesh by its DEEPEST owning - # concept. BodyParts3D `element_parts` lists every descendant element under a - # compound concept, so we claim meshes deepest-first — each structure (leaf) - # owns its own meshes and gets its own hue; the root only mops up unowned ones. - cidx = {cid: i for i, cid in enumerate(order)} # stable BFS index -> colour - pts = [] # list of (x,y,z,r,g,b) - seen_mesh = set() - regions = {} # region cid -> name - used_concepts = 0 - for cid in sorted(order, key=lambda c: -depth[c]): - fjs = elems.get(cid, []) - if not fjs: - continue - col = concept_color(cidx[cid]) - reg = region_of(cid, root, parent) - got = False - for fj in fjs: - if fj in seen_mesh: - continue - seen_mesh.add(fj) - p = os.path.join(obj_dir, fj + ".obj") - if not os.path.exists(p): - continue - for (x, y, z) in read_obj_vertices(p): - pts.append((x, y, z, col[0], col[1], col[2])) - got = True - if got: - used_concepts += 1 - regions.setdefault(reg, name.get(reg, reg)) - - if not pts: - sys.exit("no vertices gathered — check obj_dir / root") - - # deterministic downsample to the budget (uniform global stride). - stride = max(1, round(len(pts) / budget)) - sampled = pts[::stride] - - # recenter to centroid, normalize so max half-extent = 1.0. - xs = [p[0] for p in sampled]; ys = [p[1] for p in sampled]; zs = [p[2] for p in sampled] - cx, cy, cz = (min(xs) + max(xs)) / 2, (min(ys) + max(ys)) / 2, (min(zs) + max(zs)) / 2 - half = max(max(xs) - min(xs), max(ys) - min(ys), max(zs) - min(zs)) / 2 or 1.0 + row_of = {fma: i for i, fma in enumerate(order)} + + # claim each mesh to its DEEPEST owning concept (compound concepts list all + # descendant elements; deepest-first so leaves own their own meshes). + owner = {} + for fma in sorted(order, key=lambda c: -depth[c]): + for fj in elems.get(fma, []): + owner.setdefault(fj, fma) + meshes_of = collections.defaultdict(list) + for fj, fma in owner.items(): + meshes_of[fma].append(fj) + for v in meshes_of.values(): + v.sort() + + # pass 1: total vertex count -> global stride for the budget + total_v = 0 + vcache = {} + for fma in order: + for fj in meshes_of.get(fma, []): + vs, ns = read_obj_v_vn(os.path.join(obj_dir, fj + ".obj")) + vcache[fj] = (vs, ns) + total_v += len(vs) + stride = max(1, round(total_v / budget)) + + # pass 2: gather gaussians GROUPED by node (contiguous ranges) with the + # per-vertex normal; build node SoA rows. + gx, gy, gz, gnx, gny, gnz, gr, gg, gb, grow = ([] for _ in range(10)) + nodes = [] + for fma in order: + r = row_of[fma] + col = concept_color(r) + g_start = len(gx) + for fj in meshes_of.get(fma, []): + vs, ns = vcache[fj] + for k in range(0, len(vs), stride): + (x, y, z) = vs[k] + (nx, ny, nz) = ns[k] + gx.append(x); gy.append(y); gz.append(z) + gnx.append(nx); gny.append(ny); gnz.append(nz) + gr.append(col[0]); gg.append(col[1]); gb.append(col[2]) + grow.append(r) + g_count = len(gx) - g_start + nodes.append({ + "row": r, "fma": fma, "name": name.get(fma, fma), "depth": depth[fma], + "parent": row_of.get(parent.get(fma)) if fma in parent else None, + "tiers": tier_ranks(fma, parent, children), + "rgb": list(col), "g_start": g_start, "g_count": g_count, + "fj": meshes_of.get(fma, []), + }) + + if not gx: + sys.exit("no vertices gathered") + + # recenter to centroid, uniform-normalize so max half-extent = 1 (normals, + # being directions under a recenter + uniform scale, stay valid). + cx = (min(gx) + max(gx)) / 2; cy = (min(gy) + max(gy)) / 2; cz = (min(gz) + max(gz)) / 2 + half = max(max(gx) - min(gx), max(gy) - min(gy), max(gz) - min(gz)) / 2 or 1.0 inv = 1.0 / half + for i in range(len(gx)): + gx[i] = (gx[i] - cx) * inv; gy[i] = (gy[i] - cy) * inv; gz[i] = (gz[i] - cz) * inv + + # per-node centroid + bbox in the normalized frame (the OBJ-geometry tenant). + for nd in nodes: + s, c = nd["g_start"], nd["g_count"] + if c == 0: + nd["centroid"] = None; nd["bbox"] = None + continue + xs = gx[s:s + c]; ys = gy[s:s + c]; zs = gz[s:s + c] + nd["centroid"] = [sum(xs) / c, sum(ys) / c, sum(zs) / c] + nd["bbox"] = [[min(xs), min(ys), min(zs)], [max(xs), max(ys), max(zs)]] + + n = len(gx) + bmin = (min(gx), min(gy), min(gz)); bmax = (max(gx), max(gy), max(gz)) + radius = 0.0035 - gx = [(p[0] - cx) * inv for p in sampled] - gy = [(p[1] - cy) * inv for p in sampled] - gz = [(p[2] - cz) * inv for p in sampled] - bmin = (min(gx), min(gy), min(gz)) - bmax = (max(gx), max(gy), max(gz)) - radius = 0.0045 - opacity = 220 + def qi8(v): # normalize a normal component to a signed byte + return max(-127, min(127, int(round(v * 127)))) - n = len(sampled) buf = bytearray() - buf += b"SPL1" - buf += struct.pack(" 0), } - mpath = os.path.join(os.path.dirname(out_path), "torso.manifest.json") - with open(mpath, "w", encoding="utf-8") as f: + with open(os.path.join(pub, "torso.manifest.json"), "w", encoding="utf-8") as f: json.dump(manifest, f, indent=2) - print(f"baked {out_path}: {n:,} gaussians from {len(seen_mesh)} meshes / " - f"{used_concepts} concepts ({len(pts):,} verts, stride {stride})", file=sys.stderr) - print(f" bbox [{bmin[0]:.2f},{bmin[1]:.2f},{bmin[2]:.2f}].." - f"[{bmax[0]:.2f},{bmax[1]:.2f},{bmax[2]:.2f}] size {len(buf):,} B", file=sys.stderr) - print(f" regions: {', '.join(name.get(k, k) for k in regions)}", file=sys.stderr) + owners = sum(1 for nd in nodes if nd["g_count"] > 0) + print(f"baked {out_path}: {n:,} gaussians, {len(nodes)} node rows " + f"({owners} own meshes), {len(owner)} meshes, stride {stride}", file=sys.stderr) + print(f" SPL2 {len(buf):,} B + torso.nodes.json + manifest", file=sys.stderr) if __name__ == "__main__": diff --git a/crates/osint-bake/tools/spl_codec.py b/crates/osint-bake/tools/spl_codec.py new file mode 100644 index 000000000..45908743d --- /dev/null +++ b/crates/osint-bake/tools/spl_codec.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +"""Helix-anchor codec for the torso gaussian splat — the "x265 for gaussians" +the design converged on. Encodes SPL2 -> SPL3 and round-trips it, reporting the +compression ratio + reconstruction fidelity. This is the MEASUREMENT tool that +proves the design before it is wired into the render/animation path. + +The x265 analogy, mapped to signals already in SPL2 + torso.nodes.json: + helix = 3D Morton (Z-order) of the position = the space-filling / identity + order. Locality-preserving: neighbours in the stream are neighbours + in space, so deltas are tiny. + anchor = the FMA node (its SoA centroid + per-node mean colour/normal) — the + I-frame. Random-access: a structure decodes from its own anchor. + motion = each gaussian's offset from its node anchor (the motion vector). + residual = the helix-ordered DELTA of (motion, normal) from the previous entry. + colour = fully ANCHOR-PREDICTED: per-structure flat colour, so the residual is + ZERO — colour is just the 91-entry node palette (crisp by + construction, no per-gaussian bytes, no boundary bleed). +Entropy back end here is zlib (a stand-in for a real range/CABAC coder); the +point this tool measures is the *structure* (anchor + motion + residual + scan), +not the last entropy %. + +Usage: python3 spl_codec.py +""" +import json +import struct +import sys +import zlib + + +def part1by2(n): + """Spread the low 16 bits of n with two zero bits between each (3D Morton).""" + n &= 0xFFFF + n = (n | (n << 32)) & 0x1F00000000FFFF + n = (n | (n << 16)) & 0x1F0000FF0000FF + n = (n | (n << 8)) & 0x100F00F00F00F00F + n = (n | (n << 4)) & 0x10C30C30C30C30C3 + n = (n | (n << 2)) & 0x1249249249249249 + return n + + +def morton3(x, y, z): + return part1by2(x) | (part1by2(y) << 1) | (part1by2(z) << 2) + + +def main(spl_path, nodes_path): + raw = open(spl_path, "rb").read() + assert raw[:4] == b"SPL2" + count = struct.unpack_from(" a tiny per-node palette; per-gaussian colour = 0 bytes. + palette = {} + for nd in nodes: + palette[nd["row"]] = nd.get("rgb", [180, 180, 180]) + # verify colour is fully predicted by node_row (flat per structure) + colour_exact = all(rgb[i] == ((palette[row[i]][0] << 16) | (palette[row[i]][1] << 8) | palette[row[i]][2]) + for i in range(count)) + + # MOTION (anchor-relative) + RESIDUAL (helix delta), quantized. + # motion = q16(pos) - q16(anchor centroid); then delta along the helix order. + def qc(v, k): + return q16(v, k) + + mot = bytearray(); nrm = bytearray(); rows = bytearray() + prev_mx = prev_my = prev_mz = 0 + prev_nx = prev_ny = prev_nz = 0 + prev_row = -1 + run = 0 + rle = [] # (row, run_length) + for i in order: + ax, ay, az = centroid[row[i]] + mx = qx[i] - qc(ax, 0); my = qy[i] - qc(ay, 1); mz = qz[i] - qc(az, 2) + # zig-zag delta vs previous (x265-style residual along the scan) + for d in (mx - prev_mx, my - prev_my, mz - prev_mz): + z = (d << 1) ^ (d >> 31) + while z >= 0x80: + mot.append((z & 0x7F) | 0x80); z >>= 7 + mot.append(z & 0x7F) + prev_mx, prev_my, prev_mz = mx, my, mz + for a, p in ((nx[i], prev_nx), (ny[i], prev_ny), (nz[i], prev_nz)): + nrm.append((a - p) & 0xFF) + prev_nx, prev_ny, prev_nz = nx[i], ny[i], nz[i] + # node_row run-length (constant within a structure run along the helix) + if row[i] == prev_row: + run += 1 + else: + if prev_row >= 0: + rle.append((prev_row, run)) + prev_row, run = row[i], 1 + rle.append((prev_row, run)) + for r, n in rle: + rows += struct.pack(" {len(raw)/spl3:.1f}x smaller") + print(f" motion(zz-delta+zlib) {len(zmot):,} normal(delta+zlib) {len(znrm):,} " + f"rows(RLE+zlib) {len(zrows):,} palette {len(pal):,}") + print(f"colour anchor-predicted (0 per-gaussian bytes): {colour_exact} " + f"({len(palette)} node palette)") + print(f"position round-trip RMSE: {rmse:.5f} (normalized units; bbox half-extent 1.0)") + + +if __name__ == "__main__": + main(sys.argv[1], sys.argv[2])