Pixedar commited on
Commit
e3cf718
·
1 Parent(s): 3e70d37

Deploy Python probe API

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +3 -32
  2. .gitignore +4 -0
  3. README.md +3 -46
  4. app.py +157 -110
  5. mindVisualizer/data/brain_alignment.json +28 -0
  6. mindVisualizer/data/extra_parcellation/README.md +53 -0
  7. mindVisualizer/data/{roi_flow/mdn_training_all_points.npy → extra_parcellation/combined_atlas.nii.gz} +2 -2
  8. mindVisualizer/data/extra_parcellation/combined_atlas_labels.json +129 -0
  9. mindVisualizer/data/label_grid_cache.keys.json +1 -0
  10. mindVisualizer/data/{roi_flow/probe_embed.npy → label_grid_cache.npz} +2 -2
  11. mindVisualizer/data/{roi_flow/mdn_universal_all_grid64_entropy.bin → mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_entropy.bin} +2 -2
  12. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mean_xyz3.bin +3 -0
  13. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_meta.json +1 -0
  14. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu1_xyz3.bin +3 -0
  15. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu2_xyz3.bin +3 -0
  16. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu3_xyz3.bin +3 -0
  17. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu4_xyz3.bin +3 -0
  18. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu5_xyz3.bin +3 -0
  19. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu6_xyz3.bin +3 -0
  20. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_pi_xyz6.bin +3 -0
  21. mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_training_points.npy +3 -0
  22. mindVisualizer/data/{roi_flow/mdn_universal_all_grid64_mean_xyz3.bin → meshes_obj/10153.obj} +2 -2
  23. mindVisualizer/data/meshes_obj/10154.obj +3 -0
  24. mindVisualizer/data/meshes_obj/10155.obj +3 -0
  25. mindVisualizer/data/meshes_obj/10156.obj +3 -0
  26. mindVisualizer/data/{roi_flow/mdn_universal_all_grid64_mu1_xyz3.bin → meshes_obj/10157.obj} +2 -2
  27. mindVisualizer/data/meshes_obj/10158.obj +3 -0
  28. mindVisualizer/data/meshes_obj/10159.obj +3 -0
  29. mindVisualizer/data/meshes_obj/10292.obj +3 -0
  30. mindVisualizer/data/meshes_obj/10306.obj +3 -0
  31. mindVisualizer/data/{roi_flow/probe_roi_centers.npy → meshes_obj/10307.obj} +2 -2
  32. mindVisualizer/data/meshes_obj/10308.obj +3 -0
  33. mindVisualizer/data/meshes_obj/10311.obj +3 -0
  34. mindVisualizer/data/meshes_obj/10313.obj +3 -0
  35. mindVisualizer/data/meshes_obj/10327.obj +3 -0
  36. mindVisualizer/data/meshes_obj/10329.obj +3 -0
  37. mindVisualizer/data/meshes_obj/10330.obj +3 -0
  38. mindVisualizer/data/meshes_obj/10331.obj +3 -0
  39. mindVisualizer/data/meshes_obj/10332.obj +3 -0
  40. mindVisualizer/data/meshes_obj/10333.obj +3 -0
  41. mindVisualizer/data/meshes_obj/10334.obj +3 -0
  42. mindVisualizer/data/meshes_obj/10335.obj +3 -0
  43. mindVisualizer/data/meshes_obj/10336.obj +3 -0
  44. mindVisualizer/data/meshes_obj/10337.obj +3 -0
  45. mindVisualizer/data/meshes_obj/10338.obj +3 -0
  46. mindVisualizer/data/meshes_obj/10339.obj +3 -0
  47. mindVisualizer/data/meshes_obj/10342.obj +3 -0
  48. mindVisualizer/data/meshes_obj/10343.obj +3 -0
  49. mindVisualizer/data/meshes_obj/10344.obj +3 -0
  50. mindVisualizer/data/meshes_obj/10346.obj +3 -0
.gitattributes CHANGED
@@ -1,35 +1,6 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
  *.npy filter=lfs diff=lfs merge=lfs -text
15
  *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
1
  *.bin filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
2
  *.npy filter=lfs diff=lfs merge=lfs -text
3
  *.npz filter=lfs diff=lfs merge=lfs -text
4
+ *.obj filter=lfs diff=lfs merge=lfs -text
5
+ *.nii filter=lfs diff=lfs merge=lfs -text
6
+ *.gz filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ .git
2
+ __pycache__
3
+ *.pyc
4
+ .env
README.md CHANGED
@@ -1,53 +1,10 @@
1
- ---
2
  title: MindVisualizer API
3
  sdk: docker
4
  app_port: 7860
5
  pinned: false
6
  ---
7
 
8
- # MindVisualizer Python API
9
-
10
- Small FastAPI adapter for the hosted web page.
11
-
12
- The GitHub Pages frontend renders particles locally. This backend is only for algorithm-sensitive operations:
13
-
14
- - recomputing probe trajectories with the original Python `TriLinearSampler`
15
- - mapping a trajectory to ROI vectors with the original `ManifoldToROIKNN`
16
- - building the original `ROIFlowAnalyzer` context
17
- - optionally calling the original `ROIFlowLLM` if `OPENAI_API_KEY` is configured
18
-
19
- ## Cheapest hosting shape
20
-
21
- Use a free Python container host and keep the service public:
22
-
23
- 1. Bundle the minimal `mindVisualizer` source/data folder into the Space as `/app/mindVisualizer`.
24
- 2. Deploy this directory as a Docker/FastAPI service.
25
- 3. Set `MINDVIS_REPO=/app/mindVisualizer`.
26
- 4. Set `CORS_ORIGINS=https://pixedar.github.io,http://localhost:3000`.
27
- 5. In the GitHub Pages build, set `NEXT_PUBLIC_MINDVIS_API_URL=https://your-backend-url`.
28
- 6. Optional: set `OPENAI_API_KEY` as a Space secret and `OPENAI_MODEL` as a Space variable.
29
-
30
- Current Space:
31
-
32
- - https://huggingface.co/spaces/Pixedar/mindvisualizer-api
33
- - https://pixedar-mindvisualizer-api.hf.space
34
-
35
- Do not install the full `mindVisualizer` `pyproject.toml` on a tiny free host; it pulls desktop/VTK dependencies. This adapter uses `PYTHONPATH` and installs only the packages needed for the API path.
36
-
37
- ## Local run
38
-
39
- ```bash
40
- cd backend/mindvis-api
41
- python -m venv .venv
42
- .venv\Scripts\activate
43
- pip install -r requirements.txt
44
- $env:MINDVIS_REPO="C:\Users\assas\PycharmProjects\mindVisualizer"
45
- uvicorn app:app --reload --port 7860
46
- ```
47
-
48
- Then build/run the web page with:
49
 
50
- ```bash
51
- $env:NEXT_PUBLIC_MINDVIS_API_URL="http://localhost:7860"
52
- pnpm dev
53
- ```
 
1
+ ---
2
  title: MindVisualizer API
3
  sdk: docker
4
  app_port: 7860
5
  pinned: false
6
  ---
7
 
8
+ # MindVisualizer API
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ Python-backed probe trajectory and explanation service.
 
 
 
app.py CHANGED
@@ -1,4 +1,3 @@
1
- import json
2
  import os
3
  import sys
4
  from functools import lru_cache
@@ -11,20 +10,20 @@ from fastapi.middleware.cors import CORSMiddleware
11
  from pydantic import BaseModel, Field
12
 
13
 
14
- FieldMode = Literal["mean", "gated", "mu1", "mu2"]
15
 
16
 
17
  class TrajectoryRequest(BaseModel):
18
  seed: list[float] = Field(default_factory=lambda: [0.5, 0.5, 0.5], min_length=3, max_length=3)
19
- fieldMode: FieldMode = "gated"
20
- steps: int = Field(default=220, ge=8, le=1200)
21
- dt: float = Field(default=0.018, gt=0, le=0.1)
22
- speedScale: float = Field(default=0.48, gt=0, le=4)
23
 
24
 
25
  class ExplainRequest(BaseModel):
26
  trajectory: list[list[float]] = Field(min_length=2)
27
- fieldMode: FieldMode = "gated"
28
  callLlm: bool = True
29
 
30
 
@@ -40,49 +39,80 @@ def mindvis_repo() -> Path:
40
  @lru_cache(maxsize=1)
41
  def services():
42
  repo = mindvis_repo()
 
43
 
44
  from src.field_loader import TriLinearSampler, load_field
45
- from src.roi_flow import ManifoldToROIKNN, ROIFlowAnalyzer
46
 
47
- data = repo / "data"
48
- flow = load_field(data / "roi_flow" / "mdn_universal_raw_grid64_meta.json")
49
  mean = flow["mean"]
50
- mu1 = flow["mus"][0]
51
- mu2 = flow["mus"][1]
52
  pi = flow["pi"]
53
- gated = np.where(np.argmax(pi, axis=-1)[..., None] == 0, mu1, mu2).astype(np.float32)
54
-
55
- samplers = {
56
- "mean": TriLinearSampler(mean, flow["amin"], flow["amax"]),
57
- "gated": TriLinearSampler(gated, flow["amin"], flow["amax"]),
58
- "mu1": TriLinearSampler(mu1, flow["amin"], flow["amax"]),
59
- "mu2": TriLinearSampler(mu2, flow["amin"], flow["amax"]),
60
- }
61
-
62
- embed = np.load(data / "roi_flow" / "probe_embed.npy").astype(np.float32)
63
- roi = np.load(data / "roi_flow" / "probe_roi.npy").astype(np.float32)
64
- centers = np.load(data / "roi_flow" / "probe_roi_centers.npy").astype(np.float32)
65
- structures = json.loads((data / "structures.json").read_text(encoding="utf-8"))
66
-
67
- names = []
68
- for idx in range(roi.shape[1]):
69
- item = structures[idx] if idx < len(structures) else {}
70
- names.append(item.get("name") or item.get("acronym") or f"ROI {idx + 1}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
- mapper = ManifoldToROIKNN(embed, roi, k=256)
73
- analyzer = ROIFlowAnalyzer(names, centers[: len(names)])
74
 
75
  return {
76
- "amin": flow["amin"],
77
- "amax": flow["amax"],
78
- "span": flow["amax"] - flow["amin"],
79
  "samplers": samplers,
80
- "mapper": mapper,
81
- "analyzer": analyzer,
 
 
 
82
  }
83
 
84
 
85
- app = FastAPI(title="MindVisualizer API", version="0.1.0")
86
 
87
  origins = [origin.strip() for origin in os.environ.get("CORS_ORIGINS", "*").split(",") if origin.strip()]
88
  app.add_middleware(
@@ -105,10 +135,16 @@ def health():
105
  @app.post("/api/mindvis/trajectory")
106
  def trajectory(req: TrajectoryRequest):
107
  svc = services()
108
- path = integrate_path(req.seed, req.fieldMode, req.steps, req.dt, req.speedScale)
 
109
  return {
110
  "fieldMode": req.fieldMode,
111
- "trajectory": normalized(path, svc["amin"], svc["span"]).tolist(),
 
 
 
 
 
112
  }
113
 
114
 
@@ -120,42 +156,82 @@ def explain(req: ExplainRequest):
120
  raise HTTPException(status_code=400, detail="trajectory must be an array of [x,y,z] points")
121
 
122
  world = denormalized(np.clip(traj, 0.0, 1.0), svc["amin"], svc["span"])
123
- mapper = svc["mapper"]
124
- analyzer = svc["analyzer"]
125
- start_roi = mapper.query(world[0])
126
- end_roi = mapper.query(world[-1])
127
- delta = analyzer.compute_delta(start_roi, end_roi)
128
- context = analyzer.build_llm_context(delta)
129
-
130
- text = ""
131
- if req.callLlm and os.environ.get("OPENAI_API_KEY"):
132
- text = call_openai_interpreter(context)
133
-
134
- if not text:
135
- analysis = analyzer.analyze_flow_pattern(delta)
136
- text = (
137
- f"Pattern: {analysis['pattern_type']}. "
138
- f"Bulk direction: {analysis['bulk_direction']}. "
139
- f"Positive ROIs: {analysis['n_significant_positive']}; "
140
- f"negative ROIs: {analysis['n_significant_negative']}."
141
  )
142
 
143
- return {"text": text, "context": context}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
 
 
 
 
145
 
146
- def integrate_path(seed: list[float], field_mode: FieldMode, steps: int, dt: float, speed_scale: float) -> np.ndarray:
 
 
 
 
 
 
 
 
 
 
147
  svc = services()
148
- p = denormalized(np.asarray(seed[:3], dtype=np.float32)[None, :], svc["amin"], svc["span"])
149
- sampler = svc["samplers"][field_mode]
150
- path = np.empty((steps, 3), dtype=np.float32)
 
 
 
 
 
 
 
 
 
151
 
152
- for idx in range(steps):
153
- path[idx] = p[0]
154
- v = sampler.sample_vec(p)
155
- p = p + v * (dt * speed_scale)
156
- p = ((p - svc["amin"]) % svc["span"]) + svc["amin"]
157
 
158
- return path
159
 
160
 
161
  def denormalized(points: np.ndarray, amin: np.ndarray, span: np.ndarray) -> np.ndarray:
@@ -166,44 +242,15 @@ def normalized(points: np.ndarray, amin: np.ndarray, span: np.ndarray) -> np.nda
166
  return (points.astype(np.float32) - amin[None, :]) / span[None, :]
167
 
168
 
169
- def call_openai_interpreter(context: str) -> str:
170
- from openai import OpenAI
171
-
172
- model = os.environ.get("OPENAI_MODEL", "gpt-4o-mini")
173
- instructions = (
174
- "You are a neuroscientist interpreting brain state dynamics from a "
175
- "manifold flow simulation. The user traced a path through a learned "
176
- "neural manifold. You are given how each ROI's contribution changed "
177
- "along this path.\n\n"
178
- "The delta values do not mean simple activation. They measure how each "
179
- "ROI's contribution to the overall brain state shifted. Positive means "
180
- "the region became a stronger contributor; negative means it became a "
181
- "weaker contributor.\n\n"
182
- "Do not list every ROI. Synthesize the spatial pattern, directionality, "
183
- "and network shift into one coherent interpretation. Keep the response "
184
- "to 2 concise paragraphs."
185
- )
186
-
187
- try:
188
- client = OpenAI(timeout=60.0)
189
- if hasattr(client, "responses"):
190
- response = client.responses.create(
191
- model=model,
192
- instructions=instructions,
193
- input=context,
194
- max_output_tokens=900,
195
- )
196
- return (response.output_text or "").strip()
197
-
198
- response = client.chat.completions.create(
199
- model=model,
200
- messages=[
201
- {"role": "system", "content": instructions},
202
- {"role": "user", "content": context},
203
- ],
204
- max_tokens=900,
205
- temperature=0.3,
206
- )
207
- return (response.choices[0].message.content or "").strip()
208
- except Exception as exc:
209
- return f"[GPT ERROR] {exc}"
 
 
1
  import os
2
  import sys
3
  from functools import lru_cache
 
10
  from pydantic import BaseModel, Field
11
 
12
 
13
+ FieldMode = Literal["mean", "gated", "mu1", "mu2", "mu3", "mu4", "mu5", "mu6"]
14
 
15
 
16
  class TrajectoryRequest(BaseModel):
17
  seed: list[float] = Field(default_factory=lambda: [0.5, 0.5, 0.5], min_length=3, max_length=3)
18
+ fieldMode: FieldMode = "mean"
19
+ steps: int = Field(default=700, ge=8, le=1600)
20
+ dt: float = Field(default=1.0, gt=0, le=8.0)
21
+ speedScale: float = Field(default=1.0, gt=0, le=8.0)
22
 
23
 
24
  class ExplainRequest(BaseModel):
25
  trajectory: list[list[float]] = Field(min_length=2)
26
+ fieldMode: FieldMode = "mean"
27
  callLlm: bool = True
28
 
29
 
 
39
  @lru_cache(maxsize=1)
40
  def services():
41
  repo = mindvis_repo()
42
+ data = repo / "data"
43
 
44
  from src.field_loader import TriLinearSampler, load_field
45
+ from src.mesh_overlay import FlowMeshOverlay
46
 
47
+ flow = load_field(data / "mdn" / "mdn_particles_rdcim_teacher_edge_hq_grid125_meta.json")
 
48
  mean = flow["mean"]
49
+ mus = flow["mus"]
 
50
  pi = flow["pi"]
51
+ ent = flow["ENT"]
52
+ amin = flow["amin"]
53
+ amax = flow["amax"]
54
+ span = amax - amin
55
+ diag = float(np.linalg.norm(span))
56
+ target_step = 0.01 * max(diag, 1e-6)
57
+
58
+ winner = np.argmax(pi, axis=-1)
59
+ gated = np.zeros_like(mean, dtype=np.float32)
60
+ for idx, mu in enumerate(mus):
61
+ gated += mu * (winner[..., None] == idx).astype(np.float32)
62
+
63
+ fields = {"mean": mean, "gated": gated}
64
+ fields.update({f"mu{idx + 1}": mu for idx, mu in enumerate(mus)})
65
+ samplers = {name: TriLinearSampler(field, amin, amax) for name, field in fields.items()}
66
+
67
+ def vmax(field):
68
+ mag = np.linalg.norm(field.reshape(-1, 3), axis=1)
69
+ nz = mag[mag > 0]
70
+ return float(np.percentile(nz, 100.0)) if nz.size else 1.0
71
+
72
+ vmax_by_name = {name: vmax(field) for name, field in fields.items()}
73
+
74
+ # The original Python app uses FlowMeshOverlay + its cached label grid for
75
+ # probe interpretation. This API intentionally reuses that path.
76
+ import vtk
77
+
78
+ ren = vtk.vtkRenderer()
79
+ win = vtk.vtkRenderWindow()
80
+ win.OffScreenRenderingOn()
81
+ win.AddRenderer(ren)
82
+ mesh = FlowMeshOverlay(ren=ren, win=win, mesh_dir=data / "meshes", alignment_file=data / "brain_alignment.json")
83
+ cache = data / "label_grid_cache.npz"
84
+ if not mesh.load_label_grid(cache):
85
+ raise RuntimeError("Python label_grid_cache is missing; run setup_brain_data.py in mindVisualizer first.")
86
+
87
+ # Optional finer parcellation, exactly as the desktop flow mode auto-detects.
88
+ try:
89
+ from src.extra_parcellation import ExtraParcellation
90
+
91
+ atlas = data / "extra_parcellation" / "combined_atlas.nii.gz"
92
+ labels = data / "extra_parcellation" / "combined_atlas_labels.json"
93
+ if atlas.exists():
94
+ extra = ExtraParcellation(atlas, labels if labels.exists() else None)
95
+ if extra.load():
96
+ mesh.set_extra_parcellation(extra)
97
+ except Exception as exc:
98
+ print(f"[extra-parcellation] disabled: {exc}")
99
 
100
+ ent_sampler = TriLinearSampler(mean, amin, amax) if ent is not None else None
 
101
 
102
  return {
103
+ "amin": amin,
104
+ "amax": amax,
105
+ "span": span,
106
  "samplers": samplers,
107
+ "vmax": vmax_by_name,
108
+ "target_step": target_step,
109
+ "mesh": mesh,
110
+ "entropy": ent,
111
+ "entropy_sampler": ent_sampler,
112
  }
113
 
114
 
115
+ app = FastAPI(title="MindVisualizer API", version="1.0.0")
116
 
117
  origins = [origin.strip() for origin in os.environ.get("CORS_ORIGINS", "*").split(",") if origin.strip()]
118
  app.add_middleware(
 
135
  @app.post("/api/mindvis/trajectory")
136
  def trajectory(req: TrajectoryRequest):
137
  svc = services()
138
+ world, mags, stopped = integrate_probe(req, svc)
139
+ transitions = analyze_regions(world, mags, req.callLlm if hasattr(req, "callLlm") else False)
140
  return {
141
  "fieldMode": req.fieldMode,
142
+ "trajectory": normalized(world, svc["amin"], svc["span"]).tolist(),
143
+ "worldTrajectory": world.tolist(),
144
+ "fieldMagnitudes": mags.tolist(),
145
+ "stopped": stopped,
146
+ "transitions": transitions,
147
+ "regionText": format_transition_text(transitions),
148
  }
149
 
150
 
 
156
  raise HTTPException(status_code=400, detail="trajectory must be an array of [x,y,z] points")
157
 
158
  world = denormalized(np.clip(traj, 0.0, 1.0), svc["amin"], svc["span"])
159
+ sampler = svc["samplers"].get(req.fieldMode, svc["samplers"]["mean"])
160
+ mags = np.linalg.norm(sampler.sample_vec(world), axis=1).astype(np.float32)
161
+ transitions = analyze_regions(world, mags, req.callLlm)
162
+ text = format_transition_text(transitions)
163
+
164
+ if req.callLlm:
165
+ from src.region_analyzer import analyze_with_gpt
166
+
167
+ text = analyze_with_gpt(
168
+ transitions,
169
+ use_rag=os.environ.get("MINDVIS_USE_RAG", "0") == "1",
170
+ model=os.environ.get("OPENAI_MODEL", "gpt-5.4-mini"),
171
+ debug=os.environ.get("MINDVIS_DEBUG", "0") == "1",
 
 
 
 
 
172
  )
173
 
174
+ return {"text": text, "transitions": transitions, "regionText": format_transition_text(transitions)}
175
+
176
+
177
+ def integrate_probe(req: TrajectoryRequest, svc: dict) -> tuple[np.ndarray, np.ndarray, bool]:
178
+ p = denormalized(np.asarray(req.seed[:3], dtype=np.float32)[None, :], svc["amin"], svc["span"])
179
+ sampler = svc["samplers"].get(req.fieldMode, svc["samplers"]["mean"])
180
+ step = req.dt * req.speedScale * (svc["target_step"] / max(svc["vmax"].get(req.fieldMode, 1.0), 1e-9))
181
+ path = []
182
+ mags = []
183
+ stopped = False
184
+
185
+ for _ in range(req.steps):
186
+ path.append(p[0].copy())
187
+ velocity = sampler.sample_vec(p)[0]
188
+ mags.append(float(np.linalg.norm(velocity)))
189
+ new_pos = np.clip(p[0] + velocity * step, svc["amin"], svc["amax"])
190
+
191
+ # Original probe boundary behavior: if a step leaves labelled brain
192
+ # space, try half-step; otherwise stop instead of wrapping.
193
+ if not is_valid_probe_position(new_pos, svc["mesh"]):
194
+ half = np.clip(p[0] + velocity * step * 0.5, svc["amin"], svc["amax"])
195
+ if is_valid_probe_position(half, svc["mesh"]):
196
+ new_pos = half
197
+ else:
198
+ stopped = True
199
+ break
200
 
201
+ if np.linalg.norm(new_pos - p[0]) < 1e-5:
202
+ stopped = True
203
+ break
204
+ p[0] = new_pos.astype(np.float32)
205
 
206
+ return np.asarray(path, dtype=np.float32), np.asarray(mags, dtype=np.float32), stopped
207
+
208
+
209
+ def is_valid_probe_position(point: np.ndarray, mesh) -> bool:
210
+ key = mesh.get_region_at_point(point)
211
+ if key is None:
212
+ key = mesh.find_nearest_region(point, search_radius=2, max_distance_mm=5.0)
213
+ return key is not None
214
+
215
+
216
+ def analyze_regions(world: np.ndarray, mags: np.ndarray, call_llm: bool) -> list[dict]:
217
  svc = services()
218
+ from src.region_analyzer import analyze_probe_path
219
+
220
+ transitions = analyze_probe_path(
221
+ world,
222
+ svc["mesh"],
223
+ sample_every=5,
224
+ field_mags=mags,
225
+ entropy_sampler=svc["entropy_sampler"],
226
+ entropy_field=svc["entropy"],
227
+ )
228
+ return make_json_safe(transitions)
229
+
230
 
231
+ def format_transition_text(transitions: list[dict]) -> str:
232
+ from src.region_analyzer import format_transitions_text
 
 
 
233
 
234
+ return format_transitions_text(transitions)
235
 
236
 
237
  def denormalized(points: np.ndarray, amin: np.ndarray, span: np.ndarray) -> np.ndarray:
 
242
  return (points.astype(np.float32) - amin[None, :]) / span[None, :]
243
 
244
 
245
+ def make_json_safe(value):
246
+ if isinstance(value, np.ndarray):
247
+ return value.tolist()
248
+ if isinstance(value, np.generic):
249
+ return value.item()
250
+ if isinstance(value, dict):
251
+ return {str(k): make_json_safe(v) for k, v in value.items() if not str(k).startswith("_")}
252
+ if isinstance(value, list):
253
+ return [make_json_safe(v) for v in value]
254
+ if isinstance(value, tuple):
255
+ return [make_json_safe(v) for v in value]
256
+ return value
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mindVisualizer/data/brain_alignment.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "matrix": [
3
+ [
4
+ -0.03483789662196803,
5
+ -0.1654855793300339,
6
+ 0.9305766368497694,
7
+ -68.4377205759064
8
+ ],
9
+ [
10
+ -0.9422190580860553,
11
+ -0.06752555868994387,
12
+ -0.047281905216520856,
13
+ 106.73199000287599
14
+ ],
15
+ [
16
+ 0.0747101104018069,
17
+ -0.9287770749837014,
18
+ -0.16236864674663903,
19
+ 115.80117022013123
20
+ ],
21
+ [
22
+ 0.0,
23
+ 0.0,
24
+ 0.0,
25
+ 1.0
26
+ ]
27
+ ]
28
+ }
mindVisualizer/data/extra_parcellation/README.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Extra Parcellation Data
2
+
3
+ Provides fine-grained subregion labels alongside the primary Allen atlas meshes.
4
+
5
+ ## Setup (recommended)
6
+
7
+ Run the setup script to build the combined atlas automatically:
8
+
9
+ ```bash
10
+ python scripts/setup_extra_parcellation.py
11
+ ```
12
+
13
+ This downloads and merges three complementary MNI-space atlases via nilearn:
14
+
15
+ | Layer | Source | Regions | Role |
16
+ |-------|--------|---------|------|
17
+ | 1 | Harvard-Oxford Cortical | 48 | Broad cortical coverage |
18
+ | 2 | Harvard-Oxford Subcortical | 17 | Thalamus, putamen, caudate, hippocampus, amygdala, etc. |
19
+ | 3 | **Julich-Brain** (highest priority) | 62 | Cytoarchitectonic: motor BA4a/4p, somatosensory BA1-3, visual V1-V5, auditory, Broca's, hippocampal subfields |
20
+
21
+ **Total: 127 labeled regions**, Julich-Brain labels override coarser Harvard-Oxford
22
+ where available.
23
+
24
+ Output files (auto-detected by flow mode):
25
+ - `combined_atlas.nii.gz` — NIfTI volume (~700KB)
26
+ - `combined_atlas_labels.json` — label ID to name map
27
+
28
+ ## How it works
29
+
30
+ The combined atlas is in MNI152 1mm space. The Allen atlas scene space is
31
+ approximately MNI-aligned, so probe coordinates can be used directly for lookups.
32
+ When the exact voxel is unlabeled, a nearby-search fallback finds the closest
33
+ labeled region within a few mm.
34
+
35
+ When both the primary Allen mesh and the extra parcellation cover a probe position,
36
+ both are highlighted: the Allen mesh in red, the extra parcellation subregion in
37
+ orange. The subregion name is included in the LLM context as additional detail.
38
+
39
+ ## Custom atlas
40
+
41
+ You can also provide any NIfTI atlas in MNI space:
42
+
43
+ ```bash
44
+ python examples/flow_probe_example.py \
45
+ --extra-parcellation my_atlas.nii.gz \
46
+ --extra-parcellation-labels my_atlas_labels.json
47
+ ```
48
+
49
+ ## Requirements
50
+
51
+ ```bash
52
+ pip install nilearn nibabel scikit-image
53
+ ```
mindVisualizer/data/{roi_flow/mdn_training_all_points.npy → extra_parcellation/combined_atlas.nii.gz} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:bf047435bda457ab7eb4d59940ae8463555bb92cffadaed9d13aad234123887f
3
- size 223208
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:68b7dbb0b9949e0e3021d60db9d6f1499615560cba955e0a2f6ab2e41962d25a
3
+ size 693799
mindVisualizer/data/extra_parcellation/combined_atlas_labels.json ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": "Frontal Pole",
3
+ "2": "Insular Cortex",
4
+ "3": "Superior Frontal Gyrus",
5
+ "4": "Middle Frontal Gyrus",
6
+ "5": "Inferior Frontal Gyrus, pars triangularis",
7
+ "6": "Inferior Frontal Gyrus, pars opercularis",
8
+ "7": "Precentral Gyrus",
9
+ "8": "Temporal Pole",
10
+ "9": "Superior Temporal Gyrus, anterior division",
11
+ "10": "Superior Temporal Gyrus, posterior division",
12
+ "11": "Middle Temporal Gyrus, anterior division",
13
+ "12": "Middle Temporal Gyrus, posterior division",
14
+ "13": "Middle Temporal Gyrus, temporooccipital part",
15
+ "14": "Inferior Temporal Gyrus, anterior division",
16
+ "15": "Inferior Temporal Gyrus, posterior division",
17
+ "16": "Inferior Temporal Gyrus, temporooccipital part",
18
+ "17": "Postcentral Gyrus",
19
+ "18": "Superior Parietal Lobule",
20
+ "19": "Supramarginal Gyrus, anterior division",
21
+ "20": "Supramarginal Gyrus, posterior division",
22
+ "21": "Angular Gyrus",
23
+ "22": "Lateral Occipital Cortex, superior division",
24
+ "23": "Lateral Occipital Cortex, inferior division",
25
+ "24": "Intracalcarine Cortex",
26
+ "25": "Frontal Medial Cortex",
27
+ "26": "Juxtapositional Lobule Cortex (formerly Supplementary Motor Cortex)",
28
+ "27": "Subcallosal Cortex",
29
+ "28": "Paracingulate Gyrus",
30
+ "29": "Cingulate Gyrus, anterior division",
31
+ "30": "Cingulate Gyrus, posterior division",
32
+ "31": "Precuneous Cortex",
33
+ "32": "Cuneal Cortex",
34
+ "33": "Frontal Orbital Cortex",
35
+ "34": "Parahippocampal Gyrus, anterior division",
36
+ "35": "Parahippocampal Gyrus, posterior division",
37
+ "36": "Lingual Gyrus",
38
+ "37": "Temporal Fusiform Cortex, anterior division",
39
+ "38": "Temporal Fusiform Cortex, posterior division",
40
+ "39": "Temporal Occipital Fusiform Cortex",
41
+ "40": "Occipital Fusiform Gyrus",
42
+ "41": "Frontal Opercular Cortex",
43
+ "42": "Central Opercular Cortex",
44
+ "43": "Parietal Opercular Cortex",
45
+ "44": "Planum Polare",
46
+ "45": "Heschl's Gyrus (includes H1 and H2)",
47
+ "46": "Planum Temporale",
48
+ "47": "Supracalcarine Cortex",
49
+ "48": "Occipital Pole",
50
+ "103": "Left Lateral Ventricle",
51
+ "104": "Left Thalamus",
52
+ "105": "Left Caudate",
53
+ "106": "Left Putamen",
54
+ "107": "Left Pallidum",
55
+ "108": "Brain-Stem",
56
+ "109": "Left Hippocampus",
57
+ "110": "Left Amygdala",
58
+ "111": "Left Accumbens",
59
+ "114": "Right Lateral Ventricle",
60
+ "115": "Right Thalamus",
61
+ "116": "Right Caudate",
62
+ "117": "Right Putamen",
63
+ "118": "Right Pallidum",
64
+ "119": "Right Hippocampus",
65
+ "120": "Right Amygdala",
66
+ "121": "Right Accumbens",
67
+ "201": "Amygdala_centromedial group",
68
+ "202": "Amygdala_laterobasal group",
69
+ "203": "Amygdala_superficial group",
70
+ "204": "Anterior intra-parietal sulcus hIP1",
71
+ "205": "Anterior intra-parietal sulcus hIP2",
72
+ "206": "Anterior intra-parietal sulcus hIP3",
73
+ "207": "Broca's area BA44",
74
+ "208": "Broca's area BA45",
75
+ "209": "Hippocampus cornu ammonis",
76
+ "210": "Hippocampus dentate gyrus",
77
+ "211": "Hippocampus entorhinal cortex",
78
+ "212": "Hippocampus hippocampal-amygdaloid transition area",
79
+ "213": "Hippocampus subiculum",
80
+ "214": "Inferior parietal lobule PF",
81
+ "215": "Inferior parietal lobule PFcm",
82
+ "216": "Inferior parietal lobule PFm",
83
+ "217": "Inferior parietal lobule PFop",
84
+ "218": "Inferior parietal lobule PFt",
85
+ "219": "Inferior parietal lobule PGp",
86
+ "220": "Inferior parietal lobule Pga",
87
+ "221": "Insula Id1",
88
+ "222": "Insula Ig1",
89
+ "223": "Insula Ig2",
90
+ "224": "Lateral geniculate body",
91
+ "225": "Mamillary body",
92
+ "226": "Medial geniculate body",
93
+ "227": "Premotor cortex BA6",
94
+ "228": "Primary auditory cortex TE1.0",
95
+ "229": "Primary auditory cortex TE1.1",
96
+ "230": "Primary auditory cortex TE1.2",
97
+ "231": "Primary motor cortex BA4a",
98
+ "232": "Primary motor cortex BA4p",
99
+ "233": "Primary somatosensory cortex BA1",
100
+ "234": "Primary somatosensory cortex BA2",
101
+ "235": "Primary somatosensory cortex BA3a",
102
+ "236": "Primary somatosensory cortex BA3b",
103
+ "237": "Secondary somatosensory cortex / Parietal operculum OP1",
104
+ "238": "Secondary somatosensory cortex / Parietal operculum OP2",
105
+ "239": "Secondary somatosensory cortex / Parietal operculum OP3",
106
+ "240": "Secondary somatosensory cortex / Parietal operculum OP4",
107
+ "241": "Superior parietal lobule 5Ci",
108
+ "242": "Superior parietal lobule 5L",
109
+ "243": "Superior parietal lobule 5M",
110
+ "244": "Superior parietal lobule 7A",
111
+ "245": "Superior parietal lobule 7M",
112
+ "246": "Superior parietal lobule 7P",
113
+ "247": "Superior parietal lobule 7PC",
114
+ "248": "Visual cortex V1 BA17",
115
+ "249": "Visual cortex V2 BA18",
116
+ "250": "Visual cortex V3V",
117
+ "251": "Visual cortex V4",
118
+ "252": "Visual cortex V5",
119
+ "253": "WM: Acoustic radiation",
120
+ "254": "WM: Callosal body",
121
+ "255": "WM: Cingulum",
122
+ "256": "WM: Corticospinal tract",
123
+ "257": "WM: Fornix",
124
+ "258": "WM: Inferior occipito-frontal fascicle",
125
+ "259": "WM: Optic radiation",
126
+ "260": "WM: Superior longitudinal fascicle",
127
+ "261": "WM: Superior occipito-frontal fascicle",
128
+ "262": "WM: Uncinate fascicle"
129
+ }
mindVisualizer/data/label_grid_cache.keys.json ADDED
@@ -0,0 +1 @@
 
 
1
+ ["", "10159", "10292", "10306", "10307", "10308", "10311", "10313", "10327", "10329", "10330", "10331", "10332", "10333", "10334", "10335", "10336", "10337", "10338", "10339", "10342", "10343", "10344", "10346", "10349", "10361", "10383", "10384", "10389", "10390", "10465", "10466", "10467", "10595", "10596", "10597", "10598", "10599", "10600", "10602", "10648", "10649", "10650", "10651", "10653", "10654", "10655", "10656", "10657", "10658", "10659", "10660", "10661", "10662", "10669", "12114", "12115", "12116", "12117", "12118", "12119", "12121", "12122", "12123", "12124", "12125", "12126", "12127", "12132", "12133", "12136", "12137", "12138", "12140", "12142", "12143", "12144", "12145", "12146", "12147", "12148", "12149", "12150", "12151", "12152", "12153", "12154", "12155", "12156", "12157", "12158", "12159", "12160", "12162", "12163", "12164", "12165", "12166", "12170", "12171", "12173", "12174", "12176", "12177", "12178", "12179", "12181", "12195", "12291", "12292", "12305", "12330", "12354", "12369", "12384", "12390", "12405", "12416", "12535", "12538", "12805", "12826", "13229", "13230", "146034872", "146034876", "146034884", "146034888", "266441657"]
mindVisualizer/data/{roi_flow/probe_embed.npy → label_grid_cache.npz} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:baecae7d26b1d76bace68d96f005b0dfc0e737dd83383345e819b669259b5af1
3
- size 113384
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ab71af20799b4cefb9986791337fcb609105b4653141cde9285d486cbfaa4791
3
+ size 101223
mindVisualizer/data/{roi_flow/mdn_universal_all_grid64_entropy.bin → mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_entropy.bin} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:5ef8fb7dace16f77b06b262e09dbbbd0070c21d5ac71e49b280a4af5e34fee2e
3
- size 1048576
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2dc61d9b05f915dad3e8ade5e5d9e5f1df27983cbeaf34c0232010ab7e0008d7
3
+ size 7812500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mean_xyz3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:34525f6bf4a68ac06f87801aa180b57cfea10c8c8559ea67d23d66ea54865109
3
+ size 23437500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_meta.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"grid":125,"axis_min":[-69.5,-104.5625,-54.25],"axis_max":[70.0625,76.09375,81.8125],"files":{"mean_xyz3":"mdn_particles_rdcim_teacher_edge_hq_grid125_mean_xyz3.bin","pi":"mdn_particles_rdcim_teacher_edge_hq_grid125_pi_xyz6.bin","entropy":"mdn_particles_rdcim_teacher_edge_hq_grid125_entropy.bin","mu1_xyz3":"mdn_particles_rdcim_teacher_edge_hq_grid125_mu1_xyz3.bin","mu2_xyz3":"mdn_particles_rdcim_teacher_edge_hq_grid125_mu2_xyz3.bin","mu3_xyz3":"mdn_particles_rdcim_teacher_edge_hq_grid125_mu3_xyz3.bin","mu4_xyz3":"mdn_particles_rdcim_teacher_edge_hq_grid125_mu4_xyz3.bin","mu5_xyz3":"mdn_particles_rdcim_teacher_edge_hq_grid125_mu5_xyz3.bin","mu6_xyz3":"mdn_particles_rdcim_teacher_edge_hq_grid125_mu6_xyz3.bin"},"dtype":"float32","layout":"C-order (x,y,z,3) for *_xyz3; (x,y,z,K) for pi_xyzK; (x,y,z) for entropy","endianness":"little","mixture_mean_field":true,"model":{"quality":"hq","components":6},"mdn_source":"particles/rdcim_teacher_edge","bounds_mode":"full_brain","mode":"field","notes":"Trained on teacher segments (XYZ→ΔS) with optional rDCM conditioning and ROI embeddings","training_points_npy":"mdn_particles_rdcim_teacher_edge_hq_training_points.npy"}
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu1_xyz3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:44c45d1ccd4c2afb936d7a4622493b1d363df9664f6ce53cb26cd5bd892b79e8
3
+ size 23437500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu2_xyz3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2f1b9505a5ae611528425d57b09387e35dd921c20377a3b232a4267133b19baf
3
+ size 23437500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu3_xyz3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:53b0999649dfccf31f8726695c4d5a738009f408389a16954144be89d2a58c87
3
+ size 23437500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu4_xyz3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:afd81e6a49823e2ddb42f8e4256f2bf58f268f5fbf83d95fbf0dc0f0eedef559
3
+ size 23437500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu5_xyz3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:68c1f5eceb934435f58ea77c3b623abb114256cfc23affaa2dba1a202139a4aa
3
+ size 23437500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_mu6_xyz3.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9827f9f7a923994c84e1a44773fc2fe88dd91fd7905e718083dc752d24a31f4d
3
+ size 23437500
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_grid125_pi_xyz6.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ffb8a88b783e3a9aefeb8b7c14cd925769fcd3b4ef7d9ca029e4a8f71cd25265
3
+ size 46875000
mindVisualizer/data/mdn/mdn_particles_rdcim_teacher_edge_hq_training_points.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0f4ac819327e772ab01ed85b81150d2a28111df1ba4ebd9b2b3af200a011849b
3
+ size 14400128
mindVisualizer/data/{roi_flow/mdn_universal_all_grid64_mean_xyz3.bin → meshes_obj/10153.obj} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:4157011b84e35e0a861730baa16de6a97b40ca42b5a0001356760d02a4cddaef
3
- size 3145728
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:03245194c13e6081c41f81bfafb018f9aa819af57642f1729d6830db236912cb
3
+ size 9316827
mindVisualizer/data/meshes_obj/10154.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0026eafd072ba11e02f3f4eab7f768ebcf89f32f5a0144fa38d8774576a1baff
3
+ size 13523828
mindVisualizer/data/meshes_obj/10155.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:89e07d4dc266bd9c69404da5b1ce8a1ea23dd2a41560e30f350b3c49a23e4c65
3
+ size 13523828
mindVisualizer/data/meshes_obj/10156.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8dd907bcc3ed5f654395b9b2bec702f2f00355d6e7a9d208e18e01766f2782eb
3
+ size 12090622
mindVisualizer/data/{roi_flow/mdn_universal_all_grid64_mu1_xyz3.bin → meshes_obj/10157.obj} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:0e64c8f46eaa1c0d3fa269440687f9ff24b561567feaa7fdbb7f4d1aa259976f
3
- size 3145728
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c1432ccc092ed2e7b1495e506a11179420fcfb0919519824bb35329ee8171002
3
+ size 3291242
mindVisualizer/data/meshes_obj/10158.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be09e3ec39b5cacb24af0e9f7d8e69086fd35853899daea7729bf7f048bb5c6d
3
+ size 1992516
mindVisualizer/data/meshes_obj/10159.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aa7c48344b0af6f41f069450f319e9c360ef8b45fe8f36dded24cb45e7ba0aef
3
+ size 149484
mindVisualizer/data/meshes_obj/10292.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2c4b4771c184c4512cfadef75b152e0bcbe9d816a62102d7b93349c967d0d955
3
+ size 112083
mindVisualizer/data/meshes_obj/10306.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aef8de5471788784415bdd77b44e5c532cabc79f5fc3f3c4be37e9dd6c5222e8
3
+ size 112083
mindVisualizer/data/{roi_flow/probe_roi_centers.npy → meshes_obj/10307.obj} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:8a64ab89787f423cb3d4ac4e953a5fe056c4be9a7b3fe4738be529d14fac7b6b
3
- size 12128
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:25a071fd3a955681fcd64f6d28fd917c921e9558b792f622649f93ebace11aa6
3
+ size 19205
mindVisualizer/data/meshes_obj/10308.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:83c6c01f3d02a6980403f340692930dbe47339c03784b4c6a41d6cc8bcf45dd2
3
+ size 28542
mindVisualizer/data/meshes_obj/10311.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6e94088b6a00b31e0077ecb75f28d21621f8b8f4ae1a033b76756713b66737fe
3
+ size 57711
mindVisualizer/data/meshes_obj/10313.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:22a69c74d7c982a8372ac63c49df436bf8bc0fc1edb401710c4939c85fd9866f
3
+ size 48263
mindVisualizer/data/meshes_obj/10327.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:61602d7e56749544c6773467d7b8af22aa7788de7640de8c0b18e6fc9630239a
3
+ size 48263
mindVisualizer/data/meshes_obj/10329.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f145efd0531e791a5f2059f89a4c649a83b12ffee4bd06648569cc36396bbd3c
3
+ size 17345
mindVisualizer/data/meshes_obj/10330.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8d96c21416298bac87134b1f41f762ac122854cd66a93f53bd97a8d833f7b99c
3
+ size 36168
mindVisualizer/data/meshes_obj/10331.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1e092fe926797259b4568d792ea0439daf36297ab5c9946a689892abe4c3b9aa
3
+ size 1853173
mindVisualizer/data/meshes_obj/10332.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c5030b54f80cad2316a5cc57db2649ac44e38d31d61677bda1710ebb29e1418f
3
+ size 1027691
mindVisualizer/data/meshes_obj/10333.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:df7e6a6ae97116b644f5090984b56ddcf5da574b5387c22bb8c554f9fff089ce
3
+ size 949235
mindVisualizer/data/meshes_obj/10334.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a16d8d4d1fcb2cc0ac4be610e5f200c6efd910b3de982492432f563c39f6c2b9
3
+ size 498360
mindVisualizer/data/meshes_obj/10335.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6f4c64f991bb22248463cf2415ab33c6cf89235bb85fa26425672958c6362708
3
+ size 225016
mindVisualizer/data/meshes_obj/10336.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:88b46eb320fe5c91aa1da562277d436caaabace45b0547a1b0d71e13cfa86d81
3
+ size 157144
mindVisualizer/data/meshes_obj/10337.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f60b0f68b013cfca7c50fc2afd63db26e64098d8e6476990d7cbc339613d68eb
3
+ size 162134
mindVisualizer/data/meshes_obj/10338.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0a913a6bd57ddc20209c2a7d0c873705c234eb0f116ae0dfbb7fa88a7074d017
3
+ size 374785
mindVisualizer/data/meshes_obj/10339.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0521f9f55fd1c10d2d9560fff80cb2385a6a9fab003bea1c524e4db1a154bcbb
3
+ size 74905
mindVisualizer/data/meshes_obj/10342.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0864087632dbee936a66dd7d0ab48f208db7fc57118bdef6a1b37e0dbe38b162
3
+ size 142593
mindVisualizer/data/meshes_obj/10343.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8c02b9faf662b97b9275ec64a0da4818c28d5c60f0c7299b0f02212b1f0cf2ea
3
+ size 121130
mindVisualizer/data/meshes_obj/10344.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bf6753d2b9f64cd0f2d6aa8202d6bcdddea7faf10fc4daf6e7c30892c89a2c45
3
+ size 53546
mindVisualizer/data/meshes_obj/10346.obj ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2af0bc2a2c14637a896b13b5ccee911dd9f0d214353ed87aaebbe4b686cdc3d0
3
+ size 396936