# 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
相机 / 相册"] --> 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`) | 大图最长边限制约 2560;JPEG 质量约 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,而不是继续堆叠本仓库内的几何管线。