Burned-in PHI images¶
BurnedInGenerator renders a synthetic name, date, and medical record number into the pixels of an image, and returns both the character-level spans and the pixel bounding boxes for each. It is the synthetic counterpart of screenshots and scans that have text burned into them, for training and smoke-testing image de-identification. See the overview for shared conventions.
Pillow is imported only when an image is rendered. Install it with pip install "openmed[multimodal]"; without it, generate raises ImportError, while importing openmed.training.synthetic still works.
These portable English examples request font_fallback=True explicitly. Missing fonts otherwise raise a typed error. The selected font must still cover every rendered character and support required shaping; see the font coverage guide for licensed script fonts.
Generate one image¶
from openmed.training.synthetic import BurnedInGenerator
generator = BurnedInGenerator(seed=3, font_fallback=True)
example = generator.generate("en")
print(example.image.size) # (640, 320)
print(example.text.splitlines()) # name, date, MRN, one per line
for box in example.gold_boxes:
print(box.label, box.bbox, box.text, box.start, box.end)
assert example.text[box.start:box.end] == box.text
gold_boxes (alias boxes) holds one BurnedInTextBox per label in BURNED_IN_LABELS (PERSON, DATE, ID_NUM). bbox is Pillow's half-open (x0, y0, x1, y1) pixel box, and start/end index into example.text. gold_spans carries the same offsets as the locale PHI SyntheticPhiSpan records. The language argument selects the locale used for the name and date text.
For a one-off example with default variation, use the helper:
from openmed.training.synthetic import generate_burned_in_example
example = generate_burned_in_example(
seed=3, language="en", canvas_size=(640, 320), font_fallback=True,
)
Layout controls¶
Without controls, background, fonts, font sizes, and positions are chosen deterministically from the seed. To pin them, pass exactly three values, in (PERSON, DATE, ID_NUM) order:
example = generator.generate(
"en",
positions=[(20, 20), (20, 80), (20, 140)], # top-left pixel of each box
font_sizes=[18, 18, 18],
background="solid",
)
print(example.gold_boxes[0].bbox)
backgroundis one ofBACKGROUND_MODES:solid,gradient,phantom.- Constructor pools default to
DEFAULT_CANVAS_SIZE(640 × 320),DEFAULT_FONT_SIZES(18, 22, 26) andDEFAULT_FONT_NAMES(three DejaVu fonts). Missing fonts are refused by default. Explicitfont_fallback=Truepermits checked fallback for the default font pool, including Pillow's bundled font when it covers the text. Missing glyphs or required shaping still refuse the render. - Invalid controls (wrong count, non-positive size, unknown background, text that cannot fit the canvas) raise
ValueError.
Training items¶
item = example.to_training_item()
print(sorted(item))
# ['image', 'is_synthetic', 'labels', 'language', 'metadata', 'pixel_boxes',
# 'synthetic_source', 'text']
The Pillow image stays in memory in the dictionary; saving it (for example item["image"].save("sample.png")) is up to the caller. metadata records the seed, background mode, canvas size, and contains_real_phi: False, plus font digests, license declarations and fallback provenance.
Seeds and determinism¶
Within the same provider, font and Pillow environment, the same seed and settings give the same text and boxes:
a = BurnedInGenerator(seed=3, font_fallback=True).generate("en")
b = BurnedInGenerator(seed=3, font_fallback=True).generate("en")
assert a.text == b.text and a.gold_boxes == b.gold_boxes
Known limits¶
- Exactly three labels (
PERSON,DATE,ID_NUM); no addresses, faces, barcodes, or handwriting. - Text is drawn horizontally with simple backgrounds. Real scans have noise, skew, compression, and layouts these images do not model.
- Values come from the locale PHI generator and Faker, so the default-date and Faker-version caveats apply here too. Rendered pixels can differ slightly between Pillow or font versions even when the seed is unchanged.
- The images are augmentation data, not clinical ground truth.