card-recog-demo/docs/demo说明.md

206 lines
8.5 KiB
Markdown
Raw Normal View History

# 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而不是继续堆叠本仓库内的几何管线。