Metadata-Version: 2.4
Name: pedicle-infer
Version: 0.1.0
Summary: 椎弓根识别 X 光 YOLOv8-Pose 推理 SDK（ONNX Runtime 后端）
Project-URL: Repository, https://github.com/yzxingtu/pedicle-discern
Author: Pedicle Discern Team
License: Proprietary
Keywords: keypoint-detection,medical-imaging,onnxruntime,pedicle,spine,yolov8
Requires-Python: >=3.10
Requires-Dist: numpy>=1.24
Requires-Dist: onnxruntime>=1.17
Requires-Dist: opencv-python-headless>=4.8
Requires-Dist: pillow>=10.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: torch
Requires-Dist: torch>=2.2; extra == 'torch'
Requires-Dist: ultralytics>=8.2; extra == 'torch'
Description-Content-Type: text/markdown

# pedicle-infer

椎弓根识别 X 光 YOLOv8-Pose 推理 SDK（ONNX Runtime 后端）。

## 安装

```bash
pip install pedicle-infer
# 可选：安装 torch 后端（用于与 ONNX 输出做差异比对）
pip install "pedicle-infer[torch]"
```

## 快速使用

```python
from pedicle_infer import PedicleDetector

detector = PedicleDetector(weights="pedicle-discern-256.onnx", device="auto")
result = detector.predict("vertebra_crop.jpg")

# 按侧别获取椎弓根
for det in result.left_pedicles:
    print(f"左侧: center=({det.center.x:.1f}, {det.center.y:.1f}), conf={det.score:.2f}")
for det in result.right_pedicles:
    print(f"右侧: center=({det.center.x:.1f}, {det.center.y:.1f}), conf={det.score:.2f}")

# JSON 序列化
print(result.to_json())
```

## CLI

```bash
# 推理
pedicle-infer predict image.jpg --weights pedicle.onnx --visualize --output results/

# 查看 SDK 信息
pedicle-infer info
```

## 数据模型

| 类别 ID | 名称 | 说明 |
|---------|------|------|
| 0 | patient_left | 左侧椎弓根 |
| 1 | patient_right | 右侧椎弓根 |

每个检测框携带 **1 个关键点**（椎弓根中心点），坐标格式为 `(x, y, v)`，其中 `v` 为可见性/置信度。

---

## 输出格式详解

### InferenceResult（单张图片完整结果）

调用 `result.to_dict()` 或 `result.to_json()` 返回以下结构：

```json
{
  "image_size": [155, 116],
  "input_size": [256, 256],
  "pedicles_count": 2,
  "left_count": 1,
  "right_count": 1,
  "detections": [ ... ]
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `image_size` | `[width, height]` | 原图尺寸（像素） |
| `input_size` | `[width, height]` | 模型推理输入尺寸（letterbox 后），用于调试 |
| `pedicles_count` | `int` | 全部检测到的椎弓根数量 |
| `left_count` | `int` | 左侧椎弓根数量 |
| `right_count` | `int` | 右侧椎弓根数量 |
| `detections` | `list[Detection]` | 所有检测框详情数组 |

### Detection（单个椎弓根检测结果）

```json
{
  "class_id": 0,
  "class_name": "patient_left",
  "score": 0.9512,
  "bbox_xyxy": [12.34, 8.56, 89.78, 95.12],
  "center": [51.06, 52.34, 0.99],
  "side": "left"
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `class_id` | `int` | 类别编号：`0` = patient_left，`1` = patient_right |
| `class_name` | `string` | 类别名称：`"patient_left"` 或 `"patient_right"` |
| `score` | `float` | 检测置信度，范围 `[0, 1]`，越高越可信 |
| `bbox_xyxy` | `[x1, y1, x2, y2]` | 检测边界框（像素坐标），`(x1,y1)` 为左上角，`(x2,y2)` 为右下角 |
| `center` | `[x, y, v]` | **椎弓根中心点**（像素坐标 + 可见性置信度） |
| `side` | `string` | 侧别快捷标识：`"left"` 或 `"right"` |

### Keypoint / center（椎弓根中心点）

`center` 字段是一个 `[x, y, v]` 三元组：

| 索引 | 名称 | 类型 | 说明 |
|------|------|------|------|
| 0 | `x` | `float` | 中心点 X 坐标（原图像素坐标系） |
| 1 | `y` | `float` | 中心点 Y 坐标（原图像素坐标系） |
| 2 | `v` | `float` | 可见性/置信度，范围 `[0, 1]` |

**`v` 值含义：**

| v 值范围 | 含义 | 可视化建议 |
|----------|------|-----------|
| `v = 0.0` | 不可见 / 未检出 | 红色叉号 |
| `0 < v ≤ 0.5` | 低置信度（可能遮挡或模糊） | 黄色圆点 |
| `v > 0.5` | 高置信度，清晰可见 | 绿色实心圆 |

### 完整输出示例

```json
{
  "image_size": [155, 116],
  "input_size": [256, 256],
  "pedicles_count": 2,
  "left_count": 1,
  "right_count": 1,
  "detections": [
    {
      "class_id": 0,
      "class_name": "patient_left",
      "score": 0.5161,
      "bbox_xyxy": [9.12, 33.86, 33.24, 57.89],
      "center": [21.03, 45.82, 0.999],
      "side": "left"
    },
    {
      "class_id": 1,
      "class_name": "patient_right",
      "score": 0.3809,
      "bbox_xyxy": [65.45, 6.08, 95.94, 36.6],
      "center": [80.52, 21.28, 1.0],
      "side": "right"
    }
  ]
}
```

---

## Python API 属性速查

### Detection 对象

```python
det.class_id       # int   - 类别 ID (0 或 1)
det.class_name     # str   - "patient_left" / "patient_right"
det.score          # float - 检测置信度
det.side           # str   - "left" / "right"
det.center         # Keypoint - 椎弓根中心点 (x, y, v)
det.center.x       # float - 中心点 X（像素）
det.center.y       # float - 中心点 Y（像素）
det.center.v       # float - 可见性置信度
det.center.visible # bool  - v > 0 即为 True
det.bbox_xyxy      # (x1, y1, x2, y2) - 边界框
det.bbox_xywh      # (cx, cy, w, h)   - 中心+宽高
det.width          # float - 边界框宽度
det.height         # float - 边界框高度
det.area           # float - 边界框面积
```

### InferenceResult 对象

```python
result.image_size      # (width, height) - 原图尺寸
result.input_size      # (width, height) - 模型输入尺寸
result.detections      # list[Detection] - 全部检测框
result.pedicles        # list[Detection] - 按 y1 升序排列
result.left_pedicles   # list[Detection] - 仅左侧，按 y1 升序
result.right_pedicles  # list[Detection] - 仅右侧，按 y1 升序
result.to_dict()       # dict            - 序列化为字典
result.to_json()       # str             - 序列化为 JSON 字符串
```

---

## CLI 输出

使用 `--save-json` 时，CLI 会在输出目录中生成：

- `<image_name>.json` — 每张图片的完整 `InferenceResult` JSON
- `_summary.json` — 汇总所有图片结果的数组

```bash
pedicle-infer predict ./images/ \
  --weights pedicle.onnx \
  --imgsz 256 \
  --conf 0.25 \
  --save-json \
  --visualize \
  --show-labels \
  --output ./results/
```

终端输出格式：

```
[pedicle-infer] 输入图片数: 287
[pedicle-infer] 权重: pedicle.onnx
[pedicle-infer] 后端: onnxruntime  设备/Provider: ['CoreMLExecutionProvider', 'CPUExecutionProvider']
  [1/287] 001159-C7.jpg -> pedicles=2 (left=1, right=1)
  [2/287] 001159-L1.jpg -> pedicles=2 (left=1, right=1)
  ...
[pedicle-infer] 全部完成，累计检测框数: 531
[pedicle-infer] 输出目录: /path/to/results
```
