1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
| import os
import random
import string
import subprocess
from pathlib import Path
# ================== 配置参数 ==================
FONT_DIR = "fonts"
TEXTURE_DIR = "images"
SYNTHETIC_DIR = "output/image"
LABEL_FILE = "output/train.txt"
NUM_IMAGES = 50000
FONTS = [
"正双排方点阵289-6.otf"
]
TEXTURE_EXTS = ['.jpg', '.jpeg', '.png']
CLEAR_EXISTING = True
# ==============================================
def get_files_in_dir(directory, extensions):
if not os.path.exists(directory):
raise FileNotFoundError(f"目录不存在: {directory}")
lower_extensions = [ext.lower() for ext in extensions]
files = []
for f in os.listdir(directory):
file_path = Path(f)
if file_path.suffix.lower() in lower_extensions:
files.append(f)
if not files:
raise FileNotFoundError(f"在 {directory} 中未找到指定类型的文件。请检查字体文件是否存在且扩展名为 {extensions} (或其小写形式)。")
return [os.path.join(directory, f) for f in files]
def random_suffix(length=6):
chars = string.ascii_uppercase + string.digits + '-'
return ''.join(random.choices(chars, k=length))
def generate_text():
# 此函数生成的是原始的、带有空格的 OCR 目标文本
plate_number = ''.join(random.choices('0123456789', k=14))
return f"{plate_number} UT {random_suffix()}"
def main():
# 创建目录
os.makedirs(SYNTHETIC_DIR, exist_ok=True)
os.makedirs(os.path.dirname(LABEL_FILE), exist_ok=True)
# 清空已有文件(可选)
if CLEAR_EXISTING:
for f in os.listdir(SYNTHETIC_DIR):
fp = os.path.join(SYNTHETIC_DIR, f)
if os.path.isfile(fp):
os.remove(fp)
print(f"🧹 已清空 {SYNTHETIC_DIR}")
relative_font_paths = get_files_in_dir(FONT_DIR, ['.otf'])
font_paths_for_trdg = [os.path.abspath(p) for p in relative_font_paths]
texture_paths = get_files_in_dir(TEXTURE_DIR, TEXTURE_EXTS)
print(f"✅ 找到 {len(font_paths_for_trdg)} 个字体")
print(f"✅ 找到 {len(texture_paths)} 个背景纹理")
# --- 开始修改部分:处理文件名中的空格 ---
temp_label_file = "temp_labels.txt"
# 1. 生成原始的、带有空格的标签文本列表
original_labels_with_spaces = [generate_text() for _ in range(NUM_IMAGES)]
# 2. 创建一个映射,将带有下划线的文本(用于文件名)映射回原始带有空格的文本(用于真实标签)
underscore_to_original_map = {}
labels_for_trdg_temp_file = [] # 这个列表中的文本将会把空格替换为下划线
for label_with_spaces in original_labels_with_spaces:
# 替换空格为下划线,作为 TRDG 生成文件名时使用的文本
label_with_underscores = label_with_spaces.replace(' ', '_')
labels_for_trdg_temp_file.append(label_with_underscores)
underscore_to_original_map[label_with_underscores] = label_with_spaces
# 3. 将带有下划线的文本写入临时文件,供 TRDG 读取并作为文件名的一部分
with open(temp_label_file, 'w', encoding='utf-8') as f:
for label_for_filename in labels_for_trdg_temp_file:
f.write(label_for_filename + '\n')
print(f"📝 生成临时标签 (用于TRDG文件名,已将空格替换为下划线): {temp_label_file}")
# --- 结束修改部分 ---
# 构建 TRDG 命令(只生成图像)
cmd = [
"python", "-m", "trdg.run",
"-c", str(NUM_IMAGES),
"-i", temp_label_file, # TRDG 现在会从这个临时文件读取带下划线的标签
"--output_dir", SYNTHETIC_DIR,
"--background", "3", # 使用自定义背景
"--image_dir", os.path.abspath(TEXTURE_DIR),
"--name_format", "0", # TRDG 将使用临时文件中的标签直接命名文件
"--margin", "10", # 增加边距
"--blur", "2", # 轻微模糊
"--random_blur",
"--text_color", "#FFFFFF,#EEEEEE,#DDDDDD,#CCCCCC", # 更接近喷码灰白色
"--language", "en",
"--format", "40",
"--width", "720",
"--alignment", "1", # 左对齐
"--orientation", "0", # 水平文本
]
for font_file_path_abs in font_paths_for_trdg:
cmd.extend(["--font", font_file_path_abs])
print("🖼️ 正在生成合成图像...")
print(f"Executing TRDG command: {' '.join(cmd)}")
try:
# 为了更好地兼容性,为 subprocess.run 添加编码设置
subprocess.run(cmd, check=True, encoding='utf-8')
print("✅ 图像生成完成")
except subprocess.CalledProcessError as e:
print(f"❌ 生成失败: {e}")
print(f"命令执行失败,请检查上面打印的TRDG命令是否正确,以及您的TRDG环境。")
return
print("✅ 开始生成 PaddleOCR 标签文件...")
# 获取所有生成的图片。此时,这些图片的文件名已经包含下划线。
generated_files = [f for f in os.listdir(SYNTHETIC_DIR) if f.endswith('.jpg')]
if len(generated_files) == 0:
print(f"❌ 错误:在 {SYNTHETIC_DIR} 中未找到任何 .jpg 文件")
return
matched_count = 0
with open(LABEL_FILE, 'w', encoding='utf-8') as f:
for img_name in generated_files:
# 从文件名中提取带有下划线的文本部分 (例如: "123_UT_ABC_0.jpg" -> "123_UT_ABC")
if '_' in img_name:
text_part_from_filename_underscored = img_name.rsplit('_', 1)[0]
# 使用映射表,将带下划线的文本转换回原始带空格的标签文本
original_label_with_spaces = underscore_to_original_map.get(text_part_from_filename_underscored)
if original_label_with_spaces is None:
print(f"⚠️ 无法找到匹配的原始标签用于文件: {img_name}")
continue
# 构造图像路径,此时路径中文件名已是带下划线的
img_path = os.path.join("synthetic", img_name).replace("\\", "/")
# 写入 PaddleOCR 要求的格式:路径(无空格)\t标签(有空格)
f.write(f"{img_path}\t{original_label_with_spaces}\n")
matched_count += 1
else:
print(f"⚠️ 跳过无法解析的文件 (无下划线分隔符): {img_name}")
print(f"✅ 成功生成 {matched_count} 条标签到 {LABEL_FILE}")
print(f"📊 共找到 {len(generated_files)} 张图像,其中 {matched_count} 张已成功写入标签文件。")
# 可选:清理临时文件
if os.path.exists(temp_label_file):
os.remove(temp_label_file)
print(f"🗑️ 已清理临时文件: {temp_label_file}")
if __name__ == "__main__":
main()
|