# pb-calibration

PB 标定文件（`.pb.txt`）反序列化校验、解析为 YAML、从 YAML 按顺序组装为 `.pb.txt`。  
输出位置与组合位置一致，且可指定。

## 环境与安装

推荐使用 **Conda** 环境 `py310`，并在该环境中安装本包及依赖：

```bash
conda activate py310
pip install -e .   # 开发安装
# 或
pip install .      # 普通安装
```

若仅安装不开发，也可：

```bash
pip install pb-calibration
```

## 功能

1. **反序列化检查**：检查 `pb.txt` 是否存在格式问题（能否正常解析）。
2. **解析为 YAML**：将 `pb.txt` 解析为每个单独的 yaml 文件，输出到**指定目录**；该目录与后续「组合」时使用的目录一致。
3. **从 YAML 组装**：按顺序将指定目录中的单独 yaml 文件组装成 `pb.txt`（输入目录与解析输出目录一致，可指定）。

## 命令行

```bash
# 1. 检查 pb.txt 格式
pb-calibration check -i /path/to/vehicle_config.pb.txt

# 2. 解析 pb.txt 为 yaml，输出到指定目录（该目录即后续 build 的输入）
pb-calibration parse -i /path/to/vehicle_config.pb.txt -o /path/to/yaml_dir

# 3. 从指定目录按顺序组装为 pb.txt（目录与 parse 的 -o 一致）
pb-calibration build -i /path/to/yaml_dir -o /path/to/vehicle_config_out.pb.txt
```

可选参数：`--templates /path/to/proto_templates` 指定模板目录，不指定则使用包内模板。

## Python API

### 接口说明

| 接口 | 签名 | 说明 |
|------|------|------|
| **check** | `check(pb_path, proto_templates_dir=None) -> (bool, str \| None)` | 反序列化校验 `.pb.txt` 格式；返回 `(是否通过, 错误信息)`，通过时错误信息为 `None`。 |
| **parse** | `parse(pb_path, yaml_dir, proto_templates_dir=None) -> (dict, dict)` | 将 `.pb.txt` 解析为多份 YAML 并写入 `yaml_dir`；返回 `(解析后的结构化数据, 缺项/漏项报告)`；失败会抛异常。 |
| **build** | `build(yaml_dir, output_pb_path, proto_templates_dir=None) -> None` | 按顺序将 `yaml_dir` 中的 YAML 组装成 `.pb.txt`；无返回值，失败抛异常。 |

**参数说明：**

- **check**  
  - `pb_path` (str, 必填)：`.pb.txt` 文件路径。  
  - `proto_templates_dir` (str \| None, 可选)：proto 模板目录，不传则使用包内模板。

- **parse**  
  - `pb_path` (str, 必填)：`.pb.txt` 文件路径。  
  - `yaml_dir` (str, 必填)：YAML 输出目录，**应与后续 `build` 的输入目录一致**。  
  - `proto_templates_dir` (str \| None, 可选)：proto 模板目录。

- **build**  
  - `yaml_dir` (str, 必填)：包含 `order_manifest.yaml` 及分组 YAML 的目录（即 `parse` 的输出目录）。  
  - `output_pb_path` (str, 必填)：输出的 `.pb.txt` 路径。  
  - `proto_templates_dir` (str \| None, 可选)：proto 模板目录。

### 使用方法

```python
from pb_calibration import check, parse, build

# 1. 反序列化检查
ok, err = check("vehicle_config.pb.txt")
if not ok:
    print("格式错误:", err)

# 2. 解析为 yaml，输出到指定目录（与 build 输入一致）
yaml_dir = "./output/yaml"  # 可任意指定
data, missing_report = parse("vehicle_config.pb.txt", yaml_dir)
# data: 解析后的结构化数据；missing_report: 与模板对比的缺项报告

# 3. 从同一目录按顺序组装为 pb.txt
build(yaml_dir, "vehicle_config_rebuilt.pb.txt")
```

**典型流程：**

1. **只校验**：`check(pb_path)` → 根据 `ok` 和 `err` 判断格式是否正常。  
2. **PB → 可编辑 YAML**：`parse(pb_path, yaml_dir)` → 在 `yaml_dir` 中修改 YAML。  
3. **YAML → 新 PB**：`build(yaml_dir, output_pb_path)`。

- **输出位置与组合位置一致**：`parse(..., yaml_dir)` 与 `build(yaml_dir, ...)` 使用同一个 `yaml_dir`，可任意指定路径。

## YAML 目录结构

解析后目录内包含：

- `order_manifest.yaml`：顺序清单
- `vehicle_info.yaml`、`vehicle_param.yaml`
- `extrinsics/000.yaml`、`001.yaml`、…
- `intrinsics/<frame_id>.yaml`、…

组装时从同一目录按 `order_manifest.yaml` 顺序读取并生成 `.pb.txt`。

## 依赖

- Python >= 3.10（推荐在 conda 环境 `py310` 下使用）
- PyYAML >= 6.0
- protobuf >= 4.21.0

## License

MIT
