Camera capture, corner detection/refinement, and preview crop pipeline for trading cards. Co-authored-by: Cursor <cursoragent@cursor.com>
8.5 KiB
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. 用户流程
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 邻域做经典视觉,把轴对齐框尽量收成倾斜四边形:
- 顶部略抬高、ROI 外扩
- 灰度 → 模糊 → Otsu,保证 AABB 中心为前景
- 最大连通域(优先覆盖种子点)
- 凸包 → 最小面积矩形 → TL→TR→BR→BL
- 面积校验失败则退回 AABB;成功则外扩并照顾卡头区域
6.4 裁剪(CardCropper)
| 条件 | 行为 |
|---|---|
| 有倾斜四边形 | copyRectify 透视变换 → 竖向校正 → 贴合 63:88 |
| 仅有 AABB | 外扩约 6% 后轴对齐裁切并贴合比例 |
| 无检测框 | 按引导框中心区域裁切(usedDetection: false) |
大图最长边限制约 2560;JPEG 质量约 98。
7. 能力边界(相对报告中的产品能力)
反编译报告中的集换社扫描落点是 「识别成功 → 匹配数据库 → 交易」。本 demo 停在几何裁切:
集换社: 采集 → ML Kit → (uCrop) → 匹配库 → 详情/交易
本 Demo: 采集 → 引导裁切 → ML Kit → 角点细化 → 自动裁切 → 预览
▲ ▲
多出的本地几何步骤 无业务下游
因此:
- 能验证「静帧 + ML Kit 锁边 + 透视纠偏」是否够用做上架 / 鉴定前处理。
- 不能验证卡牌检索准确率、价格、多卡桌面、强反光 / 极端角度等产品级指标。
- 检测失败时仍可按引导框出图,便于继续调试 UI,但不代表识别成功。
8. 运行
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 静态分析(扫描相关见 §4.8、§6.2、§9.1) |
| carddex_flutter_demo_plan.md | 早期 TFLite 方案(已与当前实现不一致,仅作历史参考) |
| README.md | 最短运行说明 |
10. 小结
本 demo 是对照集换社扫描模块做的 视觉前处理实验床:同样依赖 Google ML Kit 做区域定位,但用 Flutter 实现「引导框 → 静帧检测 → 角点细化 → 透视裁切」闭环,刻意剥离交易与图库匹配。若后续要对齐集换社产品路径,需要在裁切结果之上另接卡牌检索 / 版本匹配 API,而不是继续堆叠本仓库内的几何管线。