Metadata-Version: 2.1
Name: medics-ext-oct-viewer
Version: 202609020206
Summary: OCT/OCTA Viewer extension for MedICS
Author-email: MedICS <medics.support@gmail.com>
License: Proprietary
Project-URL: Homepage, https://Medical-Image-Computing-Suite.github.io
Project-URL: Documentation, https://github.com/Medical-Image-Computing-Suite/Community/wiki
Project-URL: Issues, https://github.com/Medical-Image-Computing-Suite/Community/issues
Keywords: medical,imaging,annotation,oct/octa viewer,extension
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Topic :: Scientific/Engineering :: Image Processing
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: medics
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"

# MedICS Extension: OCT / OCTA Viewer

Interactive viewer for optical coherence tomography (OCT) and OCT angiography
(OCTA) volumes, built as a MedICS extension. Use it to load scans, scroll
B-scans, generate en-face slabs, overlay layer segmentation, and send volumes
back to the MedICS workspace.

## Overview

The extension opens a dedicated **OCT Analyzer** window with a side panel for
data I/O and a linked multi-pane viewer:

| Pane | What it shows |
|------|----------------|
| **Left B-scan** | Fast-scan (B-scan) OCT, with optional OCTA overlay and layer curves |
| **Right B-scan** | Orthogonal (slow-scan / C-scan direction) OCT and OCTA |
| **En-face OCT** | Projection of the current slab from the structural volume |
| **En-face OCTA** | Projection of the same slab from the flow volume |

Crosshairs stay synchronized: moving the indicator on an en-face map updates
both B-scans, and moving the mouse on a B-scan reports the matching location on
the en-face maps.

Processing stays on your machine. Volumes are never uploaded.

## Requirements

- Python **3.11** or later

## Installation

```bash
pip install medics-ext-oct-viewer
```

Then start MedICS:

```bash
medics
# or
python -m medics
```

Open **OCTViewer** from the **Extensions** menu. The window title is
**OCT Analyzer**.

## Supported files

You can load OCT, OCTA, and segmentation independently. Matching pairs are
detected by filename suffix (see [Paired files](#paired-files)).

| Role | Typical extensions |
|------|--------------------|
| **OCT** (structure) | `.foct`, `.oct`, `.dcm`, `.img`, `.mat`, `.med` |
| **OCTA** (flow) | `.ssada`, `.octa`, `.dcm`, `.img`, `.mat`, `.med` |
| **Segmentation** | `.json`, `.dcm`, `.mat`, `.med` (names such as `seg.mat`, `_seg.mat`, `segmentation.dcm`) |

Vendor-style names such as `cube_z.img` / `FlowCube_z.img` and
`structural.dcm` / `flow.dcm` are recognized as OCT / OCTA pairs.

A volume is expected as a 3-D array `(frames, depth, width)`. Segmentation is
a set of per-B-scan layer curves (see [Layer names](#layer-names)).

## Window layout

The left side panel has three data-source tabs, then frame / transform
controls. The slab list sits below the transforms and drives the en-face maps.

1. **Workspace** — pick arrays already in the MedICS workspace.
2. **File** — browse or drop files from disk.
3. **Transfer** — push loaded OCT, OCTA, or segmentation into the workspace
   under a name you choose.

The status bar (green) shows load progress, mouse coordinates, pixel
intensity, and volume shape.

## Load data

### From the workspace

1. Open the **Workspace** tab.
2. Choose OCT, OCTA, and/or Segment from the dropdowns. Click the refresh
   button if you just imported variables in MedICS.
3. The viewer updates as soon as a valid array is selected.

You can also **drag a variable** from the MedICS variables panel onto the
window (`ws.variable_name`). Volumes load as OCT/OCTA; curve dictionaries
load as segmentation (you will be asked to confirm).

### From files

1. Open the **File** tab.
2. Click the folder button next to **OCT**, **OCTA**, or **Segment**, or
   type / drop a path into the corresponding field.
3. Uncheck the OCTA checkbox if you only want structural OCT.
4. Click **Load Data**.

You can drop a file onto a path field, onto **Load Data**, or onto the
window:

- Known OCT / OCTA / segmentation suffixes load immediately.
- A `.mat` or `.med` file that contains several arrays opens a picker so you
  can assign **OCT**, **OCTA**, and **Segment** keys.
- Any other suffix asks whether to treat the file as OCT, OCTA, or
  segmentation.

### Custom readers

Click **setting...** on the File tab to point at a Python file or folder of
loader functions. Assign a function to OCT, OCTA, and/or segmentation, or
leave **default** to use the built-in readers. This is useful for proprietary
or lab-specific formats.

### Paired files

When you load an OCT file, a sibling OCTA file with the paired suffix is
looked up automatically (for example `.foct` ↔ `.ssada`, `oct.dcm` ↔
`octa.dcm`). The same idea applies to segmentation files named
`*seg.mat`, `*_seg.mat`, `*segmentation.dcm`, and similar.

## Navigate the volume

### Frame control

- **Frame** spin box: current B-scan index (1-based in the UI).
- **Up / Down** (while a viewer pane is focused): previous / next B-scan.
- **Left / Right**: jump **10** B-scans at a time.

### Linked crosshairs

- Click or drag the crosshair on an **en-face** map to choose the B-scan
  (horizontal line) and A-scan (vertical line).
- Move the mouse over a **B-scan** to see the matching point on both en-face
  maps and the intensity in the status bar.

### Zoom and pan

Standard image-viewer gestures apply in each pane (scroll to zoom, drag to
pan). Use **transpose** on an en-face map if the fast/slow axes look swapped.

### Hide panes

Use the collapse buttons next to the en-face OCT and OCTA maps to hide one
projection and give more space to the other. B-scan docks can be resized by
dragging the splitters.

## En-face slabs

En-face images are projections of all voxels between an **upper** and
**lower** boundary. Pick a preset on the slab panel, or edit the custom
formula.

### Presets

| Group | Slabs |
|-------|--------|
| Regions | Vitreous, Retina, Inner, Outer, Choroid |
| Vascular (OCTA) | SVC, DVC, NFLP, GCLP, ICP, DCP |
| Layers | NFL, GCIPL, INL, OPL, ONL, EZ, IZ, RPE |
| Choroid | CC, Sattler, Haller |

**Retina** (ILM → EZ) is selected by default.

Each preset is a linear combination of two layer surfaces plus a pixel
offset, for example:

```text
upper = 1.0 × ILM + 0.0 × ILM + 0
lower = 1.0 × EZ  + 0.0 × ILM + 0
```

You can mix two layers (ratios need not sum to 1) and shift the surface in
depth with the **+ offset** spin boxes. Changes update both en-face maps and
the slab overlay on the B-scans.

### Projection mode

For each en-face map independently:

| Mode | Meaning |
|------|---------|
| **Mean** | Average intensity in the slab (default for OCT) |
| **Maximum** | Maximum intensity (default for OCTA) |
| **Minimum** | Minimum intensity |
| **Thickness** | Slab thickness in pixels (no volume required) |

### Contrast and colormap

Each pane has a color bar and low/high spin boxes. Click the color bar to
choose a colormap (grayscale for OCT, hot-style for OCTA by default). Adjust
the range to brighten faint vessels or compress bright vitreous.

## Layer overlay

If segmentation is loaded, the named curves are drawn on both B-scans. The
same surfaces define slab boundaries for en-face projection.

### Layer names

| # | Name | Typical anatomy |
|---|------|-----------------|
| 1 | PVD | Posterior vitreous detachment |
| 2 | ILM | Inner limiting membrane |
| 3 | NFLGCL | NFL / GCL |
| 4 | GCLIPL | GCL / IPL |
| 5 | IPLINL | IPL / INL |
| 6 | INLOPL | INL / OPL |
| 7 | OPLONL | OPL / ONL |
| 8 | ELM | External limiting membrane |
| 9 | EZ | Ellipsoid zone |
| 10 | EZIZ | EZ / IZ |
| 11 | IZRPE | IZ / RPE |
| 12 | RPEBM | RPE / Bruch’s membrane |
| 13 | SATHAL | Sattler / Haller |
| 14 | CHOROID | Choroid outer boundary |

If no segmentation file is provided, empty curves are created so you can still
use depth ROI and (limited) slab controls. Flattening to **RPE-BM** needs a
valid RPEBM surface.

Layer segmentation itself is a separate extension
([medics-ext-retinal-layer-segmentation](https://pypi.org/project/medics-ext-retinal-layer-segmentation/));
this viewer displays and uses those results.

## Transforms

The **Data Transform** group applies to the currently loaded volumes.

| Control | What it does |
|---------|----------------|
| **Flatten** | `None`, `Fitting`, or `RPE-BM`. Fitting / RPE-BM axially flatten the retina (and OCTA, if loaded) so en-face slabs follow anatomy. RPE-BM uses the RPEBM curve. |
| **Permute** | Reorder axes (`0,1,2` is frames, depth, width). Use this when a vendor volume is stored in a different order. |
| **Flip Axis** | `None`, `Left-Right`, or `Up-Down`. |
| **ROI** | Top and bottom depth indices. **Auto** estimates a retina-containing band so projections ignore empty vitreous/sclera. |

Flattening can take a few seconds on large volumes; a progress dialog is
shown. Segmentation curves are updated to stay aligned with the flattened
data.

## Scan resolution

Click **Update data resolution** to set:

- scan width and height in millimetres
- axial (depth) sampling in millimetres per pixel

Lateral pixel size is computed from scan size ÷ number of A-scans / B-scans.
Axial resolution is a device specification — use the help button in the dialog
if you are unsure. Correct millimetre scaling matters if you later quantify
thickness or export to other MedICS tools.

## Send data to the workspace

On the **Transfer** tab:

1. Optionally rename the variables (`oct_data`, `octa_data`, `seg_data` by
   default). Names must be valid Python identifiers.
2. Click **>>** next to OCT, OCTA, or Segment.

The arrays appear in the MedICS workspace and in the **Workspace** dropdowns
after refresh. Use this to hand volumes to other extensions (layer
segmentation, quantification, custom scripts).

## Typical workflows

### Review a paired OCT / OCTA cube

1. Drop the `.foct` (or `.oct` / DICOM) file onto **Load Data**.
2. Confirm OCTA was auto-filled (`.ssada` / `.octa` / `flow.dcm`).
3. Click **Load Data**.
4. Scroll B-scans with **Up/Down**. Click the en-face map to jump to a region
   of interest.
5. Select **SVC** or **DVC** and set OCTA projection to **Maximum**.

### Inspect a segmented retina

1. Load OCT (and OCTA if available).
2. Load the matching `*_seg.mat` / `.json` / `.med` segmentation.
3. Confirm layer curves overlay the B-scans.
4. Choose **Retina**, **NFL**, or a custom ILM–RPEBM slab and switch
   projection to **Thickness** for a thickness map.

### Flatten for cleaner en-face maps

1. Load OCT and a segmentation that includes **RPEBM**.
2. Set **Flatten** to **RPE-BM** (or **Fitting**).
3. Re-select the slab. Choroid and outer-retina projections usually look
   more uniform after flattening.

### Work from the MedICS workspace

1. Import or compute volumes in MedICS (Import Data, Jupyter, another
   extension).
2. Open OCTViewer → **Workspace** and pick the arrays.
3. After review, use **Transfer** to write a copy under a new name.

## Tips

- Uncheck OCTA before **Load Data** if the paired flow file is missing or
  you only need structure.
- If B-scans look rotated or the en-face map is stretched, try **Permute**
  and **transpose** on the en-face pane before assuming the file is wrong.
- **Auto ROI** is a good first step when vitreous or deep choroid dominates
  the projection.
- Drop `.med` / `.mat` containers rather than guessing keys — the group
  picker lists every array in the file.
- The status bar reports shape as `frames × depth × width` after load.

## Troubleshooting

| Problem | What to try |
|---------|-------------|
| **Load Data** says invalid path | At least one of OCT / OCTA / Segment must be a real file. Empty fields are fine; typo paths are not. |
| OCTA did not appear | Check the OCTA checkbox, confirm the paired suffix, or browse the flow file manually. |
| En-face is blank / noise | Load or create segmentation, pick a slab that sits on the retina, or run **Auto ROI**. Flattening often helps. |
| Layers do not match B-scans | Check **Permute** and **Flip**. Segmentation stores its own permute/flip and is reapplied when you change those controls. |
| Flatten does nothing useful | **RPE-BM** needs a valid RPEBM curve. Use **Fitting** if you only have OCT. |
| Axes look swapped on en-face | Use the transpose button on that en-face map. |
| Custom format will not load | Use **setting...** and point at a Python function that returns a 3-D NumPy array (or a curve dict for segmentation). |
| Extension does not show in the menu | Confirm `pip show medics-ext-oct-viewer` in the same environment as MedICS, then restart MedICS. |

## Links

- Homepage: [Medical-Image-Computing-Suite.github.io](https://Medical-Image-Computing-Suite.github.io)
- Documentation: [Community wiki](https://github.com/Medical-Image-Computing-Suite/Community/wiki)
- Issues: [Community issues](https://github.com/Medical-Image-Computing-Suite/Community/issues)
- Package: [medics-ext-oct-viewer on PyPI](https://pypi.org/project/medics-ext-oct-viewer/)

## License

Proprietary. Contact [medics.support@gmail.com](mailto:medics.support@gmail.com).
