Metadata-Version: 2.4
Name: ccf-habitat
Version: 0.3.1
Summary: Consistency-constrained framework for CT habitat clustering (BESP2/P2 algorithm package)
Author: Pan Ziqi
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: numpy>=1.22
Requires-Dist: scipy>=1.8
Requires-Dist: pandas>=1.3
Requires-Dist: scikit-learn>=1.6
Requires-Dist: SimpleITK>=2.0
Requires-Dist: PyRadiomics>=3.0
Requires-Dist: tqdm>=4.60
Requires-Dist: joblib>=1.0
Requires-Dist: psutil>=5.8
Requires-Dist: matplotlib>=3.5
Requires-Dist: pyyaml>=6.0
Requires-Dist: maskslic>=0.3
Dynamic: license-file

# ccf-habitat

一致性约束的 CT 影像栖息地（habitat）亚区分割工具包。
算法内核为 **BESP2**（BESMNN 谱聚类扩展版：超节点特征 → 迭代扩展 → 全局图 → 谱聚类）与
**P2**（五个冻结人源参考预测器，纯 NumPy），用于肺癌等肿瘤 CT 的亚区域无监督分割与跨物种判别。

本包把原先"一键脚本 + 数据同包"的调用方式重构为标准 Python 包：

- `pip install -e .` 即可安装，提供 `ccf-train` / `ccf-predict` / `ccf-example` / `ccf-list-data` / `ccf-slic` 命令；
- 算法代码原样归档（`ccf/engine_besp2.py`、`ccf/selfsp.py`、`ccf/predictors.py`），**不重写逻辑**，
  因此结果与既有权威输出一致；
- **数据不捆绑**：约 35 GB 的影像/中间数据通过 `data_root` 指向外部目录（默认自动探测本机
  `D:\Software-develop\BESMNN\biology-analysis\02_input`），GitHub 上只保留代码与配置。

## 安装

```bash
python -m pip install -e .
# 或直接以包根为工作目录：export PYTHONPATH=<包根>（Windows: $env:PYTHONPATH="<包根>"）
```

依赖：numpy / scipy / pandas / scikit-learn>=1.6 / SimpleITK / PyRadiomics / tqdm / joblib / psutil / matplotlib / pyyaml / maskslic。

### NumPy 2.x 环境（Linux / macOS / Windows + MSVC）

PyRadiomics 3.1.0 与 maskslic 0.3.4 在 PyPI 上的产物是 **NumPy 1.x 时代编译**的：官方 wheel 在
NumPy 2.x 下拒绝加载，Linux/macOS 无 wheel 平台安装时还需源码编译。两者的源码用 NumPy 2.x
工具链重新编译后可**原生运行于 NumPy 2.x**（数值结果与 NumPy 1.x 完全一致，实测特征与
分割逐项一致）。本包提供一键补丁编译入口：

```bash
# 1. 先跑补丁编译（自动下载 sdist、打 3 个上游兼容补丁、编译安装 PyRadiomics + maskslic）
ccf-install-np2

# 2. 再装包本体
python -m pip install ccf-habitat
```

> Windows 的 numpy 1.x 环境（有官方 wheel）无需此步骤；`ccf-install-np2` 检测到
> numpy<2 会直接提示"无需处理"退出。
> 兼容性矩阵：
>
> | 环境 | 安装方式 |
> |---|---|
> | NumPy 1.x（Windows/任意） | `pip install ccf-habitat` 直接装（官方 wheel） |
> | NumPy 2.x（Linux/macOS） | `ccf-install-np2` + `pip install ccf-habitat` |
> | NumPy 2.x（Windows） | 需 Microsoft C++ Build Tools，同样 `ccf-install-np2` + 安装 |
>
> scikit-learn 自 1.6 起实测兼容至最新版（1.9.x，selfsp 谱聚类结果一致），已放开硬锁。

## 数据策略

| 内容 | 位置 |
|---|---|
| 代码 / 配置 / 示例 | 本仓库（GitHub 可公开） |
| 人源 539 例 CT/ROI/超体素 mask | `02_input/human/besp2_source/shared/{ct,sub,merged_masks}`（外部） |
| 人源 BESP2 工作套（split、模型、日志） | `02_input/human/besp2_source/BS{3,6,10}`（外部） |
| 鼠源（6 例）与病理基准 | `02_input/mouse*`、`02_input/mouse_pathology`（外部） |

`data_root` 解析优先级：命令行 `--data-root` / yaml 配置 > 环境变量 `CCF_DATA_ROOT` > 本机默认路径。

## 用法

### 命令行

```bash
# 查看数据布局探测结果
ccf-list-data

# 冒烟：前 3 例跑通完整训练链（CPU 可跑，证明安装与调用链路）
ccf-train -k 3 -o ./out --subset 3

# 完整：全 539 例 K=6 训练+测试（重型，需 GPU 与较长时间）
ccf-train -k 6 -o ./out --mode train_test

# 判别（P2 预测器；reference 通过 CCF_DATA_REFERENCE 预置）
ccf-predict -m P2 -i embedding.npy -o ./out
```

### Python API

```python
from ccf import CCFHabitatModel, CCFConfig

model = CCFHabitatModel(CCFConfig(k=3, output_dir="./out"))
fit = model.fit(subset=3)            # 冒烟；去掉 subset=3 为全量
print(fit["train_data_path"])

from ccf.predictors import FrozenReference
ref = FrozenReference.from_model(spectral_model, train_index_mapping)
res = model.predict("P2", ref, embedding=mouse_embedding)   # labels/scores/margin
```

## 与既有权威流程的关系（结果一致性）

| 组件 | 来源（biology-analysis 核验包） | 本包 |
|---|---|---|
| BESP2 主算法 | `01_code/s02_besp2_human/1.BESMNNCORRECT4.5.py` | `ccf/engine_besp2.py`（原样复制，改相对导入） |
| 谱聚类 | `01_code/s02_besp2_human/selfsp.py` | `ccf/selfsp.py` |
| P2 预测器 | `01_code/s02_besp2_human/new_predictors.py` | `ccf/predictors.py`（原样复制） |
| PyRadiomics 配置 | — | `ccf/configs/default_radiomics.yaml` |
| maskslic 超体素 | `01_code/s01_slic/0.Maskslic20-多线程_human.py`、`1.Maskslic100brats-多线程.py` | `ccf/maskslic.py`（参数口径原样保留） |

## 超体素生成（ccf-slic，集成 maskslic）

上游 `s01_slic` 阶段用 **PyPI maskslic 包**（Benjamin Irving，BSD-3-Clause，scikit-image SLIC 的
mask 约束变体）生成"仅肿瘤区域内"的超体素；本包把两套上游脚本的参数口径原样集成进
`ccf/maskslic.py`，只做 I/O、几何信息保留与并行编排，不修改算法。第三方许可声明见 `NOTICE`。

```bash
# 单例：单模态（人源口径 compactness=10）或多模态（BraTS 口径 compactness=0.5 需显式指定）
ccf-slic --img ct.nii.gz --roi roi.nii.gz --out subregion_label.nii.gz
ccf-slic --img t1.nii.gz,t1ce.nii.gz,t2.nii.gz,flair.nii.gz --roi seg.nii.gz \
         --out label.nii.gz --compactness 0.5

# 批量：img_dir 与 roi_dir 按文件名基线匹配，并行生成（对齐上游 execute_parallel）
ccf-slic --img-dir ./fuse --roi-dir ./roi2 --out-dir ./labels --workers 8
```

```python
from ccf.maskslic import supervoxels, batch_supervoxels
supervoxels("ct.nii.gz", "roi.nii.gz", "subregion_label.nii.gz")       # 单模态
supervoxels(["t1.nii.gz", "flair.nii.gz"], "seg.nii.gz", "out.nii.gz",
            compactness=0.5)                                            # 多通道
```

既有 9 步全链核验（输入完整性自检、NMF 复现、表 1、三算法病理 KW、RNAseq 方向一致性、
多重校正、表 5 二项检验）仍由 `D:\Software-develop\BESMNN\biology-analysis` 包 `run_all.py` 提供；
本包负责把 BESP2/P2 调用标准化，供第三方复现与二次开发。

## 目录结构

```
ccf/
├── pyproject.toml          # 可安装包定义 + 命令行入口
├── ccf/
│   ├── config.py           # 数据路径/参数配置（yaml / 环境变量 / 默认值）
│   ├── dataset.py          # 02_input 布局解析
│   ├── engine_besp2.py     # BESP2 主算法（上游原样归档）
│   ├── selfsp.py           # 谱聚类修改版（sklearn >=1.6 扩展）
│   ├── predictors.py       # P2 冻结人源参考预测器（P1-P5）
│   ├── model.py            # CCFHabitatModel 高层封装（fit/predict）
│   ├── maskslic.py         # maskslic 超体素生成（上游 s01_slic 集成）
│   ├── output.py           # 报告输出
│   ├── cli.py              # ccf-* 命令
│   └── configs/            # 默认 yaml
├── ccf_np2deps/            # numpy 2.x 一键补丁编译（ccf-install-np2，独立于 ccf 包）
└── example/                # 小样本冒烟示例 + 数据指引
```

## 说明

- `02_input` 内数据目录保留上游原始命名（`BES`/`OK`/`BS3`/`5mouse` 等），与源逐文件 MD5 同批，
  勿改名（详见 `biology-analysis` 包 README 命名映射表）。
- K=3/6/10 均为论文口径；`run_mode="train"` 只训练、`"test"` 需已有 `train_data.npz`。
- 本包为科研复现用途；重跑全量需满足原始环境的依赖版本（scikit-learn>=1.6，1.6.1 与最新版均实测兼容）。
- v0.3.1：放开 scikit-learn 硬锁（1.6→1.9.x 实测兼容）、新增 `ccf-install-np2` 支持 NumPy 2.x 原生运行。
