# 香菇菌盖分析系统（AprilTag标定版）

基于AprilTag标定的香菇菌盖最大直径和开裂比自动分析系统。

## 项目特色

### ✨ 核心功能
1. **AprilTag精确标定**：使用37.58mm精确已知尺寸的AprilTag进行像素/毫米比例标定
2. **最大直径测量**：旋转卡壳算法计算菌盖真实最大直径（mm级精度）
3. **开裂比分析**：HSV双通道Otsu阈值法自动提取花纹并计算开裂比
4. **五级评定**：根据开裂比自动评定香菇等级（一级至五级）

### 🚀 性能优化（ROI处理哲学）
- **分层并行架构**：AprilTag检测和YOLO检测并行进行
- **ROI聚焦处理**：只处理感兴趣区域，而非全图
  - AprilTag区域：~100×100像素
  - 香菇ROI：~500×500像素
  - 全图：4000×3000 = 1200万像素
  - **实际处理量减少94%**（76万 vs 1200万像素）
- **可选并行模式**：多个香菇同时处理，3倍速度提升

### 🎯 技术栈
- **YOLO v8**：香菇快速检测（mAP50: 99.5%）
- **SAM (Segment Anything)**：菌盖精确分割
- **AprilTag 36h11**：亚像素级精度标定
- **旋转卡壳算法**：计算真实最远点对直径
- **HSV Otsu阈值**：自适应花纹提取

---

## 项目结构

```
mushroom_apriltag/
├── src/                              # 源代码
│   ├── apriltag_calibration.py       # AprilTag检测与标定
│   ├── diameter_calculator.py        # 最大直径计算（旋转卡壳）
│   ├── crack_analyzer.py             # 开裂比分析（HSV+Otsu）
│   ├── mushroom_detector.py          # YOLO检测 + SAM分割
│   ├── integrated_analyzer.py        # 集成分析器（ROI优化）
│   ├── parallel_processor.py         # 并行处理模块
│   └── pipeline.py                   # 批量处理脚本
│
├── models/                            # 模型文件（需下载）
│   ├── yolo_mushroom.pt              # YOLO检测模型
│   └── sam_vit_b.pth                 # SAM分割模型
│
├── data/
│   └── raw_images/                   # 原始图片（放置你的数据）
│
├── outputs/                           # 输出结果
│   ├── analysis_results.csv          # 分析结果表格
│   ├── visualizations/               # 可视化图像
│   └── analysis_report.txt           # 统计报告
│
├── requirements.txt                  # Python依赖
└── README.md                         # 本文档
```

---

## 快速开始

### 0. PyPI 安装（发布后）

```bash
pip install smpas

# 一键下载模型（YOLO + SAM）
smpas-download-models

# 启动 Web（默认数据目录：~/.smpas）
smpas-web
```

注意：SAM 需要单独安装（PyPI 不支持直链依赖）：

```bash
pip install git+https://github.com/facebookresearch/segment-anything.git
```

模型与数据默认目录：
- `~/.smpas/models`：放置 `yolo_mushroom.pt` 和 `sam_vit_b.pth`
- `~/.smpas/data`：放置待分析图片（可选）

也可以用环境变量指定路径：

```bash
export SMPAS_MODELS_DIR=/path/to/models
export SMPAS_DATA_DIR=/path/to/data
smpas-web
```

如需修改默认根目录：

```bash
export SMPAS_HOME=/custom/smpas_home
smpas-web
```

### 1. 环境配置

```bash
# 创建虚拟环境
conda create -n mushroom_apriltag python=3.10
conda activate mushroom_apriltag

# 安装PyTorch（CUDA版本）
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

# 安装其他依赖
pip install -r requirements.txt

# 安装SAM
pip install git+https://github.com/facebookresearch/segment-anything.git

# 安装AprilTag
pip install apriltag
```

### 2. 下载模型文件

推荐使用一键下载命令（会创建 `~/.smpas/models`）：

```bash
smpas-download-models
```

如果手动放置模型，请放到 `~/.smpas/models/`：

- `yolo_mushroom.pt`
- `sam_vit_b.pth`

### 3. 准备数据

将包含AprilTag的香菇图片放入 `data/raw_images/` 目录。

**数据要求**：
- 图片中包含一个AprilTag tag16h5 (ID: 25)
- AprilTag外部黑框边长：37.58mm（精确已知）
- 尽量垂直俯拍（角度差异<10°最佳）
- 推荐分辨率：2000×2000像素以上

### 4. 运行分析

```bash
cd src

# 批量处理（默认模式）
python pipeline.py ../data/raw_images --output-dir ../outputs

# 启用并行处理（推荐，多香菇加速）
python pipeline.py ../data/raw_images \
  --output-dir ../outputs \
  --parallel \
  --max-workers 4

# 自定义AprilTag尺寸
python pipeline.py ../data/raw_images \
  --apriltag-size 37.58  # AprilTag的最大黑色正方形边长（毫米）
```

### 5. 查看结果

- **CSV结果**：`outputs/analysis_results.csv`
- **统计报告**：`outputs/analysis_report.txt`
- **可视化图像**：`outputs/visualizations/`

---

## 输出结果说明

### CSV表格字段

| 字段 | 说明 | 单位 |
|------|------|------|
| filename | 文件名 | - |
| apriltag_detected | AprilTag检测成功 | True/False |
| px_per_mm | 像素/毫米比例 | px/mm |
| mushroom_id | 香菇编号（同一图多个香菇）| - |
| detection_confidence | YOLO检测置信度 | 0-1 |
| diameter_px | 菌盖最大直径（像素）| px |
| diameter_mm | 菌盖最大直径（毫米）| mm |
| cap_area_px | 菌盖面积（像素）| px² |
| cap_area_mm2 | 菌盖面积（毫米）| mm² |
| crack_area_px | 花纹面积（像素）| px² |
| crack_ratio | 开裂比 | 0-1 |
| crack_ratio_percent | 开裂比百分比 | % |
| grade | 等级评定 | 一级-五级 |
| v_threshold | V通道Otsu阈值 | 0-255 |
| s_threshold | S通道Otsu阈值 | 0-255 |

### 等级评定标准

| 等级 | 开裂比范围 | 描述 |
|------|-----------|------|
| 一级 | 0-20% | 花纹较少 |
| 二级 | 20-40% | 花纹适中 |
| 三级 | 40-60% | 花纹较多 |
| 四级 | 60-80% | 花纹丰富 |
| 五级 | 80-100% | 花纹非常丰富 |

---

## 高级用法

### 单张图片分析

```python
from integrated_analyzer import IntegratedMushroomAnalyzer

# 创建分析器
analyzer = IntegratedMushroomAnalyzer(
    yolo_model_path='../models/yolo_mushroom.pt',
    sam_model_path='../models/sam_vit_b.pth',
    apriltag_size_mm=37.58,
    device='cuda',
    enable_parallel=True,  # 启用并行处理
    max_workers=4
)

# 分析单张图片
result = analyzer.analyze_image(
    'path/to/image.jpg',
    visualize=True
)

# 查看结果
print(f"检测到 {result['mushroom_count']} 个香菇")
for mushroom in result['mushrooms']:
    print(f"直径: {mushroom['diameter_mm']:.2f}mm")
    print(f"开裂比: {mushroom['crack_ratio_percent']:.2f}%")
    print(f"等级: {mushroom['grade']}")
```

### 测试单个模块

```bash
# 测试AprilTag检测
python apriltag_calibration.py ../data/raw_images/test.jpg

# 测试直径计算
python diameter_calculator.py <mask_path>

# 测试开裂比分析
python crack_analyzer.py <image_path> <mask_path>
```

---

## 性能优化说明

### ROI处理哲学

本项目采用**分层ROI处理架构**，显著减少计算量：

```
原始图像（4000×3000 = 1200万像素）
    ↓
并行分解：
    ├─ AprilTag检测 → 只处理Tag区域（~100×100 = 1万像素）
    │      ↓
    │   计算px/mm标定参数
    │
    └─ YOLO检测香菇 → 快速全图扫描（~50ms）
           ↓
      裁剪3个香菇ROI（每个~500×500 = 25万像素）
           ↓
      并行处理每个ROI：
           ├─ 香菇1：SAM分割 → 直径 → 开裂比
           ├─ 香菇2：SAM分割 → 直径 → 开裂比
           └─ 香菇3：SAM分割 → 直径 → 开裂比

总计算量：1万 + 3×25万 = 76万像素（减少94%）
```

### 性能对比

| 模式 | 处理方式 | 单图耗时 | 相对速度 |
|------|---------|---------|---------|
| 全图暴力 | SAM处理1200万像素 | ~10秒 | 1x |
| ROI串行 | SAM处理76万像素 | ~3秒 | 3.3x |
| ROI并行 | 3个ROI同时处理 | ~1秒 | **10x** |

### 并行处理建议

- **单个香菇**：无需并行
- **2-4个香菇**：启用并行，`max_workers=2`
- **5个以上**：启用并行，`max_workers=4`

---

## 常见问题

### Q1: AprilTag检测失败

**原因**：
- Tag尺寸太小（在图像中<50像素）
- 光照过暗或过曝
- 角度太大导致畸变严重

**解决**：
- 提高图像分辨率
- 打印更大的Tag（推荐10mm+）
- 垂直俯拍，减小角度

### Q2: 直径测量不准确

**原因**：
- AprilTag标定误差
- 透视畸变未校正
- 分割掩码不准确

**解决**：
- 检查Tag是否平整
- 确保Tag和香菇在同一平面
- 减小拍摄角度（<10°）

### Q3: 开裂比异常

**原因**：
- 光照不均匀
- 香菇颜色与通常不同
- 分割掩码错误

**解决**：
- 使用均匀光照
- 检查可视化图像的分割质量
- 调整HSV阈值（高级功能）

---

## 算法原理

### 1. AprilTag标定

```python
# 检测4个角点
corners = [左下, 右下, 右上, 左上]

# 计算边长
side_lengths = [底边, 右边, 顶边, 左边]
avg_side_px = mean(side_lengths)

# 计算比例
px_per_mm = avg_side_px / 3.76
```

### 2. 最大直径计算（旋转卡壳）

```python
# 提取轮廓并计算凸包
hull = ConvexHull(contour_points)

# 暴力搜索凸包上最远点对
max_dist = 0
for i in hull_vertices:
    for j in hull_vertices:
        dist = ||point[i] - point[j]||
        max_dist = max(max_dist, dist)

diameter_mm = max_dist / px_per_mm
```

### 3. 开裂比提取（HSV+Otsu）

```python
# HSV颜色空间转换
hsv = cv2.cvtColor(roi_image, cv2.COLOR_BGR2HSV)

# Otsu自适应阈值
v_threshold = otsu(V_channel[cap_mask])
s_threshold = otsu(S_channel[cap_mask])

# 花纹条件：高亮度 + 低饱和度
crack_mask = (V > v_threshold) AND (S < s_threshold)

# 开裂比
crack_ratio = crack_area / cap_area
```

---

## 许可证

MIT License - 详见 LICENSE 文件

---

## 致谢

- 基于原项目 `shiitake_mushroom` 的开裂比算法
- 使用 Meta AI 的 Segment Anything Model (SAM)
- 使用 Ultralytics 的 YOLOv8
- 使用 AprilTag 视觉标记系统

---

## 更新日志

### v1.0.0 (2025-01-24)
- ✨ 完全ROI处理架构，减少94%计算量
- ✨ AprilTag精确标定，支持3.76mm尺寸
- ✨ 旋转卡壳算法计算真实最大直径
- ✨ 可选并行处理，3倍速度提升
- ✨ 完整的批量处理和统计报告
