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
@@ -45,8 +45,10 @@ from plate_number import (
|
||||
|
||||
# ── 车牌类型 ──
|
||||
PLATE_TYPES = [
|
||||
('blue', '蓝牌', generate_plate_number_blue),
|
||||
('green_car', '小新能源', lambda: generate_plate_number_blue(length=8)),
|
||||
('yellow', '教练车', generate_plate_number_yellow_xue),
|
||||
('green_truck','新能源', lambda: generate_plate_number_blue(length=8)),
|
||||
('green_truck','大新能源', lambda: generate_plate_number_blue(length=8)),
|
||||
('white', '警车', generate_plate_number_white),
|
||||
('white_army', '军车', generate_plate_number_army),
|
||||
('black', '港澳', generate_plate_number_black_gangao),
|
||||
@@ -113,7 +115,8 @@ def adjust_plate(plate_bgr, bg_color, h_shift, s_scale, v_scale):
|
||||
return plate_bgr.copy()
|
||||
|
||||
hue_ranges = {
|
||||
'yellow': (15, 50), 'green_truck': (40, 85),
|
||||
'yellow': (15, 50), 'green_truck': (40, 85), 'green_car': (40, 85),
|
||||
'blue': (90, 130),
|
||||
'white': (0, 180), 'white_army': (0, 180),
|
||||
'black': (0, 180), 'black_shi': (0, 180),
|
||||
}
|
||||
@@ -182,7 +185,7 @@ def update_display(*_args):
|
||||
(w + 10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.55, (0, 255, 200), 1)
|
||||
|
||||
# 类型标签
|
||||
cv2.putText(display, f"[{current_type_idx+1}/9] {label}",
|
||||
cv2.putText(display, f"[{current_type_idx+1}/{len(PLATE_TYPES)}] {label}",
|
||||
(10, display.shape[0] - 10),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (180, 180, 180), 1)
|
||||
|
||||
@@ -206,7 +209,8 @@ def save_params():
|
||||
'# Format: (h_shift, s_scale_percent, v_scale_percent)',
|
||||
'',
|
||||
'PLATE_COLOR_PROFILE = {']
|
||||
for bg_color in ['yellow', 'green_truck', 'white', 'white_army', 'black', 'black_shi']:
|
||||
for bg_color in ['yellow', 'green_truck', 'green_car', 'blue',
|
||||
'white', 'white_army', 'black', 'black_shi']:
|
||||
p = params.get(bg_color, {'h_shift': 0, 's_scale': 100, 'v_scale': 100})
|
||||
lines.append(f" '{bg_color}': ({p['h_shift']}, {p['s_scale']}, {p['v_scale']}),")
|
||||
lines.append('}')
|
||||
@@ -219,19 +223,26 @@ def save_params():
|
||||
|
||||
def on_key(key):
|
||||
global current_type_idx, synthetic_plate
|
||||
# keys: 1-9, 0(=10), -(=11) — 切换车牌类型
|
||||
idx = -1
|
||||
if ord('1') <= key <= ord('9'):
|
||||
idx = key - ord('1')
|
||||
if idx < len(PLATE_TYPES):
|
||||
current_type_idx = idx
|
||||
# 切换类型时复位 trackbar 到该类型已保存的参数
|
||||
bg_color = PLATE_TYPES[current_type_idx][0]
|
||||
p = load_params(bg_color)
|
||||
cv2.setTrackbarPos('H offset', 'Color Tuner', p['h_shift'] + 30)
|
||||
cv2.setTrackbarPos('S scale', 'Color Tuner', p['s_scale'])
|
||||
cv2.setTrackbarPos('V scale', 'Color Tuner', p['v_scale'])
|
||||
# 生成新车牌
|
||||
synthetic_plate, _, _ = generate_plate(current_type_idx)
|
||||
update_display()
|
||||
elif key == ord('0'):
|
||||
idx = 9
|
||||
elif key == ord('-'):
|
||||
idx = 10
|
||||
|
||||
if 0 <= idx < len(PLATE_TYPES):
|
||||
current_type_idx = idx
|
||||
# 切换类型时复位 trackbar 到该类型已保存的参数
|
||||
bg_color = PLATE_TYPES[current_type_idx][0]
|
||||
p = load_params(bg_color)
|
||||
cv2.setTrackbarPos('H offset', 'Color Tuner', p['h_shift'] + 30)
|
||||
cv2.setTrackbarPos('S scale', 'Color Tuner', p['s_scale'])
|
||||
cv2.setTrackbarPos('V scale', 'Color Tuner', p['v_scale'])
|
||||
# 生成新车牌
|
||||
synthetic_plate, _, _ = generate_plate(current_type_idx)
|
||||
update_display()
|
||||
elif key == ord('r') or key == ord('R'):
|
||||
bg_color = PLATE_TYPES[current_type_idx][0]
|
||||
params[bg_color] = {'h_shift': 0, 's_scale': 100, 'v_scale': 100}
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
# Format: (h_shift, s_scale_percent, v_scale_percent)
|
||||
|
||||
PLATE_COLOR_PROFILE = {
|
||||
'yellow': (-2, 150, 100),
|
||||
'green_truck': (0, 100, 100),
|
||||
'yellow': (0, 150, 150),
|
||||
'green_truck': (0, 100, 150),
|
||||
'green_car': (-4, 69, 92),
|
||||
'blue': (-7, 150, 150),
|
||||
'white': (0, 100, 100),
|
||||
'white_army': (0, 100, 100),
|
||||
'black': (0, 100, 100),
|
||||
|
||||
@@ -156,6 +156,16 @@ PLATE_TYPE_CONFIG = {
|
||||
'generator': lambda: generate_plate_number_blue(length=8),
|
||||
'description': '大型新能源'
|
||||
},
|
||||
'blue': {
|
||||
'bg_color': 'blue',
|
||||
'generator': generate_plate_number_blue,
|
||||
'description': '蓝牌小型汽车'
|
||||
},
|
||||
'green': {
|
||||
'bg_color': 'green_car',
|
||||
'generator': lambda: generate_plate_number_blue(length=8),
|
||||
'description': '小型新能源'
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -407,7 +417,7 @@ def match_plate_color(synthetic_plate: np.ndarray,
|
||||
color_cast = white_ref / ref_mean
|
||||
strength_map = {
|
||||
'white': 1.0, 'white_army': 1.0,
|
||||
'green_truck': 1.5,
|
||||
'blue': 1.0, 'green_car': 1.5, 'green_truck': 1.5,
|
||||
}
|
||||
strength = strength_map.get(bg_color, 2.0)
|
||||
|
||||
@@ -492,7 +502,8 @@ def fix_plate_bg_color(plate_bgr: np.ndarray, bg_color: str) -> np.ndarray:
|
||||
|
||||
# 色相范围
|
||||
hue_ranges = {
|
||||
'yellow': (15, 50), 'green_truck': (40, 85),
|
||||
'yellow': (15, 50), 'green_truck': (40, 85), 'green_car': (40, 85),
|
||||
'blue': (90, 130),
|
||||
'white': (0, 180), 'white_army': (0, 180),
|
||||
'black': (0, 180), 'black_shi': (0, 180),
|
||||
}
|
||||
@@ -741,11 +752,10 @@ def match_image_quality(result: np.ndarray,
|
||||
|
||||
_worker_pipeline = None
|
||||
|
||||
def _worker_init(plate_type, fast):
|
||||
def _worker_init(plate_type):
|
||||
"""进程初始化:每个 worker 启动时调用一次(加载字体、底板缓存)"""
|
||||
global _worker_pipeline
|
||||
_worker_pipeline = PlateSwapPipeline(plate_type=plate_type)
|
||||
_worker_pipeline._fast_mode = fast
|
||||
|
||||
|
||||
def _worker_process_single(args):
|
||||
@@ -791,9 +801,6 @@ class PlateSwapPipeline:
|
||||
font_dir = str(_GENERATOR_DIR / 'font_model')
|
||||
self.generator = MultiPlateGenerator(plate_model_dir, font_dir)
|
||||
|
||||
# 快速模式标志(多进程时由 _worker_process_single 设置)
|
||||
self._fast_mode = False
|
||||
|
||||
def generate_plate_number(self) -> str:
|
||||
"""生成随机特殊车牌号码"""
|
||||
return self.number_generator()
|
||||
@@ -864,7 +871,8 @@ class PlateSwapPipeline:
|
||||
# 不同底板色用不同下限,防止白底变灰、绿牌变亮
|
||||
clip_cfg = {
|
||||
'white': (0.5, 1.1), 'white_army': (0.5, 1.1),
|
||||
'green_truck': (0.4, 1.0),
|
||||
'blue': (0.5, 1.1),
|
||||
'green_truck': (0.4, 1.0), 'green_car': (0.4, 1.0),
|
||||
'yellow': (0.4, 1.0),
|
||||
'black': (0.3, 1.2), 'black_shi': (0.3, 1.2),
|
||||
}
|
||||
@@ -879,16 +887,15 @@ class PlateSwapPipeline:
|
||||
matched_plate = (matched_plate.astype(np.float32) * effective_ratio)
|
||||
matched_plate = np.clip(matched_plate, 0, 255).astype(np.uint8)
|
||||
|
||||
# ---- 8. 退化模拟(快速模式下跳过) ----
|
||||
if not self._fast_mode:
|
||||
# JPEG 极限压缩
|
||||
matched_plate = jpeg_compress(matched_plate, quality=2)
|
||||
# 降采样→升采样 模拟马赛克/像素化
|
||||
h_p, w_p = matched_plate.shape[:2]
|
||||
small = cv2.resize(matched_plate, (w_p // 4, h_p // 4), interpolation=cv2.INTER_LINEAR)
|
||||
matched_plate = cv2.resize(small, (w_p, h_p), interpolation=cv2.INTER_NEAREST)
|
||||
# 较强模糊
|
||||
matched_plate = cv2.GaussianBlur(matched_plate, (5, 5), 1.5)
|
||||
# ---- 8. 退化模拟 ----
|
||||
# JPEG 极限压缩
|
||||
matched_plate = jpeg_compress(matched_plate, quality=2)
|
||||
# 降采样→升采样 模拟马赛克/像素化
|
||||
h_p, w_p = matched_plate.shape[:2]
|
||||
small = cv2.resize(matched_plate, (w_p // 4, h_p // 4), interpolation=cv2.INTER_LINEAR)
|
||||
matched_plate = cv2.resize(small, (w_p, h_p), interpolation=cv2.INTER_NEAREST)
|
||||
# 较强模糊
|
||||
matched_plate = cv2.GaussianBlur(matched_plate, (5, 5), 1.5)
|
||||
|
||||
# ---- 9. 透视变换回贴 ----
|
||||
warped, plate_mask = warp_plate_back(
|
||||
@@ -903,7 +910,7 @@ class PlateSwapPipeline:
|
||||
|
||||
# ---- 12. 保存 ----
|
||||
basename = Path(filename).stem
|
||||
out_name = f"{basename}_{self.plate_type}_{new_plate_number}.jpg"
|
||||
out_name = f"{basename}__{self.plate_type}__{new_plate_number}.jpg"
|
||||
out_path = os.path.join(output_dir, out_name)
|
||||
_imwrite_unicode(out_path, final, [cv2.IMWRITE_JPEG_QUALITY, 95])
|
||||
|
||||
@@ -927,8 +934,7 @@ class PlateSwapPipeline:
|
||||
num_images: int = 500,
|
||||
preview: bool = False,
|
||||
seed: int = 42,
|
||||
workers: int = 1,
|
||||
fast: bool = False):
|
||||
workers: int = 1):
|
||||
"""
|
||||
批量处理 CCPD 图片目录。
|
||||
|
||||
@@ -939,7 +945,6 @@ class PlateSwapPipeline:
|
||||
preview: 是否保存调试中间结果
|
||||
seed: 随机种子
|
||||
workers: 并行进程数 (1=单进程, >1=多进程)
|
||||
fast: 快速模式 (跳过退化模拟步骤)
|
||||
"""
|
||||
random.seed(seed)
|
||||
np.random.seed(seed)
|
||||
@@ -969,8 +974,6 @@ class PlateSwapPipeline:
|
||||
print(f"目标生成数: {num_images}")
|
||||
print(f"输出目录: {output_dir}")
|
||||
print(f"并行进程: {workers}" + (" (多核加速)" if workers > 1 else ""))
|
||||
if fast:
|
||||
print(f"快速模式: 跳过退化模拟")
|
||||
print("-" * 60)
|
||||
|
||||
import time
|
||||
@@ -984,7 +987,7 @@ class PlateSwapPipeline:
|
||||
else:
|
||||
# 多进程模式
|
||||
success, failed = self._process_parallel(
|
||||
image_paths, output_dir, num_images, preview, workers, fast
|
||||
image_paths, output_dir, num_images, preview, workers
|
||||
)
|
||||
|
||||
elapsed = time.perf_counter() - t0
|
||||
@@ -1013,7 +1016,7 @@ class PlateSwapPipeline:
|
||||
return success, failed
|
||||
|
||||
def _process_parallel(self, image_paths, output_dir, num_images,
|
||||
preview, workers, fast):
|
||||
preview, workers):
|
||||
"""多进程并行处理(worker 复用 Pipeline,仅初始化一次)"""
|
||||
from multiprocessing import Pool, cpu_count
|
||||
n_procs = min(workers, cpu_count())
|
||||
@@ -1022,7 +1025,7 @@ class PlateSwapPipeline:
|
||||
|
||||
# 每个 worker 启动时加载一次 Pipeline(含字体、底板缓存)
|
||||
with Pool(n_procs, initializer=_worker_init,
|
||||
initargs=(self.plate_type, fast)) as pool:
|
||||
initargs=(self.plate_type,)) as pool:
|
||||
# 参数精简: (img_path, output_dir, preview_bool)
|
||||
args = [
|
||||
(p, output_dir, (preview and i < 10))
|
||||
@@ -1074,9 +1077,6 @@ def main():
|
||||
help='随机种子 (默认: 42)')
|
||||
parser.add_argument('--workers', type=int, default=1,
|
||||
help='并行进程数 (默认: 1, 建议设为CPU核心数)')
|
||||
parser.add_argument('--fast', action='store_true',
|
||||
help='快速模式:跳过退化模拟,速度提升约40%%')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
ccpd_dirs = [d.strip() for d in args.ccpd_dir.split(',') if d.strip()]
|
||||
@@ -1088,7 +1088,6 @@ def main():
|
||||
preview=args.preview,
|
||||
seed=args.seed,
|
||||
workers=args.workers,
|
||||
fast=args.fast,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user