Search
Write a publication
Pull to refresh

Comments 4

Хотел в своё время с чем-то таким поэкспериментировать, да так руки и не дошли. По идее это что-то близкое к аугументации. Имеет смысл попробовать не только зашумление, но и всякие другие искажения - небольшие повороты, наклоны, изменение яркости, много там чего можно придумать. Но степень полезности искажений будет зависеть от конкретной дальнейшей задачи, конечно - смотря какие там могут встретиться искажения.

Спасибо за отзыв, я в данный момент неторопливо работаю над функцией искажений, чтобы можно было задавать различные параметры или использовать функции случайного распределения, чтобы датасет был более репрезентативным. На данный момент получается их поворачивать на случайный угол. Есть момент, что при повороте, меняется разрешение изображения ( что меня ввело в ступор), и я решил поворачивать сам бокс с текстом, помогло. Когда напишу функцию искажений, которой буду доволен, напишу об этом в продолжении к этой статье.

как сгенерировать датасет печатных букв с помощью .ttf файла и кода на Python

Идея, конечно, интересная, ее можно будет принять к сведению. Я тоже, сейчас, занимаюсь похожей темой, но меня интересует более полное решение следующей задачи: «Дана ссылка на канал с видео на Ютубе, нужно распознавать встроенные двуязычные субтитры на них, в данном случае, на французском и английском языках». На базе этих данных я буду готовить уроки для своей обучающей программы.

Хорошего и бесплатного решения, с помощью ИИ-сервисов, я не нашел, поэтому, пишу собственный скрипт на Питоне.

Здесь, я хочу обойтись без датасетов и обучения нейросетей. Все интересующие видео имеют фиксированные области для каждой строки с текстом и один и тот же шрифт, правда, разных размеров. Это позволяет выделить, построчно, весь текст, преобразовать его в бинарные матрицы и, затем, разделить символы по криволинейному контуру между ними. После чего, можно приступать к процедуре распознавания этих символов, на базе тех или иных метрик.

Да, приходится, вручную, устанавливать соответствие между символами и их ключевыми параметрами, но, это работа обозримая и я уже распознал, таким образом, несколько десятков строк из начала выбранного ролика.

Нюансы здесь в том, что одному символу может соответствовать некоторое множество параметров, которые надо, вручную, прописывать в моей функции выбора. Со временем, подумаю, как этот процесс автоматизировать, а, пока, неплохо и так.

Соответственно, мне не нужно «зашумлять» исходные символы. Вполне хватает естественных дефектов. Изредка, встречаются артефакты, связанные с выбором порогового значения для лямбда-функции, участвующей в создании бинарных матриц.

Вот и пришлось воспользоваться вашим кодом!

Дело в том, что мой подход, основанный на использовании ключевых метрик шрифта – вполне хорош, но требует ручного «обучения» функции выбора, в моем скритпе распознавания встроенных субтитров видео.

Ваша идея предполагает воспользоваться ttf-шрифтами из операционной системы. Проблема была в том, что нужно было выяснить какой шрифт используется в интересующих видео и скачать его. Для распознавания шрифта есть сервис https://www.myfonts.com/pages/whatthefont . Он выдал, по изображению шрифта его название 'Cooper Black Regular.ttf'.

Короче, фонт определен, найден и загружен. Проверил соответствие в Ворде – один в один, если использовать размер шрифта – 45 и режим – bold.

Далее, чтобы сгенерировать эталонные символы – использовал ваш скрипт, немного переделав его. Потом, собираюсь сравнивать матрицы символов из видео с полученными образцами.

Здесь ваш код (модифицированный)
#====================================================================================================
# exec(open('DatasetGenerator.py', encoding='utf-8').read())
# DatasetGenerator.py - Генератор бинарных матриц символов для заданного шрифта
#====================================================================================================

#====================================================================================================
# Используемые библиотеки Питона
#====================================================================================================

from PIL import Image, ImageDraw, ImageFont, ImageFilter
import os
import csv
from glob import glob
import numpy as np

#====================================================================================================
# Глобальные константы
#====================================================================================================

_OutFolder = 'Data'

_FontName = 'Cooper Black Regular.ttf'  # 'Cooper Black Italic.otf'  # Наименование шрифта (может быть 'Cooper Black Regular_0.ttf')
_FontSize = 72  # 45  # Размер шрифта
_ImageSize = (88, 88)  # Размер выходного изображения
_BGColor = 'white'  # (255, 255, 255)  # Белый фон
_TextColor = 'black'  # (0, 0, 0)  # Черный цвет текста

# Список символов шрифта
_FontChars = list("ABCDEFGHIJKLMNOPQRSTUVWXYZÉÀÈÙÂÊÎÔÛÄËÏÖÜŸÇÆŒabcdefghijklmnopqrstuvwxyzéàèùâêîôûäëïöüÿçæœ.,:;!?'«»()"+'"')

#====================================================================================================
# CreateCharImage() - Создает эталонное изображение символа
#====================================================================================================
def CreateCharImage(BaseFont, Char, slant=1.0):
	# Создаем основное изображение
	image = Image.new('RGB', _ImageSize, _BGColor)
	draw = ImageDraw.Draw(image)

	# Рисуем текст с наклоном
	x = 0  # (image.width - text_width) / 2
	y = 0  # (image.height - text_height) / 2

	draw.text((x,y), Char, font=BaseFont, fill=_TextColor)  #, stroke_width=2, stroke_fill='red')

	return image
# CreateCharImage()

#====================================================================================================
# Processing() - Обработка данных
#====================================================================================================
def Processing() :	
	# Загружаем шрифт
	try:
		BaseFont = ImageFont.truetype(_FontName, _FontSize)		
	except OSError as e:
		print(f'Ошибка загрузки шрифта: {_FontName}')
		print(e)
		return
	# try

	# Если каталог для данных не существует, то пытаемся создать его
	if(not Path(_OutFolder).exists()) :
		# Пытаемся создать каталог для данных
		os.makedirs(_OutFolder, exist_ok=True)

		# Проверяем, созадан ли каталог?
		if(not Path(_OutFolder).exists()) :
			print(f'Каталог: "{_OutFolder}" не созадан!')
			return
		# if(not Path(_OutFolder).exists())
	# if(not Path(_OutFolder).exists())

	#for Char in _FontChars :
	for i in range(len(_FontChars)) :
		Char = _FontChars[i]
		#print(i, ord(Char))
		
		# Создаем эталонное изображение символа
		Img = CreateCharImage(BaseFont, Char)

		# Умная бинаризация с сохранением особенностей букв, с добавление случайных вариаций
		#Img = SmartBinarize(Img)

		# Сохраняем изображение
		FileName = f'{_OutFolder}\\Char_{i:03d}.png'
		print(FileName)
		#file_path = os.path.join(_OutFolder, FileName)
		Img.save(FileName)
	# for i in ramge(len(_FontChars))
	# for Char in _FontChars

	# Завершение работы
	return	
# Processing()

#====================================================================================================
# Main() - Главная функция
#====================================================================================================
def Main() :
	# Обработка данных
	Processing()

	# Завершение работы
	return
# Main()

if __name__ == '__main__' : Main()

#====================================================================================================
#====================================================================================================
Sign up to leave a comment.

Articles