Spaces:
Running
Running
File size: 6,615 Bytes
39b5db1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | """Regenerate the bundled sample PDF and the README figure.
python scripts/make_assets.py
Writes:
assets/sample.pdf 2-page synthetic A4 document (text, table, chart)
assets/figure_overview.png source | partition | adjacency | exploded fragments
The figure is rendered from a real `generate_dataset` run on the sample with
the parameters below, so it shows exactly what the tool produces.
"""
from __future__ import annotations
import os
import sys
import numpy as np
from PIL import Image, ImageDraw
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT)
from src.inspection import ( # noqa: E402
_font,
make_preview,
reassemble,
render_adjacency,
render_partition,
)
from src.pipeline import generate_dataset # noqa: E402
SAMPLE = os.path.join(ROOT, "assets", "sample.pdf")
FIGURE = os.path.join(ROOT, "assets", "figure_overview.png")
PARAMS = {"dpi": 100, "n_pieces": 14, "noise_strength": 28.0, "noise_scale": 96.0,
"master_seed": 7, "lossy": False}
PARAGRAPH = (
"Fragments recovered from the archive box were numbered in the order they "
"were lifted, not in reading order. Each was photographed on a neutral "
"background before any attempt at reconstruction. Edge profiles, ruling "
"lines and ink density were logged per fragment so candidate joins can be "
"scored independently of content."
)
def make_sample_pdf(path: str) -> None:
import fitz
doc = fitz.open()
# Page 1: prose + table.
page = doc.new_page(width=595, height=842)
page.insert_text((56, 72), "Sample document - Dataset-Maker", fontsize=17, fontname="helv")
page.insert_text((56, 90), "Synthetic test page. Contents are placeholder text.",
fontsize=9, fontname="helv", color=(0.35, 0.35, 0.35))
page.draw_line((56, 100), (539, 100), color=(0, 0, 0), width=0.7)
y = 116
for n in range(5):
page.insert_text((56, y + 10), f"{n + 1}. Observation", fontsize=10.5, fontname="hebo")
page.insert_textbox(fitz.Rect(56, y + 16, 539, y + 86), PARAGRAPH,
fontsize=9.5, fontname="tiro")
y += 92
top = 600
cols = ["Fragment", "Width (mm)", "Height (mm)", "Edge type"]
rows = [["F-01", "62", "88", "torn"], ["F-02", "45", "71", "torn / cut"],
["F-03", "80", "39", "torn"], ["F-04", "58", "66", "folded"],
["F-05", "33", "52", "torn"]]
for r, row in enumerate([cols] + rows):
for c, cell in enumerate(row):
rect = fitz.Rect(56 + c * 121, top + r * 22, 56 + (c + 1) * 121, top + (r + 1) * 22)
page.draw_rect(rect, color=(0, 0, 0), width=0.5,
fill=(0.92, 0.92, 0.9) if r == 0 else None)
page.insert_textbox(rect + (5, 6, 0, 0), cell, fontsize=8.5,
fontname="hebo" if r == 0 else "cour")
page.insert_text((56, 760), "Table 1. Fragment dimensions (placeholder values).",
fontsize=8.5, fontname="tiro")
# Page 2: line chart + ruled notes area.
page = doc.new_page(width=595, height=842)
page.insert_text((56, 72), "Figure page", fontsize=15, fontname="helv")
x0, y0, x1, y1 = 80, 110, 520, 400
page.draw_rect(fitz.Rect(x0, y0, x1, y1), color=(0, 0, 0), width=0.8)
for k in range(1, 6):
yy = y0 + k * (y1 - y0) / 6
page.draw_line((x0, yy), (x1, yy), color=(0.8, 0.8, 0.8), width=0.4)
rng = np.random.default_rng(3)
for series, colour in ((0, (0.1, 0.3, 0.8)), (1, (0.8, 0.2, 0.1))):
vals = np.cumsum(rng.normal(0, 1, 30)) * 12 + (y0 + y1) / 2 + series * 40
pts = [(x0 + i * (x1 - x0) / 29, float(np.clip(v, y0 + 5, y1 - 5)))
for i, v in enumerate(vals)]
for a, b in zip(pts, pts[1:]):
page.draw_line(a, b, color=colour, width=1.4)
page.insert_text((80, 420), "Figure 1. Two synthetic series (random walk).",
fontsize=8.5, fontname="tiro")
for k in range(14):
yy = 470 + k * 24
page.draw_line((56, yy), (539, yy), color=(0.55, 0.65, 0.85), width=0.5)
page.insert_text((60, 490), "Notes:", fontsize=10, fontname="hebo")
doc.set_metadata({"producer": "Dataset-Maker scripts/make_assets.py",
"creationDate": "D:20240101000000Z", "modDate": "D:20240101000000Z"})
doc.save(path, garbage=4, deflate=True, no_new_id=True)
doc.close()
def exploded(torn, spread: float = 0.22) -> np.ndarray:
"""Fragments pushed outward from the page centre, on a dark canvas."""
H, W = torn.height, torn.width
pad = int(max(H, W) * spread)
canvas = np.full((H + 2 * pad, W + 2 * pad, 3), 40, dtype=np.uint8)
cx, cy = W / 2, H / 2
for p in torn.pieces:
h, w = p.mask.shape
px, py = p.x + w / 2, p.y + h / 2
dx = int((px - cx) * spread * 1.6) + pad
dy = int((py - cy) * spread * 1.6) + pad
region = canvas[p.y + dy:p.y + dy + h, p.x + dx:p.x + dx + w]
region[p.mask] = p.rgb[p.mask]
return canvas
def panel(img: np.ndarray, title: str, height: int) -> Image.Image:
im = Image.fromarray(img)
im = im.resize((round(im.width * height / im.height), height), Image.LANCZOS)
out = Image.new("RGB", (im.width, height + 34), (255, 255, 255))
out.paste(im, (0, 34))
ImageDraw.Draw(out).rectangle((0, 34, im.width - 1, height + 33), outline=(200, 200, 204))
ImageDraw.Draw(out).text((2, 8), title, fill=(24, 24, 27), font=_font(17))
return out
def main() -> None:
make_sample_pdf(SAMPLE)
run = generate_dataset(SAMPLE, source_name="sample.pdf", **PARAMS)
torn = run.pages[0]
pv = make_preview(torn, max_side=900)
n = len(torn.pieces)
panels = [
panel(reassemble(torn), "1 source page (A4 render)", 620),
panel(render_partition(pv, n), "2 partition + piece index", 620),
panel(render_adjacency(pv, n, torn.adjacency), "3 adjacency ground truth", 620),
panel(exploded(torn), "4 fragments, pulled apart from their offsets", 620),
]
gap = 18
fig = Image.new("RGB", (sum(p.width for p in panels) + gap * 3, panels[0].height),
(255, 255, 255))
x = 0
for p in panels:
fig.paste(p, (x, 0))
x += p.width + gap
fig.save(FIGURE, optimize=True)
r = run.reports[0]
print(f"wrote {SAMPLE} and {FIGURE}")
print(f"page 0: {r.n_pieces} fragments, {r.n_edges} adjacency pairs, "
f"partition={'ok' if r.is_partition else 'FAIL'}; params={PARAMS}")
if __name__ == "__main__":
main()
|