Быстро создавайте сотни изображений шрифтов.

Давайте продолжим с того места, где мы остановились в последнем посте. Мы очистили аннотации JSON и экспортировали их в виде файла CSV. Теперь давайте снова загрузим файл CSV и отфильтруем их с заданными нами условиями и создадим изображения PNG, чтобы мы могли использовать изображения для обучения сверточных нейронных сетей.



Настройка каталога

Опять же, я рассматриваю этот пост как Блокнот Jupyter, поэтому, если вы хотите продолжить, откройте Блокнот Jupyter в своей среде. Вам также потребуется загрузить репозиторий Google Fonts Github и создать аннотации CSV. Мы рассмотрели все это в последнем посте, поэтому, пожалуйста, ознакомьтесь с ним первым.

Как видно из древовидной диаграммы ниже, репозиторий Google Fonts Github загружается в каталог input. Все файлы шрифтов хранятся в подкаталоге ofl, как он изначально настроен, и я не вносил в него никаких изменений. Я также настроил каталог notebook с блокнотом .ipynb (этот пост), а также с файлом аннотаций CSV.

.
├── input
│   ├── fonts
│   │   ...
│   │   ├── ofl
│   │   ...
│   ├── fonts-master.json
└── notebook
    └── google-fonts-ml
        ├── google-fonts-ml.ipynb
        └── google-fonts-annotaion.csv

Загрузить аннотации CSV

Сначала мы загрузим аннотацию CSV как pandas.DataFrame.

Посмотрите сводку данных

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

На момент написания статьи, например, существует 325 семейств шрифтов с засечками, 311 шрифтов без засечек и 204 семейства шрифтов с засечками. Однако количество шрифтов не совпадает с количеством файлов шрифтов, потому что аннотация CSV учитывает только семейства шрифтов и другие факторы, такие как вариативные шрифты и т. д.

Фильтрация шрифтов

Теперь давайте создадим условия для создания подгрупп шрифтов. Поскольку мы потратили время на создание красивой аннотации CSV, шрифты легко фильтровать в соответствии с нашими собственными критериями. Скажите, сколько шрифтов thin, regular и thai?

Причина, по которой мы sum(axis=1) после фильтрации, состоит в том, чтобы захватить несколько столбцов, если они соответствуют одному и тому же условию. Например, если мы фильтруем с помощью italic, будет включено несколько столбцов, таких как bolditalic, mediumitalic и т. д. Мы можем объединить несколько условий в логический объект Series с именем mask и передать его в наш объект DataFrame. Он вернет только те строки, которые соответствуют условиям. Мы используем & для выбора только тех шрифтов, которые соответствуют всем условиям.

Вот еще один — Давайте найдем шрифты, которые поддерживают chinese и sans-serif.

Я получаю обратно 3 шрифта, которые соответствуют критериям — NotoSansHK, NotoSansSC и NotoSansTC. По какой-то причине эти шрифты NotoSans не были включены в репозиторий Google Fonts на Github. Таким образом, вам придется загружать их вручную, если вам нужно их использовать.

Мы не хотим продолжать редактировать объект mask каждый раз, когда используем другой набор фильтров, поэтому мы создадим список со всеми фильтрами, которые хотим использовать, и просто переберем их. Эти строки на самом деле являются регулярными выражениями, и вы можете самостоятельно попробовать более сложную фильтрацию.

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

Некоторые предостережения

Прежде чем мы двинемся дальше, я хочу указать на некоторые проблемы, которые я обнаружил. Мы полагаемся на данные о шрифтах из аннотаций CSV, которые мы создали с помощью Google Fonts Developer API, но есть некоторые расхождения.

  • Во-первых, количество шрифтов, представленных в аннотациях, не совпадает с количеством загруженных нами файлов шрифтов.
  • Некоторые шрифты, которые не обозначены как latin, по-прежнему имеют латинский алфавит.
  • NotoSansTC присутствует в аннотации, но не включен в ZIP-архив. Вероятно, потому что некоторые языки, такие как китайский или корейский, имеют много символов, а файлы шрифтов становятся намного больше по сравнению с латинскими шрифтами. Это просто мое предположение…
  • Шрифт под названием Ballet — файл шрифта существует, но его нет в аннотации. Может быть еще несколько подобных случаев.
  • Имя папки, содержащей файлы шрифтов, в основном совпадает с именем самих шрифтов, но есть некоторые исключения. Например, шрифт с именем SignikaNegative находится в папке с именем signika.
  • Шрифт под названием BlackHanSans, очевидно, очень жирный, но указан как обычный.

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

Загрузить путь к файлу шрифта

Мы будем использовать glob для загрузки пути к шрифтам. Если вы хотите отфильтровать шрифты только по весам, таким как Regular, Bold, Thin, будет достаточно простой проверки имени файла, поскольку веса/стили уже являются частью имен файлов, но вы не сможете использовать другие аннотации, которые мы рассмотрели. например, языковые подмножества или категории.

number of font files in total:  8708

Фильтровать шрифты

Пришло время объединить разные части в единую функцию, которая будет принимать объект DataFrame и путь к файлам шрифтов, а затем использовать определяемые нами фильтры для возврата списка отфильтрованных путей шрифтов.

Чтобы описать, что делает функция — мы хотим посмотреть как на filtered_fontnames, так и на соответствующий путь к файлу и проверить, существует ли файл. Если это так, функция возвращает путь к файлу.

Из имен шрифтов мы можем получить имена файлов, чтобы мы могли загрузить каждый шрифт и позже сгенерировать изображения. Мы фильтруем шрифты по начертаниям, стилям, подмножествам и категориям, но имена файлов содержат только имена шрифтов и начертания/стили.

Несколько замечаний:

  • В зависимости от вашей ОС, вам может потребоваться задать фильтры с учетом регистра. Например, Bold, LightItalic могут работать, а bold, lightitalic — нет. Я использую Mac, и он нечувствителен к регистру. Вы также не можете комбинировать взаимоисключающие условия вместе, такие как фильтрация sans-serif и serif одновременно. Однако вы можете ввести регулярное выражение, чтобы создать более сложный фильтр.
  • Некоторые вариативные шрифты не выбраны (например, CrimsonPro, HeptaSlab), потому что они имеют другие соглашения об именах, чем другие. Я просто проигнорировал их, потому что их не так много, а вариативные шрифты, имеющие статические версии, доступны для поиска через фильтры.

Предварительный просмотр изображений шрифтов

Наконец-то пришло время увидеть шрифты, отображаемые в виде изображений.

Все вместе

Вот блок кода, который собирает все вместе. На этот раз все изображения будут сохранены в виде файлов PNG.

Вывод

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

Надеюсь, мой пост был вам полезен — дайте мне знать, если вы сделаете что-нибудь интересное со шрифтами!