grading_ocr.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # -*- coding: utf-8 -*-
  2. """
  3. best.pt 裁评级标签条 + PaddleOCR 识别分行文本
  4. 流程:
  5. 1. best.pt(yolo26) 在原图检测评级标签条 → 取置信度最高的框裁剪
  6. 2. 对裁出的标签条跑 PaddleOCR(use_doc_orientation_classify=True)
  7. 3. 输出:
  8. - crops/<原图名>.jpg: 裁出的标签条图
  9. - ocr_result.json: 每张图的 OCR 分行文本
  10. - ocr_summary.csv: 汇总表(文件名,评级框坐标,置信度,OCR分行文本)
  11. 运行环境: 先用 pytorch 环境跑裁剪, 再用 paddleocr 环境跑 OCR
  12. """
  13. import os
  14. import sys
  15. import json
  16. import csv
  17. import hashlib
  18. from pathlib import Path
  19. sys.stdout.reconfigure(encoding="utf-8")
  20. ROOT = "/home/martin/顾工交接/wzj/test" # 4个子目录 BGS/CGC/PSA/SGC
  21. OUT = "/home/martin/顾工交接/wzj/grading_ocr" # 输出目录
  22. BEST = "/home/martin/顾工交接/wzj/ultralytics/runs/detect/card_v1/weights/best.pt"
  23. FOLDERS = ["BGS", "CGC", "PSA", "SGC"]
  24. CONF = 0.25
  25. os.makedirs(OUT, exist_ok=True)
  26. os.makedirs(os.path.join(OUT, "crops"), exist_ok=True)
  27. # ============ 第一步: best.pt 裁剪 (pytorch 环境) ============
  28. print("[STEP1] best.pt 裁评级标签条 ...")
  29. sys.path.insert(0, "/home/martin/顾工交接/wzj")
  30. from modules.ultralytics_compat import import_yolo
  31. YOLO = import_yolo()
  32. model = YOLO(BEST, task="detect")
  33. crop_records = [] # [{file, true_label, box, conf, crop_path}, ...]
  34. total_imgs = 0
  35. for fld in FOLDERS:
  36. imgs = sorted(Path(os.path.join(ROOT, fld)).glob("*.jpg"))
  37. total_imgs += len(imgs)
  38. print(f" {fld}: {len(imgs)} 张")
  39. for imgp in imgs:
  40. name = imgp.name
  41. results = model.predict(str(imgp), conf=CONF, imgsz=640, verbose=False)
  42. box, conf_val = None, 0.0
  43. if results and results[0].boxes is not None and len(results[0].boxes) > 0:
  44. import numpy as np
  45. confs = results[0].boxes.conf.cpu().numpy()
  46. xyxy = results[0].boxes.xyxy.cpu().numpy()
  47. best_i = int(np.argmax(confs))
  48. conf_val = float(confs[best_i])
  49. box = tuple(float(v) for v in xyxy[best_i])
  50. # 裁剪
  51. import cv2
  52. img = cv2.imread(str(imgp))
  53. crop = None
  54. if box:
  55. x1, y1, x2, y2 = box
  56. h, w = img.shape[:2]
  57. x1i, y1i = max(0, int(x1)), max(0, int(y1))
  58. x2i, y2i = min(w, int(x2)), min(h, int(y2))
  59. if x2i > x1i and y2i > y1i:
  60. crop = img[y1i:y2i, x1i:x2i]
  61. if crop is None:
  62. crop = img # 未检测到则用原图
  63. crop_path = os.path.join(OUT, "crops", f"{fld}_{name}")
  64. cv2.imwrite(crop_path, crop)
  65. crop_records.append({
  66. "file": name,
  67. "true_label": fld,
  68. "box": box,
  69. "conf": round(conf_val, 4) if conf_val else None,
  70. "crop_path": crop_path,
  71. })
  72. print(f"[STEP1] 完成, 共处理 {total_imgs} 张, 裁剪图存于 {OUT}/crops/")
  73. # ============ 第二步: PaddleOCR 识别 (需要 paddleocr 环境) ============
  74. print("\n[STEP2] PaddleOCR 识别裁剪图 ...")
  75. print("提示: 此步骤需要在 paddleocr conda 环境运行:")
  76. print(" conda activate paddleocr")
  77. print(" python grading_ocr.py --ocr-only")
  78. print("\n当前脚本将只生成裁剪图, OCR 步骤请单独运行。")
  79. # 保存裁剪记录供 OCR 步骤使用
  80. with open(os.path.join(OUT, "crop_records.json"), "w", encoding="utf-8") as f:
  81. json.dump(crop_records, f, ensure_ascii=False, indent=2)
  82. print(f"裁剪记录已保存: {OUT}/crop_records.json")
  83. # ============ OCR 步骤(单独脚本) ============
  84. # 见下方 grading_ocr_step2.py