Metadata-Version: 2.4
Name: mirc-dataset-handler
Version: 0.2.3
Summary: Utilities for loading MIRC annotations, creating subject-aware cross-validation splits, and building PyTorch DataLoaders for semantic segmentation workflows.
Author: Iago Rodrigues
License-Expression: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: Pillow
Requires-Dist: tqdm
Requires-Dist: opencv-python
Requires-Dist: matplotlib
Requires-Dist: pandas
Requires-Dist: scikit-learn
Requires-Dist: segmentation-models-pytorch
Requires-Dist: torch-pruning==1.6.1
Requires-Dist: notebook
Requires-Dist: torch
Requires-Dist: torchvision
Requires-Dist: torchaudio
Dynamic: license-file

# mirc-dataset-handler

Utilities for loading, organizing, splitting, and creating PyTorch DataLoaders for the MIRC dataset.

## Features

- Recursive loading of polygon annotations from JSON files
- Compact in-memory annotation structure
- Subject-aware cross-validation split
- Fold-based PyTorch DataLoader creation
- Support for semantic masks with classes:
  - `0`: background
  - `1`: person
  - `2`: robot

## Repository Structure

    mirc-dataset-handler/
    ├── mircdataset/
    │   ├── __init__.py
    │   ├── data_utils.py
    │   └── mirc_torch_dataset.py
    ├── README.md
    ├── pyproject.toml
    └── LICENSE

## Installation

### Environment setup

For better environment setup, before installing the mirc-dataset-handler, please consider to create an environment in this way:

- conda create -n test python=3.9
- conda activate test
- conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia

### Local development

    pip install -e .

### From PyPI

    pip install mirc-dataset-handler

## Package Import

    from mircdataset import data_utils

## Expected Annotation Folder Layout

    annotations/
    └── multi-person/
        └── subject6/
            └── activity1/
                └── routine01_cam1/
                    ├── frame_crop_cam1_000000.json
                    ├── frame_crop_cam1_000015.json
                    └── ...

## Generated Key Format

Each loaded JSON is stored in a dictionary using the key format:

    subjectid_activityid_routineid_camid_frameid

Example:

    6_1_1_1_000000
    6_1_1_1_000015

## Stored Annotation Structure

Each key maps to a compact dictionary like:

    {
        "objects": [
            {
                "label": "person",
                "points": [[x1, y1], [x2, y2], ...]
            },
            {
                "label": "robot",
                "points": [[x1, y1], [x2, y2], ...]
            }
        ],
        "image_height": 720,
        "image_width": 1280,
        "image_path": "/absolute/path/to/frame_crop_cam1_000000.jpg"
    }

## Basic Usage

    from mircdataset import data_utils

    root_folder = "/media/mirc-dataset/annotations/multi-person/"

    dataset_masks = data_utils.load_dataset_masks(root_folder)

    cv_dataset_masks = data_utils.split_dataset_by_subject_cross_validation(dataset_masks, k=5)

    dataloaders = data_utils.create_dataloaders(cv_dataset_masks, batch_size=4)
    from mircdataset import data_utils

or simply:

    root_folder = "/media/mirc-dataset/annotations/multi-person/"
    
    dataloaders = data_utils.create_dataloaders_pipeline(root_folder, k=5, batch_size=4)

## Cross-Validation Behavior

The split is subject-aware, so subjects are never mixed between training and validation folds.

Example with subjects `1..9` and `k=5`:

    fold 0: [1, 2]
    fold 1: [3, 4]
    fold 2: [5, 6]
    fold 3: [7, 8]
    fold 4: [9]

Example with subjects `1..6` and `k=5`:

    fold 0: [1, 2]
    fold 1: [3]
    fold 2: [4]
    fold 3: [5]
    fold 4: [6]

## DataLoader Output

Each sample returned by the dataset has the format:

    {
        "image": torch.FloatTensor,
        "mask": torch.LongTensor
    }

Expected shapes:

    image -> [3, 256, 256]
    mask  -> [256, 256]

Mask classes:

    0 -> background
    1 -> person
    2 -> robot

## Accessing a Fold

    train_loader, val_loader = dataloaders[0]

If `k=5`, then:

- `dataloaders[0]` uses fold 0 as validation
- `dataloaders[1]` uses fold 1 as validation
- `dataloaders[2]` uses fold 2 as validation
- `dataloaders[3]` uses fold 3 as validation
- `dataloaders[4]` uses fold 4 as validation

## Inspecting a Batch

    import matplotlib.pyplot as plt

    train_loader, val_loader = dataloaders[0]

    batch = next(iter(train_loader))

    images = batch["image"]
    masks = batch["mask"]

    image = images[0].cpu().numpy().transpose(1, 2, 0)
    mask = masks[0].cpu().numpy()

    plt.figure(figsize=(10, 4))

    plt.subplot(1, 2, 1)
    plt.imshow(image)
    plt.title("Image")
    plt.axis("off")

    plt.subplot(1, 2, 2)
    plt.imshow(mask, vmin=0, vmax=2)
    plt.title("Mask")
    plt.axis("off")

    plt.tight_layout()
    plt.show()

## Main Public Functions

### `load_dataset_masks(root_folder)`

Recursively loads all JSON annotation files and returns a compact dictionary indexed by:

    subjectid_activityid_routineid_camid_frameid

### `split_dataset_by_subject_cross_validation(dataset_dict, k)`

Splits the dataset into `k` subject-aware folds.

### `create_dataloaders(dataset_folds, batch_size=32, transform=None, mask_mode=None, num_workers=0, pin_memory=False)`

Creates a list of `(train_loader, val_loader)` tuples for cross-validation.

## Notes

- Images are resized to `256x256`
- Masks are generated from polygons and rasterized at `256x256`
- Training DataLoaders use `shuffle=True`
- Validation DataLoaders use `shuffle=False`
- Subjects are never mixed across folds
