Dataset: add READMEs, organize scripts, update .gitignore

- 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
This commit is contained in:
kirl committed 2026-06-23 14:41:39 +08:00
1 parent 7867c3bfaf
commit a64690477a
43 files changed
+2691 -205

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
test/
train/
+75
View File
@@ -0,0 +1,75 @@
# CCPD_19K — 11类中国车牌数据集
> **以脚本为准**:生成逻辑以 `ICE_Dataset/scripts/build_ccpd_19k.py` 为准。
基于 CCPD 构建的 11 分类车牌数据集,涵盖蓝牌、绿牌及 9 种特殊车牌。
## 数据来源
| 来源 | 类型 | 采样数 | 说明 |
|------|------|--------|------|
| CCPD2019 | 蓝牌 (blue) | 5,000(随机) | 全蓝牌,从 341,369 张中随机抽取 |
| CCPD2020 | 绿牌 (green) | 5,000(随机) | 全绿牌,从 11,776 张中随机抽取 |
| CCPD_SPE | 特殊车牌 (9类) | 9,000(全部) | 9 类特殊车牌,每类 1,000 张 |
## 11 类车牌
| 序号 | 类别 | 目录名 | 说明 | 底板色 |
|------|------|--------|------|--------|
| 1 | 蓝牌 | `blue` | 普通小型汽车 | 蓝底白字 |
| 2 | 绿牌 | `green` | 新能源小型汽车 | 绿底黑字 |
| 3 | 警车 | `police` | 警用车牌 | 白底,末位"警"红字 |
| 4 | 军车 | `army` | 军车/武警 | 白底 |
| 5 | 港澳 | `gangao` | 港澳入出境 | 黑底,粤Z·XXXX港/澳 |
| 6 | 使馆旧版 | `shiguan_old` | 使馆车牌(旧版) | 黑底,"使"红字 |
| 7 | 使馆新版 | `shiguan_new` | 使馆车牌(新版) | 黑底 |
| 8 | 领馆旧版 | `lingguan_old` | 领馆车牌(旧版) | 黑底,"领"红字 |
| 9 | 领馆新版 | `lingguan_new` | 领馆车牌(新版) | 黑底 |
| 10 | 教练车 | `coach` | 教练车牌 | 黄底,末位"学" |
| 11 | 新能源大型 | `new_energy` | 大型新能源 | 黄绿双拼,8位 |
## 目录结构
```
CCPD_19K/
├── train/ # 训练集 (90%, 17,100 张)
│ ├── blue/ # 4,500 张
│ ├── green/ # 4,500 张
│ ├── police/ # 900 张
│ ├── army/ # 900 张
│ ├── gangao/ # 900 张
│ ├── shiguan_old/ # 900 张
│ ├── shiguan_new/ # 900 张
│ ├── lingguan_old/ # 900 张
│ ├── lingguan_new/ # 900 张
│ ├── coach/ # 900 张
│ └── new_energy/ # 900 张
├── test/ # 测试集 (10%, 1,900 张)
│ ├── blue/ # 500 张
│ ├── green/ # 500 张
│ └── ... (同上 11 类)
└── README.md
```
## 划分方式
- 训练集:测试集 = 9:1
- 分层抽样(stratified):每类内部独立按 9:1 划分
- 随机种子:42(可复现)
## 总计
- 训练集:17,100 张
- 测试集:1,900 张
- **总计:19,000 张**
## 生成脚本
```bash
# 构建 CCPD_19K (从源数据采样)
python build_ccpd_19k.py
# 推理 → bbox拓展裁剪 → 角点重映射 → CCPD_19K_EXP_CUT
# 脚本位于 CCPD_19K_EXP_CUT/build_ccpd_19k_exp_cut.py
python ../CCPD_19K_EXP_CUT/build_ccpd_19k_exp_cut.py --full
```
+195
View File
@@ -0,0 +1,195 @@
#!/usr/bin/env python3
"""
Build CCPD_19K dataset from:
- CCPD2019 (all blue plates): random 5,000 images -> class "blue"
- CCPD2020 (all green plates): random 5,000 images -> class "green"
- CCPD_SPE (9 special plate types): all 9,000 images -> 9 classes
Output structure (under ICE_Dataset/CCPD_19K/):
train/
blue/ ~4500
green/ ~4500
police/ ~900
army/ ~900
gangao/ ~900
shiguan_old/ ~900
shiguan_new/ ~900
lingguan_old/ ~900
lingguan_new/ ~900
coach/ ~900
new_energy/ ~900
test/
(same 11 classes, ~10% each)
Split ratio: 9:1 (train : test), stratified by class.
"""
import os
import sys
import random
import shutil
from pathlib import Path
from collections import defaultdict
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
BASE_DIR = Path(r"C:\Users\Kirl\Desktop\ICEv2\ICE_Dataset")
CCPD2019_DIR = BASE_DIR / "CCPD" / "CCPD2019"
CCPD2020_DIR = BASE_DIR / "CCPD" / "CCPD2020"
CCPD_SPE_DIR = BASE_DIR / "CCPD_SPE"
OUTPUT_DIR = BASE_DIR / "CCPD_19K"
SEED = 42
TRAIN_RATIO = 0.9 # 9:1 split
# Number of images to sample from CCPD2019 / CCPD2020
N_CCPD2019 = 5000
N_CCPD2020 = 5000
# ---------------------------------------------------------------------------
# Step 1: Collect all images from CCPD2019 (blue plates)
# ---------------------------------------------------------------------------
print("=" * 60)
print("Step 1: Collecting CCPD2019 (blue) images ...")
ccpd2019_images = []
for jpg in CCPD2019_DIR.rglob("*.jpg"):
ccpd2019_images.append(jpg)
print(f" Found {len(ccpd2019_images)} total images")
random.seed(SEED)
sampled_2019 = random.sample(ccpd2019_images, min(N_CCPD2019, len(ccpd2019_images)))
print(f" Sampled {len(sampled_2019)} images")
# ---------------------------------------------------------------------------
# Step 2: Collect all images from CCPD2020 (green plates)
# ---------------------------------------------------------------------------
print("\nStep 2: Collecting CCPD2020 (green) images ...")
ccpd2020_images = []
for jpg in CCPD2020_DIR.rglob("*.jpg"):
ccpd2020_images.append(jpg)
print(f" Found {len(ccpd2020_images)} total images")
random.seed(SEED)
sampled_2020 = random.sample(ccpd2020_images, min(N_CCPD2020, len(ccpd2020_images)))
print(f" Sampled {len(sampled_2020)} images")
# ---------------------------------------------------------------------------
# Step 3: Collect all images from CCPD_SPE (9 special classes)
# ---------------------------------------------------------------------------
print("\nStep 3: Collecting CCPD_SPE (9 special plate classes) ...")
# The 9 CCPD_SPE class names (subdirectory names)
SPE_CLASSES = [
"police",
"army",
"gangao",
"shiguan_old",
"shiguan_new",
"lingguan_old",
"lingguan_new",
"coach",
"new_energy",
]
spe_images = defaultdict(list)
for jpg in CCPD_SPE_DIR.rglob("*.jpg"):
# Path like: .../CCPD_SPE/ccpd_base/police/xxx.jpg
# The class is the immediate parent directory name
parent_dir = jpg.parent.name
if parent_dir in SPE_CLASSES:
spe_images[parent_dir].append(jpg)
for cls in SPE_CLASSES:
print(f" {cls}: {len(spe_images[cls])} images")
total_spe = sum(len(v) for v in spe_images.values())
print(f" Total CCPD_SPE: {total_spe} images")
# ---------------------------------------------------------------------------
# Step 4: Build class -> file list mapping
# ---------------------------------------------------------------------------
print("\nStep 4: Building class mappings ...")
class_files = {}
# Blue plates from CCPD2019
class_files["blue"] = sampled_2019
# Green plates from CCPD2020
class_files["green"] = sampled_2020
# 9 special plate classes
for cls in SPE_CLASSES:
class_files[cls] = spe_images[cls]
# Validate
all_11_classes = ["blue", "green"] + SPE_CLASSES
print(f" 11 classes: {all_11_classes}")
for cls in all_11_classes:
print(f" {cls}: {len(class_files[cls])} images")
# ---------------------------------------------------------------------------
# Step 5: Stratified 9:1 train/test split and copy
# ---------------------------------------------------------------------------
print("\nStep 5: Splitting and copying files ...")
random.seed(SEED)
for cls in all_11_classes:
files = class_files[cls]
random.shuffle(files)
n_train = max(1, int(len(files) * TRAIN_RATIO))
train_files = files[:n_train]
test_files = files[n_train:]
# Create output directories
train_dir = OUTPUT_DIR / "train" / cls
test_dir = OUTPUT_DIR / "test" / cls
train_dir.mkdir(parents=True, exist_ok=True)
test_dir.mkdir(parents=True, exist_ok=True)
# Copy train files (handle duplicate filenames by adding suffix)
for src in train_files:
dst = train_dir / src.name
counter = 1
stem, suffix = dst.stem, dst.suffix
while dst.exists():
dst = train_dir / f"{stem}_{counter}{suffix}"
counter += 1
shutil.copy2(src, dst)
# Copy test files (handle duplicate filenames by adding suffix)
for src in test_files:
dst = test_dir / src.name
counter = 1
stem, suffix = dst.stem, dst.suffix
while dst.exists():
dst = test_dir / f"{stem}_{counter}{suffix}"
counter += 1
shutil.copy2(src, dst)
print(f" {cls}: train={len(train_files)}, test={len(test_files)}")
# ---------------------------------------------------------------------------
# Step 6: Summary
# ---------------------------------------------------------------------------
print("\n" + "=" * 60)
print("CCPD_19K dataset built successfully!")
print(f" Output: {OUTPUT_DIR}")
total_train = 0
total_test = 0
for cls in all_11_classes:
train_cnt = len(list((OUTPUT_DIR / "train" / cls).glob("*.jpg")))
test_cnt = len(list((OUTPUT_DIR / "test" / cls).glob("*.jpg")))
total_train += train_cnt
total_test += test_cnt
print(f" {cls:15s} train: {train_cnt:5d} test: {test_cnt:5d}")
print(f" {'TOTAL':15s} train: {total_train:5d} test: {total_test:5d}")
print(f" Grand total: {total_train + total_test}")
print("=" * 60)