FontDNA-V2 / README.md
Kuba-cs's picture
Update README.md
8f92600 verified
|
Raw
History Blame Contribute Delete
3.83 kB
---
license: mit
library_name: onnx
pipeline_tag: image-feature-extraction
language:
- mul
inference: false
tags:
- onnx
- computer-vision
- font-recognition
- typography
- image-embeddings
- document-analysis
- multi-task
---
# FontDNA
**FontDNA** is an ONNX model for recognizing typography from **word-image crops**.
It returns a font embedding plus word-local typography predictions. Font family is not a fixed classifier: compare the embedding against embeddings of your own reference fonts.
## Model I/O
**Inputs**
- `img` β€” `float32`, shape `(B, 1, 40, W)`
- `cols` β€” `int64`, shape `(B,)`; real crop width divided by `8`
Word crops are grayscale, resized to height `40` while preserving aspect ratio. Width is aligned to multiples of `8` (max `320`). Scale pixels to `[0,1]`, then normalize each crop with:
```python
x = (x - x.mean()) / (x.std() + 1e-4)
```
**Outputs, in order**
| # | Output | Decode as |
|---|---|---|
| 0 | font embedding | L2-normalize, then use cosine similarity |
| 1 | style logits `[4]` | `sigmoid` β†’ `bold, italic, underline, strikethrough` |
| 2 | category logits `[5]` | `softmax` β†’ `serif, sans-serif, display, handwriting, monospace` |
| 3 | confidence logit | `sigmoid` |
| 4 | script logits `[14]` | `softmax` β†’ mapping below |
Script indices:
```text
0 latin 5 hangul 10 tamil
1 cyrillic 6 arabic 11 thai
2 greek 7 hebrew 12 armenian
3 han 8 devanagari 13 georgian
4 kana 9 bengali
```
Styles are **per word**. For example, one underlined word can still share the same font-family embedding/section as the surrounding regular words.
## Raw ONNX Runtime example
```python
import numpy as np
import onnxruntime as ort
session = ort.InferenceSession("glyphdna.onnx")
# img: preprocessed float32 array shaped (B, 1, 40, W)
# cols: int64 array shaped (B,), where cols[i] = real_width // 8
embedding, style_logits, category_logits, confidence_logits, script_logits = (
session.run(None, {"img": img, "cols": cols})
)
sigmoid = lambda x: 1 / (1 + np.exp(-np.clip(x, -60, 60)))
softmax = lambda x: np.exp(x - x.max(-1, keepdims=True)) / np.exp(
x - x.max(-1, keepdims=True)
).sum(-1, keepdims=True)
embedding = embedding / np.maximum(
np.linalg.norm(embedding, axis=1, keepdims=True), 1e-8
)
styles = sigmoid(style_logits)
categories = softmax(category_logits)
confidence = sigmoid(confidence_logits).reshape(-1)
scripts = softmax(script_logits)
# Example: first word
print("bold:", styles[0, 0])
print("italic:", styles[0, 1])
print("underline:", styles[0, 2])
print("strikethrough:", styles[0, 3])
print("category index:", categories[0].argmax())
print("script index:", scripts[0].argmax())
```
If your exported ONNX uses different tensor names, inspect them with:
```python
print([x.name for x in session.get_inputs()])
print([x.name for x in session.get_outputs()])
```
## Font matching
To recognize a font family, embed reference word renders from each candidate font with the same model and preprocessing. L2-normalize the vectors and rank candidates by cosine similarity. Combining several neighboring word embeddings is usually more reliable than trusting a single word, because some words contain few font-discriminative glyphs.
A standalone Python library for indexing fonts, segmenting images, clustering same-font sections, and preserving per-word formatting is planned separately and is expected to be released in a few weeks.
## Notes
- This model is **not OCR** and does not transcribe text.
- Exact font names come from your own reference/index collection.
- Bold, italic, underline, strikethrough, category, and script are predicted per word.
- Precompiled font indexes must use the same model weights and preprocessing.
## License
MIT.