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:
1 parent
7867c3bfaf
commit
a64690477a
43 files changed
+2691
-205
No files matched your search
@@ -0,0 +1,2 @@
|
||||
test/
|
||||
train/
|
||||
@@ -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
|
||||
```
|
||||
@@ -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)
|
||||
Reference in new issue
Block a user