# 卡牌匹配完全体框架 · 操作指南 > 本目录是「宝可梦卡牌匹配完全体」框架的**自包含可迁移包**:一张交易平台图(eBay 原图)进来, > 输出「匹配到的 card_id + 评级信息 + 三属性(编号/稀有度/元素)+ 入库判定」。 > 代码/文档/配置资产已在包内;**模型权重需按 `114模型资源清单.md` 用硬盘拷进 `models/`**。 > > 生成时间:2026-07-27。深入细节见 `docs/` 下各子系统专文,本文只讲**全局架构 + 怎么跑**。 --- ## 0. 一句话数据流 ``` eBay 原图 │ ├─【A】卡牌本体分割(★card_seg_v2, yolo26s-seg) → 4点透视矫正 → 正立 ── 得「正立卡面图」 │ ├─【B】双区级联检索(DINOv2-large 上半区召回 + 下半区重排) ─────────→ card_id + fusion/u/l 相似度 │ (查询图直接裁卡→letterbox→上下半区特征→全库检索) │ ├─【C】语种+方向判断(PaddleOCR 字符统计) ────────────────────────→ language(tcg us/jp/简中/繁中)+angle │ ├─【D】cat16 三属性(正立图): │ card_no(yolo26s_card_no检测+PP-OCRv6 rec-only+单次宽容) / rarity(YOLO26s 25类) / element(YOLO26s 13类) │ └─【E】评级卡区域(YOLO26s-seg 12类 → 裁评级框 → PaddleOCR) ───────→ 评级公司/分数/编号/签字分 │ ▼ 【入库精修算法】合并 A~E → 按规则分流 → 匹配入库结果.xlsx + 人工核验分类图 ``` 五个子系统各自独立、可单独跑;**入库精修算法**(`ebay_sync/_build_ruhku.py`)是把它们串起来做「确定入库 / 人工核验」判定的总闸。 --- ## 1. 本包目录结构 ``` 完整流程/ ├── 卡牌匹配完全体框架操作指南.md ← 本文(总纲) ├── 114模型资源清单.md ← 模型在114的路径 + 拷贝方法 ├── config.py ← 全局配置(模型路径已指向 models/) ├── models/ ← ★需自行拷入(见清单):.pth/.npy/.pt/.onnx/元数据 │ ├── modules/ ← 核心可复用模块 │ ├── yolo_detector.py # 卡牌检测裁切(onnx) │ ├── rectifier.py # 透视矫正 + 旋转正立 │ ├── feature_extractor_dual.py # ★双区 DINOv2-large 特征提取(建库/查询共用预处理) │ ├── vector_index.py # 向量检索 │ ├── ultralytics_compat.py # import_yolo() 规避命名空间遮蔽 │ ├── image_downloader.py / csv_reader.py / db_reader.py │ └── feature_extractor.py / grading_detector.py # (A4/card_v1 旧线,保留兼容) │ ├── scripts/ │ ├── cascade_match.py # ★双区级联(单图/自检索/pairs) │ ├── cascade_match_batch.py # ★双区级联批量(目录→csv+topk.json,入库用) │ └── build_gallery.py / match_transactions.py / test_single.py # (A4 旧线,参考) │ ├── ocr_judge.py / yolo_crop.py ← 【C】语种+方向(paddleocr / pytorch) ├── grading_ocr.py / step1_crop.py ← 【E】评级卡(paddleocr / pytorch) ├── parse_card_no.py ← 【归档】旧 card_no 五格式规则(勿再作最终 card_no) │ ├── ebay_sync/ ← 应用侧脚本(cat16三属性 + 入库算法 + ebay批量) │ ├── _build_ruhku.py # ★★入库精修总闸(合并+规则分流+xlsx) │ ├── _build_ruhku_html.py # ★可视化 HTML 生成 │ ├── _run_gm_test.py # ★服务器GPU三阶段(评级检测+双区匹配+评级OCR) │ ├── _step1_param.py / _grading_param.py # 评级脚本的薄包装(改路径调 main) │ ├── _run_lang_stage.py / _run_lang_for.py # ★语种消歧(仅对5.1那批跑OCR) │ ├── _pull_gallery_for.py # 拉 gallery 图(带下载校验+重传) │ ├── run_rectify_only_cat16.py # cat16 阶段0:裁卡+矫正+正立→rectified_cards │ ├── run_infer_from_rectified.py # cat16 阶段A:裁ROI+rarity/element(card_no 旧 OCR 段已废弃) │ ├── run_pixel_rarity_rule.py # cat16 阶段B:rarity 像素右侧规则(card_no 应改接新链路) │ ├── _rarity_boxes.py # rarity 多框+cx │ ├── ocr_card_no_step.py / _ocr_with_boxes.py / parse_card_no_ebay.py # 【归档】旧五格式 │ ├── infer_cat16_pipeline.py / run_full_rerun_cat16.py │ └── ebay_infer_stream.py / ebay_lang_judge.py / ebay_rematch.py / ... # ebay批量→ClickHouse │ ├── pokemon/(框架根,不在本包内时指向 wzj 根) │ ├── flat_card_no_detect.py # ★现役 card_no 检测裁剪(yolo26s_card_no conf=0.3) │ └── flat_card_no_ocr.py # ★现役 rec-only + 单次宽容 + 低分置空 │ ├── modules/card_no_leniency.py # ★现役宽容/格式判定(框架根 modules/) │ ├── assets/ │ ├── roi_box_cat16.json ← rarity/element 固定 ROI(card_no 不再用) │ └── grading_roi/ ← 评级卡 10 类 _roi_box.txt + OCR规则.md + 映射表.md │ └── docs/ ← 各子系统专文(深入细节) ├── 宝可梦整体流程框架详解.md (A/B/C 总览) ├── 卡牌区域匹配模型架构更新.md (A + cat16三属性 完整,含 card_no 新链路) ├── 卡牌区域OCR内容指南.md (★card_no 现役总览+合法格式) ├── 卡牌区域OCR_rec宽容政策.md (★card_no 唯一后处理规则) ├── 卡牌区域检测裁切与旋转正立流程.md (A 细节) ├── 语种判断逻辑说明.md (C) ├── 评级卡OCR评分提取完整流程.md (E) ├── 卡牌匹配入库算法核心更新点.md (★入库算法规则 + 1000张结果) └── ... ``` --- ## 2. 环境准备 两套 **互不兼容** 的 conda 环境(一台 GPU 机器上都装): | 环境 | 关键依赖 | 用于 | |---|---|---| | `pytorch` | torch 2.x+cu12x、ultralytics、transformers、numpy、opencv、Pillow | A 裁切矫正 / B 双区检索 / D 的 YOLO(含 card_no 检测) / E 的检测裁切 | | `paddleocr` | paddleocr==3.2.0 + paddlepaddle-gpu==3.2.0、hanzidentifier、pandas、openpyxl | C 语种 / E 的评级 OCR | | `paddleocr37` | paddleocr==3.7 + transformers + CPU torch | **D 的 card_no rec-only**(`PP-OCRv6_medium_rec`;3.2 环境无法按名加载 v6) | > 为什么拆环境:`ultralytics` 与 `paddleocr` 底层冲突;v6 rec 还需 3.7 环境。流程仍是「pytorch 出中间产物 → 切 OCR 环境 → 再合并」。 激活:`source ~/miniconda3/etc/profile.d/conda.sh && conda activate ` **GPU 注意**:114 是 2×RTX 5090。脚本 `_run_gm_test.py` 会自动挑**空闲显存最多**的一块; 若有其他训练占用,各阶段独立进程跑完即释放,峰值仅几 GB。给 `cascade_match_batch` 不要传 `--device 0` (`torch.device("0")` 报错),靠 `CUDA_VISIBLE_DEVICES` 隔离后自动用 cuda。 **模型**:按 `114模型资源清单.md` 把权重拷进 `models/`,用第 4 节自检命令确认齐全。 --- ## 3. 五大子系统(简述 + 专文指引) ### 【A】卡牌本体裁切 + 透视矫正 + 旋转正立 `modules/yolo_detector.py`(CardDetector) + `modules/rectifier.py`(CardRectifier)。 分割 mask→凸包 4 角点→护栏(valid_quad/has_perspective)→warpPerspective 拉正→按 OCR angle 正立。 → 产「正立卡面图」,是 D、C 的输入。细节见 `docs/卡牌区域检测裁切与旋转正立流程.md`。 ### 【B】双区级联检索匹配 ★核心 `scripts/cascade_match.py`(类 `DualCascadeMatcher`) + `modules/feature_extractor_dual.py`。 查询图→裁卡→letterbox 392→**上半区[0:196]** dinov2-large→CLS 1024维→L2→全库点积召回 Top-K(`CASCADE_TOP_K_RECALL=30`) → **下半区[196:392]** Layer3→对候选算相似度→`fusion=α·upper+(1-α)·lower`(`CASCADE_ALPHA=0.5`)重排→Top-1 card_id。 - 单图/自检索/版本消歧:`python scripts/cascade_match.py --self-test 500` / `--image <图>` / `--pairs ` - 批量(入库用):`python scripts/cascade_match_batch.py --image-dir <目录> --out-csv --top-n 5` → 出 `` + `.topk.json`(每候选带 fusion/upper/lower/master_card_no/**language**/card_name/series/img_filename) - 建库/查询必须**同模型同预处理**(feature_extractor_dual)。细节见 `docs/宝可梦整体流程框架详解.md §三`。 ### 【C】语种 + 方向判断 `yolo_crop.py`(pytorch 裁卡) → `ocr_judge.py`(paddleocr)。字符统计:假名≥10→tcg jp;cjk*3>latin→简/繁中(hanzidentifier);否则→tcg us。顺带出 angle(0/90/180/270)。细节见 `docs/语种判断逻辑说明.md`。 ### 【D】cat16 三属性(card_no / rarity / element) - **`card_no`(★2026-08-11 现役)**:正立全图 → `yolo26s_card_no`(conf=0.3,多框取最高 conf)→ 裁剪 → `PP-OCRv6_medium_rec`(**仅 rec**)→ `modules/card_no_leniency.py` 单次宽容 → 低分不合规置空。 脚本:`pokemon/flat_card_no_detect.py` + `pokemon/flat_card_no_ocr.py`。 文档:`docs/卡牌区域OCR内容指南.md` + `docs/卡牌区域OCR_rec宽容政策.md`。 空结果:**无编号**(无检测框 / rec 空)vs **模糊不可读**(有框但 rec_score≤0.9 且格式不合规)。 ~~旧:固定 ROI seq_left/seq_right + det+rec + 五格式猜号~~ → 归档,勿再作最终 card_no。 - `rarity`:固定 ROI `seq_left/seq_right` + YOLO26s 25 类;**像素右侧规则**(框中心 x 须在 card_no 检测区域右侧)。 - `element`:固定 ROI + YOLO26s 13 类(右上角能量图标)。 驱动:`run_rectify_only_cat16.py`(阶段0) → rarity/element 既有 Stage A/B;**card_no 改接新检测+rec 链路**。细节见 `docs/卡牌区域匹配模型架构更新.md`。 ### 【E】评级卡区域识别 `step1_crop.py`(pytorch, YOLO26s-seg 12类 → 裁评级框+透视拉直) → `grading_ocr.py`(paddleocr, 按 `assets/grading_roi/_roi_box.txt` 分框 OCR → grade_score/grade_name/cert_number/auto_score)。OCR 判「非评级卡」= 误检自动剔除。细节见 `docs/评级卡OCR评分提取完整流程.md`。 --- ## 4. 入库精修算法 ★★(把 A~E 串成「确定入库 / 人工核验」) 规则权威见 `docs/卡牌匹配入库算法核心更新点.md`。核心(`ebay_sync/_build_ruhku.py`): - **阈值**:`SIM_HI=0.50`(Top1 fusion≥0.5 高置信);`<0.5` → **图库需要更新的卡**(留空+存原图)。 - **card_no 消歧**:默认只用 Top1;当 Top2-5 有候选 fusion 与 Top1 差 `≤CLOSE(0.15)` 时触发—— 接近候选(含Top1)里 `master_card_no==det_card_no(现役 card_no 链路)` 唯一者采纳(**确定匹配·编号消歧**)。 - **规则5.1 语种消歧**:若 ≥2 候选同号无法定夺 → 对**这批**query 图跑语种OCR(`_run_lang_stage.py`,只此分支跑,不全量), 同号候选里只留与 query **同语种**者;唯一 → 采纳(**确定匹配·语种消歧**);仍 ≥2 → **多张卡牌编号相同**(留空+存图)。 - **规则5.2**:接近候选无一 card_no 命中 det → **未识别到相应编号**(留空+存图)。 - **评级卡**:OCR 判真的 → 原图+评级框另存 `评级区域\{原图,评级框}`;grade/cert 入 xlsx。 - **rarity/element** 入 xlsx,**不进 cards_master_v2**。 - **留空语义**:需人工核验的行,其 identity 字段(final_card_id/卡名/系列/语种/年份)留空(= 未确定正确匹配)。 **输出根**:`ebay_入库\人工核验\`(`匹配入库结果.xlsx` + 分类图片文件夹 + `可视化\匹配可视化.html`)。 **1000 张实测(2026-07-27)**:确定匹配 360 + 编号消歧 294 + 语种消歧 27 = **681(68.2%)**;图库需更新 122;多张同号 98;未识别 98;评级卡 250。 --- ## 5. 端到端运行(复现 1000 张联合测试) > 前提:`models/` 已就位;`ebay_sync/` 里脚本内嵌 114 凭据(paramiko),本地 Windows/Python 跑即可。 > 采样源 `test_images_cat16`(2000 张,数据集,不在包内;在 114 `ebay_sync/test_images_cat16/`)。 ```powershell cd 完整流程\ebay_sync # ① 服务器GPU三阶段(评级seg检测 + 双区匹配 + 评级OCR),拉回 _gm/n1000/ python _run_gm_test.py 1000 42 # ② 合并+分流(pass1,先出 5.1 的 id 清单) python _build_ruhku.py "_gm/n1000" "D:\顾工交接\wzj\ebay_入库\人工核验" --ids-only # ③ 只对 5.1 那批(约125张)判语种 python _run_lang_stage.py "D:\顾工交接\wzj\ebay_入库\人工核验\_multi_cardno_ids.txt" "_gm\n1000\_lang_result.csv" # ④ 合并+分流(pass2,带语种消歧,出最终 xlsx + 分类图) python _build_ruhku.py "_gm/n1000" "D:\顾工交接\wzj\ebay_入库\人工核验" --lang "_gm\n1000\_lang_result.csv" # ⑤ 可视化 HTML(query原图 + Top-5 gallery缩略图 + 评级框 + 判定/语种) python _pull_gallery_for.py "_gm/n1000/match_result.topk.json" "D:\顾工交接\wzj\ebay_入库\人工核验\可视化\gallery" python _build_ruhku_html.py "_gm/n1000" "D:\顾工交接\wzj\ebay_入库\人工核验\可视化" ``` > `cat16 三属性`本测试直接复用 `data_all/卡牌区域/infer_cat16_result_2000.xlsx`(1000⊂2000)。 > 若换新图集,需先跑 §3【D】的三阶段生成三属性,再进 `_build_ruhku.py`。 > ⚠ 写 xlsx 前先关掉 Excel 里的 `匹配入库结果.xlsx`(文件锁)。 **单独跑某子系统**见对应专文;只想验证双区检索通不通:`python scripts/cascade_match.py --self-test 200`。 --- ## 6. 关键脚本速查 | 想做的事 | 脚本 | 环境 | |---|---|---| | 双区自检索 sanity | `scripts/cascade_match.py --self-test N` | pytorch | | 交易图批量匹配→card_id | `scripts/cascade_match_batch.py` | pytorch | | 评级检测+裁框 | `step1_crop.py`(或 `ebay_sync/_step1_param.py` 包装) | pytorch | | 评级 OCR 提分 | `grading_ocr.py`(或 `_grading_param.py`) | paddleocr | | 语种判定 | `ocr_judge.py` / 入库用 `ebay_sync/_run_lang_for.py` | paddleocr | | cat16 三属性(生产) | `ebay_sync/run_pixel_rarity_rule.py` | pytorch+paddleocr | | 入库合并+分流 | `ebay_sync/_build_ruhku.py` | 本地(纯python) | | 联合测试三阶段 | `ebay_sync/_run_gm_test.py` | 本地→114 GPU | | 可视化 | `ebay_sync/_build_ruhku_html.py` | 本地 | --- ## 7. 已知局限 / 待办 - 匹配 Top1 对「同角色不同印刷版本」偶混淆——正是下半区 Layer3 + card_no/语种消歧要补的;仍有 ~10% 进「多张同号/未识别」需人工。 - rarity 训练样本不足,偶有误检;评级 12 类外的评级公司(GEM/HGA 等)会漏检(归 Other)。 - `match_transactions.py`(A4 单区)已被 `cascade_match_batch.py`(双区)取代,仅留作参考。 - 大模型/HF缓存需按 `114模型资源清单.md` 手工拷入 `models/`。 - 语种消歧只在 5.1 分支触发(省推理);如需全量语种,另跑 §3【C】。