[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-165":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":13,"subscribersCount":13,"size":13,"stars1d":13,"stars7d":13,"stars30d":13,"stars90d":13,"forks30d":13,"starsTrendScore":13,"compositeScore":14,"rankGlobal":8,"rankLanguage":8,"license":8,"archived":15,"fork":15,"defaultBranch":16,"hasWiki":17,"hasPages":15,"topics":18,"createdAt":8,"pushedAt":8,"updatedAt":19,"readmeContent":20,"aiSummary":21,"trendingCount":13,"starSnapshotCount":13,"syncStatus":22,"lastSyncTime":23,"discoverSource":24},165,"CMR_QC_Studio","maxmo2009\u002FCMR_QC_Studio","maxmo2009",null,"JavaScript",101,10,1,0,3.12,false,"master",true,[],"2026-06-12 02:00:09","# Cardiac Segmentation QC Studio\n\nA multi-user web application for reviewing cardiac MRI (CMR) segmentation results. Reviewers step through patients and both cardiac phases (End-Diastole \u002F End-Systole), score each segmentation (accept \u002F reject \u002F fine-tune \u002F unclassified), and persist decisions to their own JSON file.\n\n![Lab Logo](https:\u002F\u002Fimages.squarespace-cdn.com\u002Fcontent\u002Fv1\u002F611bce9f0ec5ff43949b98ea\u002F068036ac-5a6f-4da8-869f-520764bdaaaa\u002Fstill_v023_frame_0103_photoshop_layer_logo_LMS.png?format=300w)\n\n## Features\n\n### Multi-User\n- Username + password login (credentials in `JSON\u002Fusers.json`)\n- Each reviewer's QC annotations are fully isolated under `JSON\u002Fusers\u002F\u003Cusername>\u002F`\n- Session-based auth with 3-day rolling lifetime\n\n### Dataset Management\n- Each user can maintain any number of QC dataset files side-by-side\n- A dataset dropdown in the stats panel switches the active file without re-login\n- Dataset format: top-level dict keyed by patient path, values hold `ED_Comments` \u002F `ES_Comments`\n\n### 3-Panel Visualization (per cardiac phase)\n- **Left panel** — MRI slices with optional color-coded segmentation overlay (zoom + transparency sliders)\n- **Middle panel** — Color-coded segmentation slices\n- **Right panel** — Three.js 3D InstancedMesh rendering (~50K voxels) with OrbitControls (rotate \u002F pan \u002F zoom)\n\n### QC Decisions\n- Four mutually exclusive decisions: **Accept ✓**, **Reject ✗**, **Fine-tune ⚙**, **Unclassified ?**\n- Free-text reviewer comments per patient + phase\n- Chart.js pie chart of decision distribution for the active dataset\n\n### Slice Navigation\n- Auto-play at 5 FPS, plus manual prev\u002Fnext\n- All three panels stay synchronized on the same slice\n\n### Medical Imaging Support\n- Reads NIfTI (`.nii.gz`) for both MRI and segmentation\n- Voxel spacing taken from NIfTI header for correct physical dimensions\n- Multi-label color map: label 1 = LV (red), 2 = RV (green), 3 = myocardium (blue)\n\n## Installation\n\n```bash\ngit clone git@github.com:maxmo2009\u002FCMR_QC_Studio.git\ncd CMR_QC_Studio\npip install -r requirements.txt\n```\n\n## Running\n\n```bash\npython3 app.py\n```\n\nServer binds to **http:\u002F\u002Flocalhost:5000** (`DEBUG=False`). For deployment, run behind your own reverse proxy or tunnel of choice.\n\n## Adding Users\n\nThree manual steps — no CLI helper, no auto-seeding:\n\n1. Edit `JSON\u002Fusers.json`:\n   ```json\n   {\n     \"admin\": \"cardiacMRI\",\n     \"alice\": \"alicepassword\"\n   }\n   ```\n2. Create the folder: `mkdir JSON\u002Fusers\u002Falice`\n3. Drop one or more QC dataset `.json` files into that folder\n\nNo server restart needed — users.json is re-read on each login and the folder is scanned per request.\n\n## Expected File Layout (per patient, on disk)\n\n```\n{patient_path}\u002F\n├── lvsa_SR_ED.nii.gz      # ED-phase MRI\n├── lvsa_SR_ES.nii.gz      # ES-phase MRI\n├── seg_lvsa_SR_ED.nii.gz  # ED-phase segmentation\n└── seg_lvsa_SR_ES.nii.gz  # ES-phase segmentation\n```\n\nThe `{patient_path}` is stored as a full absolute path in each dataset JSON.\n\n## Tech Stack\n\n### Backend (modular Flask app)\n- Flask 3.0.0 — app factory + blueprints (`routes\u002Fauth.py`, `routes\u002Fpages.py`, `routes\u002Fapi.py`)\n- nibabel 5.3.3 — NIfTI parsing\n- numpy 1.24.3 — array ops\n- Pillow 10.0.0 — slice → PNG\n\n### Frontend (vanilla, no bundler)\n- Three.js r128 — WebGL 3D scene with 5-point lighting\n- OrbitControls — camera interaction\n- Chart.js 4.4.0 — statistics pie chart\n- HTML5 Canvas — MRI + overlay compositing\n\n## Project Structure\n\n```\nCMR_QC_Studio\u002F\n├── app.py                      # Flask app factory (create_app) + entrypoint\n├── config.py                   # Constants + path helpers (USERS_JSON_PATH, user_dir, ...)\n├── requirements.txt\n├── README.md                   # This file\n│\n├── routes\u002F                     # Flask blueprints\n│   ├── auth.py                 #   \u002Flogin, \u002Flogout, login_required decorator\n│   ├── pages.py                #   \u002F  (main page) and \u002Fhealth\n│   └── api.py                  #   all \u002Fapi\u002F* endpoints\n│\n├── services\u002F                   # Business logic (no Flask dependency)\n│   ├── users.py                #   auth + per-user dataset file listing + path-traversal guard\n│   ├── qc_store.py             #   QCStore class (per-request, JSON-backed) + parse_decision\n│   ├── nifti_loader.py         #   MRI\u002Fsegmentation slice loading → base64 PNG, 3D voxel extraction\n│   └── patient.py              #   get_store_for_session + build_patient_payload orchestrator\n│\n├── templates\u002F\n│   ├── index.html              # Main page skeleton (3 panels + floating QC\u002Fstats panels)\n│   └── login.html              # Username + password form\n│\n├── static\u002F\n│   ├── css\u002Fapp.css             # All UI styles\n│   ├── js\u002Fapp.js               # All frontend logic (Three.js, Chart.js, controls)\n│   ├── left_placeholder.png\n│   └── right_placeholder.png\n│\n└── JSON\u002F                       # gitignored — contains credentials + patient data\n    ├── users.json              #   {\"username\": \"plaintext_password\", ...}\n    └── users\u002F\n        └── \u003Cusername>\u002F\n            └── *.json           #     Per-user QC dataset files\n```\n\nNothing under `JSON\u002F` is committed — both credentials and patient data stay local.\n\n## API Endpoints\n\nAll `\u002F` and `\u002Fapi\u002F*` routes require auth. Most `\u002Fapi\u002F*` routes also require an active dataset (set automatically on first visit, or via `\u002Fapi\u002Fset_qc_file`).\n\n| Method | Path | Notes |\n|---|---|---|\n| GET | `\u002Flogin` | Username + password form |\n| GET | `\u002Flogout` | Clears session |\n| GET | `\u002F` | Main page |\n| GET | `\u002Fhealth` | Health check (no auth) |\n| GET | `\u002Fapi\u002Flist_qc_files` | Files available to this user |\n| GET | `\u002Fapi\u002Fset_qc_file\u002F\u003Cfilename>` | Switch active dataset |\n| GET | `\u002Fapi\u002Fset_phase\u002F\u003Cphase>` | `ED` or `ES` |\n| GET | `\u002Fapi\u002Fnext_patient` \u002F `\u002Fapi\u002Fprev_patient` \u002F `\u002Fapi\u002Fgoto_patient\u002F\u003Cid>` | Navigation |\n| GET | `\u002Fapi\u002Fpatient_data` | Current patient payload (slices + voxels) |\n| GET | `\u002Fapi\u002Fpatient_list` | Patients in active dataset + per-phase decisions |\n| GET | `\u002Fapi\u002Fqc_statistics` | Counts + percentages |\n| POST | `\u002Fapi\u002Fsave_qc` | Persist one decision + comment |\n| GET | `\u002Fapi\u002Fdownload_json` | Download the active dataset |\n\n## Data Format\n\n### NIfTI inputs\n- MRI: grayscale intensity values\n- Segmentation: integer labels (0 = background, 1 = LV, 2 = RV, 3 = myocardium)\n- Voxel spacing read from NIfTI header (typically ~1.25 × 1.25 × 8.0 mm)\n\n### QC comment encoding\nEach saved decision is encoded as `\"\u003Cdecision>:\u003Cfree-text>\"` in the `ED_Comments` or `ES_Comments` field:\n```json\n{\n  \"ED_Comments\": \"accept:Good segmentation quality\",\n  \"ES_Comments\": \"reject:Poor myocardium boundary\"\n}\n```\n\n## Development Notes\n\n- Backend logic is split across `routes\u002F` and `services\u002F`; `config.py` centralizes constants\n- CSS and JS live under `static\u002F` (no bundler, no framework) — edit and hard-refresh the browser\n- `DEBUG=False` — Flask caches templates, so restart Flask after editing `templates\u002F*.html`\n- JSON-on-disk storage is not safe for concurrent writes; per-user isolation reduces risk but same-user parallel writes can still collide\n\n## License\n\nAll rights reserved.\n\n## Acknowledgments\n\nBuilt with assistance from Claude Code (claude.com\u002Fcode).\n","CMR_QC_Studio是一个多用户网页应用程序，用于审核心脏MRI（CMR）分割结果。其核心功能包括支持多用户登录、数据集管理和三面板可视化界面，能够查看MRI切片及其分割叠加、纯分割图像以及三维渲染。此外，该应用还提供了四种互斥的审核决策选项，并能生成决策分布饼图。它适合在医学研究或临床环境中使用，特别是需要对大量心脏MRI分割结果进行质量控制和评估时。技术上，此项目采用JavaScript作为前端语言，后端基于Flask框架开发，支持NIfTI格式文件读取与处理，确保了医学影像数据的准确呈现。",2,"2026-06-11 02:31:14","CREATED_QUERY"]