ThaiVecFont / data_utils /write_glyph_imgs.py
microhum's picture
rm dockerfile
024aa56
raw
history blame
7.21 kB
from PIL import Image
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import argparse
import numpy as np
import os
import multiprocessing as mp
from tqdm import tqdm
char_error = 0
def get_bbox(img):
img = 255 - np.array(img)
sum_x = np.sum(img, axis=0)
sum_y = np.sum(img, axis=1)
range_x = np.where(sum_x > 0)
width = range_x[0][-1] - range_x[0][0]
range_y = np.where(sum_y > 0)
height = range_y[0][-1] - range_y[0][0]
return width, height
def write_glyph_imgs_mp(opts):
"""Useing multiprocessing to render glyph images"""
charset = open(f"{opts.data_path}/char_set/{opts.language}.txt", 'r').read()
fonts_file_path = os.path.join(opts.ttf_path, opts.language)
sfd_path = os.path.join(opts.sfd_path, opts.language)
for root, dirs, files in os.walk(os.path.join(fonts_file_path, opts.split)):
ttf_names = files
# ttf_names = ['08343.aspx_id=299524532']
ttf_names.sort()
font_num = len(ttf_names)
charset_lenw = len(str(len(charset)))
process_nums = mp.cpu_count() - 1
font_num_per_process = font_num // process_nums + 1
def process(process_id, font_num_p_process):
for i in tqdm(range(process_id * font_num_p_process, (process_id + 1) * font_num_p_process)):
if i >= font_num:
break
fontname = ttf_names[i].split('.')[0]
# print(fontname)
if not os.path.exists(os.path.join(sfd_path, opts.split, fontname)):
continue
ttf_file_path = os.path.join(fonts_file_path, opts.split, ttf_names[i])
try:
font = ImageFont.truetype(ttf_file_path, int(opts.img_size*opts.FONT_SIZE), encoding="unic")
except:
print('cant open ' + fontname)
continue
fontimgs_array = np.zeros((len(charset), opts.img_size, opts.img_size), np.uint8)
fontimgs_array[:, :, :] = 255
flag_success = True
for charid in range(len(charset)):
# read the meta file
txt_fpath = os.path.join(sfd_path, opts.split, fontname, fontname + '_' + '{num:0{width}}'.format(num=charid, width=charset_lenw) + '.txt')
try:
txt_lines = open(txt_fpath,'r').read().split('\n')
except:
print('cannot read text file')
flag_success = False
break
if len(txt_lines) < 5:
flag_success = False
break # should be empty file
# the offsets are calculated according to the rules in data_utils/svg_utils.py
vbox_w = float(txt_lines[1])
vbox_h = float(txt_lines[2])
norm = max(int(vbox_w), int(vbox_h))
if int(vbox_h) > int(vbox_w):
add_to_y = 0
add_to_x = abs(int(vbox_h) - int(vbox_w)) / 2
add_to_x = add_to_x * (float(opts.img_size) / norm)
else:
add_to_y = abs(int(vbox_h) - int(vbox_w)) / 2
add_to_y = add_to_y * (float(opts.img_size) / norm)
add_to_x = 0
char = charset[charid]
array = np.ndarray((opts.img_size, opts.img_size), np.uint8)
array[:, :] = 255
image = Image.fromarray(array)
draw = ImageDraw.Draw(image)
try:
font_width, font_height = font.getsize(char)
except Exception as e:
print('cant calculate height and width ' + "%04d"%i + '_' + '{num:0{width}}'.format(num=charid, width=charset_lenw))
flag_success = False
break
try:
ascent, descent = font.getmetrics()
except:
print('cannot get ascent, descent')
flag_success = False
break
draw_pos_x = add_to_x
#if opts.language == 'eng':
thai_characters_long = ["ญ","ฎ","ฏ","ฐ"]
if char in thai_characters_long:
draw_pos_y = add_to_y + opts.img_size - ascent - descent - int((opts.img_size / 24.0) * (10.0 / 3.0))
else:
draw_pos_y = add_to_y + opts.img_size - ascent - int((opts.img_size / 24.0) * (10.0 / 3.0))
#else:
# draw_pos_y = add_to_y + opts.img_size - ascent - int((opts.img_size / 24.0) * (10.0 / 3.0))
draw.text((draw_pos_x, draw_pos_y), char, (0), font=font)
if opts.debug:
image.save(os.path.join(sfd_path, opts.split, fontname, str(charid) + '_' + str(opts.img_size) + '.png'))
try:
char_w, char_h = get_bbox(image)
# print(charid, char_w, char_h)
except Exception as e:
print("cannot get bbox")
print(e)
flag_success = False
break
# Detect large font
problem = []
if font_width > 59:
problem.append("width")
if font_height > 93:
problem.append("height")
if problem:
print(problem,fontname, charid, font_width, font_height, char_w, char_h)
flag_success = False
break
# Detect Small Font
if (char_w < opts.img_size * 0.15) and (char_h < opts.img_size * 0.15):
flag_success = False
break
fontimgs_array[charid] = np.array(image)
if flag_success:
np.save(os.path.join(sfd_path, opts.split, fontname, 'imgs_' + str(opts.img_size) + '.npy'), fontimgs_array)
else:
global char_error # Count char flag not success
char_error += 1
print("flag on", fontname, charid, 'imgs_' + str(opts.img_size) + '.npy', " Not Succeed")
processes = [mp.Process(target=process, args=(pid, font_num_per_process)) for pid in range(process_nums)]
for p in processes:
p.start()
for p in processes:
p.join()
def main():
parser = argparse.ArgumentParser(description="Write glyph images")
parser.add_argument("--language", type=str, default='eng', choices=['eng', 'chn', 'tha'])
parser.add_argument("--data_path", type=str, default='./Font_Dataset', help="Path to Dataset")
parser.add_argument("--ttf_path", type=str, default='../data/font_ttfs')
parser.add_argument('--sfd_path', type=str, default='../data/font_sfds')
parser.add_argument('--img_size', type=int, default=64)
parser.add_argument('--split', type=str, default='train')
parser.add_argument('--FONT_SIZE', type=float, default=1)
parser.add_argument('--debug', type=bool, default=False)
opts = parser.parse_args()
write_glyph_imgs_mp(opts)
if __name__ == "__main__":
main()