- Add README.md to all 16 dataset directories with script references - Centralize generation scripts under scripts/ with full README - Update .gitignore to cover all data directories, keep only metadata - Remove redundant CCPD/.gitignore (parent covers same rules) - Remove stale scripts/test/ (254MB pipeline residue) - Fix label parser reference: scripts are authoritative source of truth
127 lines
4.2 KiB
Python
127 lines
4.2 KiB
Python
"""
|
|
CCPD原始真图 全量 TRANS (GT顶点外接框 + 12%/18%外扩)
|
|
输出: ICE_Dataset/CCPD_REAL_TRANS/train/
|
|
全量 ~338K, 文件名 _mask_real_ 标记 (训练时屏蔽省位+城市位)
|
|
"""
|
|
import os, sys, cv2, shutil
|
|
import numpy as np
|
|
from pathlib import Path
|
|
|
|
ICEv2 = Path(r"C:\Users\Kirl\Desktop\ICEv2")
|
|
sys.path.insert(0, str(ICEv2 / "ICE_NNv2/ICE-OCR/script/tools"))
|
|
from dataset import parse_ccpd_filename, imread_unicode
|
|
|
|
CCPD_DIRS = [
|
|
ICEv2 / "ICE_Dataset/CCPD/CCPD2019",
|
|
ICEv2 / "ICE_Dataset/CCPD/CCPD2020",
|
|
]
|
|
OUT_DIR = ICEv2 / "ICE_Dataset/CCPD_REAL_TRANS/train"
|
|
EXPAND_NORMAL = 1.12
|
|
EXPAND_SMALL = 1.18
|
|
SMALL_BOX_W = SMALL_BOX_H = 16
|
|
MIN_PAD = 2
|
|
|
|
|
|
def process_one(full_path, stem):
|
|
"""GT顶点→外接框→12/18%外扩→裁切→顶点重映射→warp"""
|
|
img = imread_unicode(str(full_path))
|
|
if img is None:
|
|
return None
|
|
h, w = img.shape[:2]
|
|
|
|
parts = stem.split("-")
|
|
if len(parts) < 4:
|
|
return None
|
|
# GT顶点 (CCPD: br, bl, tl, tr)
|
|
verts = []
|
|
for v in parts[3].split("_"):
|
|
x, y = v.split("&")
|
|
verts.append([float(x), float(y)])
|
|
verts = np.float32(verts)
|
|
|
|
# 外接框
|
|
x1, y1 = verts[:, 0].min(), verts[:, 1].min()
|
|
x2, y2 = verts[:, 0].max(), verts[:, 1].max()
|
|
bw, bh = x2 - x1, y2 - y1
|
|
|
|
# 外扩
|
|
ef = EXPAND_SMALL if (bw < SMALL_BOX_W or bh < SMALL_BOX_H) else EXPAND_NORMAL
|
|
px = max(MIN_PAD, int(round(bw * (ef - 1.0) / 2.0)))
|
|
py = max(MIN_PAD, int(round(bh * (ef - 1.0) / 2.0)))
|
|
cx1 = max(0, int(x1) - px); cy1 = max(0, int(y1) - py)
|
|
cx2 = min(w, int(x2) + px); cy2 = min(h, int(y2) + py)
|
|
if cx2 <= cx1 or cy2 <= cy1:
|
|
return None
|
|
|
|
cropped = img[cy1:cy2, cx1:cx2]
|
|
|
|
# 顶点重映射到裁切坐标 + OpenCV顺序 (CCPD: br,bl,tl,tr → tl,tr,br,bl)
|
|
verts_crop = verts[[2, 3, 0, 1], :] - np.array([cx1, cy1])
|
|
verts_crop = verts_crop.astype(np.float32)
|
|
|
|
OW, OH = 192, 64
|
|
dst = np.float32([[0, 0], [OW - 1, 0], [OW - 1, OH - 1], [0, OH - 1]])
|
|
M = cv2.getPerspectiveTransform(verts_crop, dst)
|
|
return cv2.warpPerspective(cropped, M, (OW, OH))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Step 0: 清空
|
|
if OUT_DIR.exists():
|
|
shutil.rmtree(str(OUT_DIR))
|
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Step 1: 收集
|
|
print("[1/2] Scanning all CCPD...")
|
|
all_files = []
|
|
total = skipped = 0
|
|
for d in CCPD_DIRS:
|
|
for root, dirs, files in os.walk(str(d)):
|
|
for f in files:
|
|
if not f.lower().endswith(".jpg"):
|
|
continue
|
|
indices, plate = parse_ccpd_filename(f)
|
|
if indices is None:
|
|
skipped += 1
|
|
continue
|
|
total += 1
|
|
all_files.append((os.path.join(root, f), Path(f).stem, plate))
|
|
|
|
print(f" Valid: {total}, Skipped: {skipped}")
|
|
for prov in sorted(set(p[2][0] for p in all_files),
|
|
key=lambda p: -sum(1 for x in all_files if x[2][0] == p)):
|
|
cnt = sum(1 for x in all_files if x[2][0] == prov)
|
|
print(f" {prov}: {cnt}")
|
|
|
|
# Step 2: GT顶点 warp
|
|
print(f"\n[2/2] GT-vertex warp {len(all_files)} -> {OUT_DIR}...")
|
|
done = err = 0
|
|
for i, (full_path, stem, plate) in enumerate(all_files):
|
|
try:
|
|
warped = process_one(full_path, stem)
|
|
if warped is None:
|
|
err += 1
|
|
continue
|
|
|
|
# _mask_real_ 标记: 训练时屏蔽 pos0(省)+pos1(城市码)
|
|
out_name = f"{stem}_mask_real_{plate}_trans.jpg"
|
|
out_path = OUT_DIR / out_name
|
|
|
|
ret, enc = cv2.imencode(".jpg", warped, [cv2.IMWRITE_JPEG_QUALITY, 95])
|
|
if ret:
|
|
with open(str(out_path), "wb") as wf:
|
|
wf.write(enc.tobytes())
|
|
done += 1
|
|
else:
|
|
err += 1
|
|
except Exception as e:
|
|
err += 1
|
|
if err <= 3:
|
|
print(f" [!] {Path(full_path).name}: {e}")
|
|
|
|
if (i + 1) % 10000 == 0:
|
|
print(f" [{i+1}/{len(all_files)}] done={done}, err={err}")
|
|
|
|
print(f"\nDone! Saved: {done}, Errors: {err}")
|
|
print(f"Output: {OUT_DIR} ({len(list(OUT_DIR.glob('*.jpg')))} files)")
|