card-recog-demo/docs/demo说明.md
a1518 ccf8eeb21d Initial commit: Flutter card recognition demo
Camera capture, corner detection/refinement, and preview crop pipeline for trading cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 20:17:32 -07:00

206 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Card Scan Demo 说明
> 对照《集换社_反编译分析报告》v3.23.15)与本仓库当前实现,说明 demo 定位、流水线与差异。
---
## 1. 背景:集换社里的「卡牌扫描」
集换社是 TCG 卡牌 **C2C 交易平台**(包名 `com.jihuanshe`),卡牌扫描只是完整业务中的一环,不是独立工具 App。
反编译报告里与扫描相关的关键结论:
| 项 | 集换社侧证据 |
|----|--------------|
| 入口 | `CardScanActivity` / `CardScanAlbumActivity` / `CaptureActivity` / `ScanActivity` |
| 相机 | CameraX`MetadataHolderService` 等) |
| 识别 | Google ML Kit`libmlkitcommonpipeline.so` ~8.4MB、`GraphicOverlay`、`MlKitInitProvider` |
| 裁剪 | uCrop`MCropActivity`)— 识别不佳时可手动纠偏后再跑 |
| 结果 | 匹配卡牌库 → `CardDetailActivity`(详情 / 价格)→ 购物车或上架 |
报告中的扫描流程可概括为:
```
相机 / 相册 → ML Kit 边框检测 →(可选)手动裁剪 → 匹配卡牌数据库 → 详情页
```
加固(爱加密)导致无法还原完整 Java/Kotlin 源码,上述链路主要来自 Manifest、Native 库与 Flutter 字符串等静态证据,**不是**可运行的源码级复刻。
本 demo **只复现「拍/选图 → 锁定卡边 → 裁剪纠偏」** 这一段视觉能力,不包含交易、匹配库、登录、支付等平台能力。
---
## 2. Demo 是什么
纯 Flutter 小应用(`carddex_demo` v2.0.0),竖屏暗色 UI。
**一句话**:拍照或相册选图 → 按 TCG 引导框裁切 → ML Kit 目标检测得到外接框 → 经典 CV 细化倾斜四边形 → 透视 / 轴对齐裁剪 → 预览结果。
**明确不做**
- 实时预览帧上的检测(拍摄页只有引导框)
- 卡牌身份识别 / 图库检索 / 价格
- 打包自研或从 APK 抽取的 TFLite 模型(早期方案已废弃)
- 集换社业务订单、IM、拍卖、仓储等
---
## 3. 与集换社扫描链路的对照
| 维度 | 集换社(反编译推断) | 本 Demo |
|------|----------------------|---------|
| 形态 | 交易 App 内嵌模块Native Activity | 独立 Flutter Demo |
| 采集 | CameraX + 相册 Activity | `camera` + `image_picker` |
| 检测时机 | 报告描述含实时预览标注(`GraphicOverlay` | **仅静帧**:进入预览页后跑一次 |
| 检测引擎 | Google ML Kit | 同为 Google ML Kit Object Detection |
| 边框形态 | 报告侧重 AABB + Overlay细节不可见 | AABB → 可选倾斜四边形细化 |
| 裁剪纠偏 | uCrop 手动为主 | 自动透视 / 轴对齐裁剪(无手动 uCrop |
| 下游 | 匹配卡库 → 详情 / 交易 | **无**:只展示锁定框与裁切图 |
| 架构上下文 | Native + Flutter Hybrid + 大量 SDK | 单应用、无后端、无加固 |
技术选型上demo 与集换社扫描模块最接近的一点是:**都用 ML Kit 做卡牌区域定位,而不是卡牌分类识别**。定位成功后集换社走业务匹配demo 停在图像几何处理。
早期仓库内的 `carddex_flutter_demo_plan.md` 曾计划复刻 CardDex 的本地 `detect.tflite`;当前实现已改为 ML Kit与集换社扫描栈更一致也避免依赖 APK 内模型资产。
---
## 4. 工程结构
```
lib/
├── main.dart # 入口、竖屏、暗色主题
├── screens/
│ ├── capture_screen.dart # 相机预览 + 引导框(无 ML
│ └── preview_screen.dart # 检测 / 细化 / 裁剪 / 展示
├── services/
│ ├── card_detector.dart # ML Kit 静帧检测 + 选框 + 调用细化
│ ├── card_corner_refiner.dart # Otsu / 连通域 / 最小外接四边形
│ └── card_cropper.dart # 透视或轴对齐裁剪,贴合 63:88
└── widgets/
├── guide_overlay.dart # 拍摄页暗角 + 白框
└── guide_frame.dart # 引导框几何(含 BoxFit.cover 映射)
```
依赖(与相机 / 图像相关):
| 包 | 作用 |
|----|------|
| `camera` | 后置预览与拍照 |
| `image_picker` | 相册 |
| `google_mlkit_object_detection` | 静帧目标检测 |
| `image` | 解码、模糊输入、透视 `copyRectify`、JPEG |
| `path_provider` | 引导裁切临时文件 |
`assets/` 为空:模型由 ML Kit 插件运行时提供,不随 App 打包自定义 `.tflite`
---
## 5. 用户流程
```mermaid
flowchart LR
A["CaptureScreen<br/>相机 / 相册"] --> B["PreviewScreen"]
B --> C["按引导框裁切全图"]
C --> D["ML Kit 静帧检测"]
D --> E["经典 CV 角点细化"]
E --> F["透视 / AABB 裁剪"]
F --> G["展示锁定框 + 结果图"]
G --> H["重新拍摄 → pop"]
```
| 页面 | 职责 |
|------|------|
| **CaptureScreen** | 后置相机、`ResolutionPreset.high`、引导遮罩、快门 / 相册 / 翻转。生命周期:切后台释放、回前台重建。 |
| **PreviewScreen** | 全部视觉处理与结果 UI绿框锁定、置信度 / 标签、裁切图、重拍)。 |
导航为一次 `Navigator.push`,无路由库、无状态管理包。
---
## 6. 处理流水线(实现细节)
### 6.1 引导框
TCG 常见比例 **63:88**。框约占视口高度 62%、宽度 78%,垂直中心约在 46%。
- 拍照:用预览视口 + `BoxFit.cover` 反算到照片像素(`GuideFrame.inCoverImage`)。
- 相册:直接在图像坐标系算引导矩形(`GuideFrame.inImage`)。
进入检测前先按引导框裁掉框外区域,减小背景干扰(隐含前提:卡已大致落在框内)。
### 6.2 ML Kit 检测(`CardDetector`
- `DetectionMode.single`,开启分类与多目标。
- 输出 `CardBox`AABB、置信度、标签通用 COCO 类名,**不是**卡牌 ID
- `pickBest`:分数 = `0.4 * confidence + 0.6 * fillRatio`,丢弃填充比 ∉ `[0.04, 0.98]` 的框。
这是通用物体检测,不是「宝可梦 / 游戏王」专用模型;能锁边框即可,标签仅作调试信息。
### 6.3 角点细化(`CardCornerRefiner`
在 AABB 邻域做经典视觉,把轴对齐框尽量收成倾斜四边形:
1. 顶部略抬高、ROI 外扩
2. 灰度 → 模糊 → Otsu保证 AABB 中心为前景
3. 最大连通域(优先覆盖种子点)
4. 凸包 → 最小面积矩形 → TL→TR→BR→BL
5. 面积校验失败则退回 AABB成功则外扩并照顾卡头区域
### 6.4 裁剪(`CardCropper`
| 条件 | 行为 |
|------|------|
| 有倾斜四边形 | `copyRectify` 透视变换 → 竖向校正 → 贴合 63:88 |
| 仅有 AABB | 外扩约 6% 后轴对齐裁切并贴合比例 |
| 无检测框 | 按引导框中心区域裁切(`usedDetection: false` |
大图最长边限制约 2560JPEG 质量约 98。
---
## 7. 能力边界(相对报告中的产品能力)
反编译报告中的集换社扫描落点是 **「识别成功 → 匹配数据库 → 交易」**。本 demo 停在几何裁切:
```
集换社: 采集 → ML Kit → (uCrop) → 匹配库 → 详情/交易
本 Demo: 采集 → 引导裁切 → ML Kit → 角点细化 → 自动裁切 → 预览
▲ ▲
多出的本地几何步骤 无业务下游
```
因此:
- 能验证「静帧 + ML Kit 锁边 + 透视纠偏」是否够用做上架 / 鉴定前处理。
- **不能**验证卡牌检索准确率、价格、多卡桌面、强反光 / 极端角度等产品级指标。
- 检测失败时仍可按引导框出图,便于继续调试 UI但不代表识别成功。
---
## 8. 运行
```bash
export PATH="$HOME/flutter/bin:$PATH"
cd /Users/a1518/Desktop/project/card-dex-demo
flutter pub get
flutter run
```
Android `minSdk` 为 26需相机与媒体读取权限。真机效果明显优于模拟器。
---
## 9. 相关文档
| 文档 | 说明 |
|------|------|
| [集换社_反编译分析报告.md](../../apk_analysis/recognize/202607_analysis/集换社_反编译分析报告.md) | APK 静态分析(扫描相关见 §4.8、§6.2、§9.1 |
| [carddex_flutter_demo_plan.md](../carddex_flutter_demo_plan.md) | 早期 TFLite 方案(已与当前实现不一致,仅作历史参考) |
| [README.md](../README.md) | 最短运行说明 |
---
## 10. 小结
本 demo 是对照集换社扫描模块做的 **视觉前处理实验床**:同样依赖 Google ML Kit 做区域定位,但用 Flutter 实现「引导框 → 静帧检测 → 角点细化 → 透视裁切」闭环,刻意剥离交易与图库匹配。若后续要对齐集换社产品路径,需要在裁切结果之上另接卡牌检索 / 版本匹配 API而不是继续堆叠本仓库内的几何管线。