Initial commit
This commit is contained in:
commit
900bdcc302
|
|
@ -0,0 +1,38 @@
|
|||
# Virtual environment
|
||||
venv/
|
||||
.venv/
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
|
||||
# Pipeline outputs (large, regenerated each run)
|
||||
output/
|
||||
uploads/
|
||||
|
||||
# Input newspaper PDFs (large binary data)
|
||||
*.pdf
|
||||
|
||||
# Scratch / diagnostic preview images
|
||||
_*.png
|
||||
pg-*.jpg
|
||||
q-*.jpg
|
||||
gp-*.jpg
|
||||
gq-*.jpg
|
||||
|
||||
# Generated HTML guides
|
||||
Extractor_Guide.html
|
||||
HOW_IT_WORKS.html
|
||||
|
||||
# Secrets / API keys (never commit)
|
||||
.keyenv
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# OS / editor cruft
|
||||
~$*
|
||||
.DS_Store
|
||||
*.swp
|
||||
.idea/
|
||||
.vscode/
|
||||
|
|
@ -0,0 +1,515 @@
|
|||
# Article-Cropping Strategy & Learnings (self-improving loop)
|
||||
|
||||
Living doc for the geometric article-cropping in `smart_extractor.py`
|
||||
(`cluster_all_article_blocks` → `crop_all_article_blocks`). Updated each loop iteration.
|
||||
|
||||
## Validation rules (NEVER violate)
|
||||
- **Never run `smart_extractor.py`** — it calls the paid Claude API. Validate ONLY with the
|
||||
geometric replay scripts: `_replay_all.py` (AJ), `_replay_namaste.py` (NT Siddipet),
|
||||
`_replay_jangaon.py` (NT Jangaon). These run the full cluster chain with NO API.
|
||||
- **Measure read-only BEFORE editing** (blast-radius of any new rule), then **re-validate after**.
|
||||
- **Baselines** (block counts) — keep stable unless an improvement is intentional & documented:
|
||||
- AJ: 12 / 18 / 14 / **21** (pg4 20→21: the ';'-delimiter fix recovered a real గజ్వేల్ dateline R12)
|
||||
- NT Siddipet: **11 / 23 / 20 / 25** (pg2 22→23: అంగన్వాడీ R127 split off the ప్రజావాణి section R110;
|
||||
pg3 19→20: పర్యావరణ R60 split off; both are the Type-2 paragraph_title-anchor split)
|
||||
- NT Jangaon: pg1 → **6**, pg2 → **18** (pg1 7→6: orphan photo R25 bound into its article;
|
||||
pg2 Type-2 splits: R65→3 కలెక్టర్/సుందరయ్య/పోస్టుమార్టం, R64→2 జాతీయరహదారి/ఉపసర్పంచుల, R97→2
|
||||
గుండెచికిత్స/మృతుడిపరామర్శ; + L89 court notice, F44 furniture)
|
||||
- Sakshi Jangaon: pg1 → **22**, pg2 → **20** (new paper, no line separators; all orphan PHOTOS
|
||||
bound to articles — 0 image orphans remain)
|
||||
|
||||
## Layout model (from the line-pattern study)
|
||||
- **NT (Namaste) = boxed grid.** ~139 horizontal rules/4pp, many ~2-column wide; long vertical
|
||||
column dividers. ~50% of articles are ruled on 3–4 sides. Boundaries are largely *drawn*.
|
||||
- **AJ (Andhra Jyothi) = whitespace layout.** Few rules (~69/4pp, mostly ≤0.6-col caption
|
||||
underlines). Most articles ruled on 0–2 sides. Boundaries come from column gutters +
|
||||
grow-right-to-dead-end + headline/dateline structure. Lines are only *confirmation* in AJ.
|
||||
- **Rule width classifies horizontal lines:** ≤0.6 col = caption underline (NEVER a boundary);
|
||||
~1 col = single-col article edge / box edge; ~2 col = article boundary (NT workhorse);
|
||||
≥2.5 col = section/banner divider.
|
||||
- **Vertical rules:** long (≥0.5 page H) = column divider / article wall; short = quote-box edge.
|
||||
|
||||
## Why earlier runs failed (root causes found)
|
||||
1. **Over-merge from clustering + containment-merge.** Multi-column articles whose datelines sit
|
||||
only in the left column get over-extended upward; a separate dated article then falls *inside*
|
||||
the box and is absorbed → 2 articles in one crop (JG R28, R64). Fixed by **header-split**.
|
||||
2. **Banner over multiple sub-stories** not cropped as one rectangle, or its sub-stories
|
||||
double-cropped → **section-banner rectangle** + **containment-merge**.
|
||||
3. **L-shaped articles** (one column longer): rectangular crop's empty corner = a *different*
|
||||
article masked white → looks like white space (JG H28). Generic ragged-bottom fix REJECTED —
|
||||
it would also move AJ R48/R53 (currently fine). Still open; needs a tighter signal.
|
||||
4. **Top-of-column banner with no anchor** falls into the article below → page-tall crop (JG R2).
|
||||
Fixed by **ceiling-trim**.
|
||||
5. **Body-less header strips** (doc_title or quote-box paragraph_title) cropped alone, split from
|
||||
body → **body-less header merge** (H and now P).
|
||||
|
||||
## Strategies implemented (all gated + measured to touch only defective blocks)
|
||||
- **Banner rectangle** (H & P, ≥1.6-col header, ≥2 cols, sure bottom boundary): crop whole rect.
|
||||
- **Section-banner rectangle** (doc_title ≥2.5 col with ≥2 headed sub-stories): crop banner-top →
|
||||
next spanning full-width separator; absorb sub-blocks. (Only JG R67 across all runs.)
|
||||
- **Containment-merge** (block ≥90% inside a larger one → fold in). Fixes split columns,
|
||||
roundup sub-stories, orphan tails.
|
||||
- **Header-split** (H block with a dateline >20px ABOVE its headline → split at headline).
|
||||
Only JG R28, R64.
|
||||
- **Ceiling-trim** (DL block, leading furniture >300px above the dateline → drop). Only JG R2.
|
||||
- **Body-less header merge** (H or P, no text, sits ≤90px above a text block, ≥60% overlap → fold).
|
||||
H: NT R65→R73. P (iter-1): NT R133→R132, JG R52→R4.
|
||||
- **Right-edge → page** (rightmost-column block → extend right edge to page-content edge).
|
||||
Touches only rightmost blocks (AJ 4/6/3/4, NT 2/3/3/8), ≤15px; interior untouched.
|
||||
- **Drop classifieds** (`drop_classifieds_regions`, runs right after `drop_masthead_regions`).
|
||||
Classifieds = the "Classified Ads / phone-number listing" columns = page FURNITURE, not news.
|
||||
Left in, a neighbour article's column-fold grows down into them (JG R65 swallowed the whole
|
||||
left column to page-bottom). A region is classifieds when (only TALL regions ≥400px are
|
||||
OCR-scanned) its OCR text carries a classifieds keyword (`classified`/`contact`) **OR** ≥5
|
||||
phone-like `\d{6,}` runs (a news article rarely has >3). OCR is **half-res `eng`-only** — the
|
||||
phone-runs + English keyword are the real signals, so this is ~2× faster than full-res tel+eng
|
||||
and gives the IDENTICAL drop set on the corpus. Court/legal notices are intentionally NOT
|
||||
dropped (user: classifieds ONLY) — they are carved into their own section instead (next).
|
||||
- **Carve court/legal notices** (`tag_legal_notices` + a carve pass in `cluster_all_article_blocks`).
|
||||
Court summons / name-change & matrimonial petitions / "by order of the court" notices are page
|
||||
furniture too — but, per the brief, KEPT and cropped as their OWN section (kind **`L`**), not
|
||||
dropped and not absorbed into a neighbour (JG R65 swallowed a court summons in its left column).
|
||||
`tag_legal_notices` half-res-`eng`-OCRs single-column text/paragraph_title regions and tags
|
||||
`r['_legal']='core'|'support'` on a legal-boilerplate keyword (CORE: hon'ble, in the court of,
|
||||
by order of, plaintiff/defendant, petitioner/respondent, summons, o.s.no, civil judge … ;
|
||||
SUPPORT: advocate, whereas, vakalat). The clusterer then groups adjacent tagged regions and
|
||||
carves a cluster into its own LOCKED `L` block **only when** (1) ≥2 tagged regions incl. ≥1
|
||||
CORE, (2) they all sit in ONE host block, and (3) that host is WIDE (>1100px → masked). Gate 3
|
||||
is the safety rule: a wide masked host whites the carved area out (no duplication), whereas a
|
||||
NARROW host is cropped verbatim, so carving out of it would duplicate the notice — those are
|
||||
left alone (e.g. NT pg3's petition notice straddling the narrow locked #75 + open #62 is NOT
|
||||
carved, so the NT baseline is untouched). The carved `L` block shows in BOTH the per-article
|
||||
crops and the debug boundary map (the carve lives inside `cluster_all_article_blocks`, which
|
||||
every consumer re-runs).
|
||||
- **Type-2 split** (split pass in `cluster_all_article_blocks`, after the legal carve). TWO
|
||||
layouts look like one big box but need OPPOSITE treatment (AJ/Namaste = ruled papers):
|
||||
- **Type 1** — sub-stories under ONE header with a COMMON BOTTOM rule → the rule + wide banner
|
||||
already made it a `_raw_rect` section (banner/section pass) → crop as ONE rectangle. NEVER split.
|
||||
- **Type 2** — independent articles stacked one below another, EACH with its own doc_title +
|
||||
its own dateline, NO common bottom rule (JG R65: కలెక్టర్/సుందరయ్య/పోస్టుమార్టం) → over-merge →
|
||||
SPLIT into one article per headline (members assigned to the nearest headline at/above them).
|
||||
Discriminator = the `_raw_rect` flag (set ⇒ sure bottom rule ⇒ Type 1). The split anchors are
|
||||
headlines that **OWN** a dateline (each dateline assigned to the nearest headline above it) — a
|
||||
single article with a headline + a sub-headline sharing ONE dateline has only ONE owning
|
||||
headline, so it is NOT split (this fixed the AJ R50/R57 & R35/R79 false splits). Anchors must be
|
||||
vertically stacked ≥120px apart (not two columns headed side-by-side). NOTE for line-less papers
|
||||
(Sakshi): the `_raw_rect` bottom-rule signal won't exist — a different bottom cue would be needed.
|
||||
|
||||
## Iteration log
|
||||
- **iter-1:** body-less header merge extended to `paragraph_title` → NT R133→R132, JG R52→R4
|
||||
(title-only fragments fixed). AJ untouched; NT pg4 26→25, JG pg1→9.
|
||||
- **iter-2:** drop graphic-label orphans (pure-text O block ≥80% inside a FOREIGN image) →
|
||||
JG R34 dropped (label inside banner image). AJ/NT 0 drops; JG pg1 9→8.
|
||||
- **iter-3:** orphan-TEXT absorb (fold pure-text orphan UP into clear above-article, gap≤80,
|
||||
no down-folds) — TRIED & **REVERTED**. Only match was NT pg4 R75→R132, a CLASSIFIEDS
|
||||
"change of name" notice; could not verify R75 belongs to that ad vs a separate notice →
|
||||
merging distinct classifieds is a regression risk. Deferred. (AJ/JG had 0 matches anyway.)
|
||||
|
||||
## Assessment after iter-3 — safe heuristics largely exhausted
|
||||
The remaining backlog items are **risk-bearing or need human judgment**, not safe heuristics:
|
||||
- Orphan PHOTOS (JG R25, AJ R12/R26): binding a standalone photo to "the right" article is
|
||||
ambiguous (far gaps, multiple candidates).
|
||||
- Orphan TEXT in classifieds/notices (NT R75, etc.): can't tell same-ad vs separate-ad.
|
||||
- JG front-page over-merges (R64/R65): dense multi-headline roundups; further splitting is
|
||||
complex and could fragment legit roundups.
|
||||
- JG H28 L-shape white space: a generic ragged-bottom split also moves AJ R48/R53 (fine now).
|
||||
Recommendation: pause autonomous loop; these need a human call per case. Resume with a
|
||||
specific directive if desired.
|
||||
|
||||
## Open defect backlog (prioritized for next iterations)
|
||||
1. **Orphan photo/text blocks (kind O)** — REMAINING: AJ pg1 R12 (photo+cap+text), pg1 R76
|
||||
(text), pg3 R32 (text), pg3 R26 (img+text); NT pg3 R7 (text tail, 36px below H98),
|
||||
pg4 R75 (text, 14px below P132); JG pg1 R25 (img-only photo). [R34 done in iter-2.]
|
||||
Next safest: fold orphan TEXT into the article directly above/below within a small gap
|
||||
(NT R75→P132 gap14, R7→H98 gap36) — measure first (risk: wrong-article merge).
|
||||
Harder: bind orphan IMAGE (R25) to caption+nearest article.
|
||||
2. **JG front-page over-merges** R65 (4DL), R64 (residual 2DL below headline) — dense section
|
||||
roundups; may need below-headline multi-headline split.
|
||||
3. **JG H28 L-shape white space** — needs a signal that distinguishes it from AJ R48/R53 (which
|
||||
are fine). Candidate: only when the empty corner is masked-out *foreign* article AND the
|
||||
block's tail is a single-column sidebar with its own sub-head/byline → split the sidebar.
|
||||
|
||||
## Hard limitation: undetected headlines (OCR gap, not a cropping bug)
|
||||
On some pages PaddleOCR detects **no doc_title** for the top articles (JG pg1: only 3 doc_titles
|
||||
total, ALL in the bottom half; top-half headlines `భానుడి భగభగ` / Indiramma / కరీమాబాద్ were
|
||||
missed entirely). A geometric crop cannot include a headline that has no region. Symptoms:
|
||||
DL-anchored crops with the heading missing (JG a01_DL3, a03_DL4) and lead photos orphaned from
|
||||
their headless article (JG a02_O25). The REAL pipeline recovers these via the paid Claude
|
||||
"catch by eye" pass (pipeline log: "N article(s) Claude must catch by EYE — no headline box").
|
||||
The geometric `all_article_crops` (real run AND replay) will lack them. The only geometric fix
|
||||
is a NEW pixel-level headline-band detector (find the large-type band above a headless dateline)
|
||||
— substantial + risky for AJ/NT baselines; deferred unless explicitly requested.
|
||||
|
||||
## Replay validation cheatsheet
|
||||
```
|
||||
python3 _replay_all.py # AJ → all_article_crops_final
|
||||
python3 _replay_namaste.py # NT Siddipet → all_article_crops_final
|
||||
python3 _replay_jangaon.py # NT Jangaon → all_article_crops_review
|
||||
```
|
||||
Read-only block inspection: replicate the chain (dedup → merge_stacked → drop_masthead →
|
||||
promote_paragraph_titles → mark_bullet_titles → find_article_starts_by_dateline →
|
||||
[probe cluster → recover_orphan_text_headlines → re-detect] → cluster_all_article_blocks).
|
||||
|
||||
## Partition passes added (post iter-2) — all gated + validated
|
||||
- **Seed/lock confident cells** — a block is `_locked` (confident) when it's a single complete
|
||||
article (exactly 1 dateline + a headline) OR fully boxed (≥3 ruled sides). Over-merges stay open.
|
||||
- **Step 4 — grow OPEN cells into gaps** (bounded by walls/cells/frame; locked never move;
|
||||
strict guard: never increase overlap with a locked cell). AJ/NT: 0 open∩locked overlaps.
|
||||
- **Step 5 — containing-assignment** — every unassigned region inside a cell's box joins it
|
||||
(no box growth). Cleared NT pg4's 11 section-absorbed regions; counts unchanged.
|
||||
- **No-overlap reconciliation** — trims a 0-member over-reaching box back to its members.
|
||||
- **Lead-photo rebind (caption-anchored)** — a PHOTO→CAPTION→HEADLINE stack = lead photo; move
|
||||
the photo+caption down into the headline's block. Fixes JG a06_P37/maize R29 + AJ pg4/NT lead
|
||||
photos. The caption requirement excludes the H93 false positive (photo at an article's bottom).
|
||||
- **Horizontal-line LENGTH FLOOR (`_lines.separator_barriers`)** — a horizontal rule counts as an
|
||||
article separator only if width ≥ **0.6× column** (median text width). Drops short
|
||||
caption/decorative underlines. NOTE: ≥1.0× is TOO aggressive (a single-column article's own
|
||||
boundary is <1 col → ≥1.0 merged NT pg4 R121); 0.6× merges ZERO articles. Caption-vs-separator
|
||||
is still decided primarily by "what's directly above the line" (photo/caption) — length is a
|
||||
secondary floor. A rule below a caption ≈ caption width = caption underline (dropped); only a
|
||||
rule much WIDER than the caption above it (≥1.5×) is kept as a boundary.
|
||||
|
||||
## Tried & REVERTED (kept for the record)
|
||||
- **Orphan-TEXT absorb** — only match was a NT classifieds box (R75/R132); couldn't verify
|
||||
same-ad vs separate-ad → regression risk. Deferred.
|
||||
- **Ragged-bottom sidebar split** — landed for JG H28 (split the `రాత్రికి రాత్రికే` sidebar so the
|
||||
L-shape white space cleared); later the lead-photo/grow cascade made H28 tile both quote boxes
|
||||
with no white space anyway. (Gate: main part must stay multi-column → AJ R53 never split.)
|
||||
- **Below-divider cut** (cut content sitting below a vertical divider's END out of the right-column
|
||||
article above — JG DL2 holding the maize wide photo R30). Detection is SAFE (straddle gate ⇒
|
||||
only JG R2; AJ/NT untouched), but the repair destabilised JG (merged into wrong neighbour R49;
|
||||
emptied DL2 regrew). Deferred — needs correct merge-target (the dateline governing the band) +
|
||||
a "don't regrow a just-cut block" guard.
|
||||
|
||||
## RUN-WIDE VALIDATION (all 7 output runs, geometric, no API) — 2026-06-09
|
||||
Ran the full cluster chain on every run in `output/` and checked counts + 2+dateline over-merges.
|
||||
- **AJ Siddipet ×3** (incl. 2 never-loaded runs): **12 / 18 / 14 / 20 on all three, 0 over-merges.**
|
||||
- **NT Siddipet ×3** (incl. 2 never-loaded runs): **11 / 22 / 19 / 25 on all three.**
|
||||
- **NT Jangaon**: 7 / 12.
|
||||
- **Every `2+dateline` block is an intended ROUNDUP** (verified): NT pg2 [110,127], pg3 [54,60,62],
|
||||
pg4 [67,121] (R121 = a `raw_rect` section: headline + 2 dated sub-stories + photos, same accepted
|
||||
pattern as R67), JG [64,65] (front-page section roundups).
|
||||
- **New runs match the baselines exactly** ⇒ rules generalise (not overfit). No crashes, no new
|
||||
over-merges, no merged articles from the length floor.
|
||||
Conclusion: the horizontal-line + caption handling and the partition/lead-photo passes are
|
||||
validated across the whole corpus.
|
||||
|
||||
## Classifieds-drop validation (end-to-end replay, no API) — 2026-06-09
|
||||
Wired `drop_classifieds_regions` into the pipeline (after `drop_masthead_regions`) + all 3 replay
|
||||
scripts, then re-ran every replay:
|
||||
- **AJ: 12 / 18 / 14 / 20** — baseline EXACT, **0 classifieds dropped** (no false positives).
|
||||
- **NT Siddipet: 11 / 22 / 19 / 25** — baseline EXACT; roundups [110,127] / [54,60,62] /
|
||||
[67,121] all intact; 0 classifieds dropped.
|
||||
- **NT Jangaon 130635: pg1 = 7, pg2 = 13** (was 12). The only intended change: R65 shrank from
|
||||
`[113,1958,1977,6279]` (page bottom, 4 datelines, swallowing the phone-listing classifieds) to
|
||||
`[113,1958,1977,5113]` (3-DL front-page roundup). Classifieds R87 (`y5143–6267`, phones=8)
|
||||
dropped; the freed left-column content below becomes its own block (12→13). a06_H65 renders as
|
||||
a bounded roundup, no longer page-tall over the classifieds.
|
||||
- **OCR cost addressed:** detector now OCRs each tall (≥400px) region at **half-res `eng`-only**
|
||||
(was full-res `tel+eng`) — ~2× faster per call, verified to produce the IDENTICAL drop set
|
||||
(R87 still phones=8/kw=True; 6 sampled news bodies still 0/False).
|
||||
- NOTE: R65 still includes a *court/legal* notice stacked in its left column. Per the user's
|
||||
"classifieds ONLY" directive this is intentionally left; separating court notices is deferred.
|
||||
|
||||
## Court/legal-notice carve validation (end-to-end replay, no API) — 2026-06-09
|
||||
Follow-up directive: "include court/legal notices as box/section in populating the crops + debug
|
||||
img." Added `tag_legal_notices` (pipeline + 3 replays, after classifieds) + the carve pass in
|
||||
`cluster_all_article_blocks`, then re-ran every replay:
|
||||
- **JG 130635 pg2: 13 → 14 crops.** The court summons (R51/R89/R101/R108/R93) was carved out of
|
||||
R65 into a new **`a08_L89`** block `[118,2887,595,4080]` (5 regs) — a clean, complete notice
|
||||
("IN THE COURT OF THE HONBLE JUNIOR CIVIL JUDGE … BY ORDER OF THE HON'BLE COURT … ADVOCATE").
|
||||
R65 dropped 30→25 members and **whites the carved area out** (verified in `a06_H65` — no
|
||||
duplication). The debug boundary map shows it as **LOCK #89 [L] (5)**, nested in #65. pg1 = 7.
|
||||
- **AJ: 12 / 18 / 14 / 20** — baseline EXACT, 0 legal carves.
|
||||
- **NT Siddipet: 11 / 22 / 19 / 25** — baseline EXACT, 0 legal carves; roundups intact. NT pg3 has
|
||||
a real petition notice (R47/R79/R89) but it straddles the NARROW locked #75 + open #62, so Gate 3
|
||||
(wide-host-only) correctly SKIPS it → baseline untouched.
|
||||
- Detection sweep (read-only) across the corpus: legal keywords flagged ONLY the JG court notice
|
||||
and the NT pg3 petition; **0 false positives on any AJ/NT news region.**
|
||||
- COST: `tag_legal_notices` OCRs ~40–70 single-column text regions/page (the expensive part).
|
||||
Acceptable for the paid pipeline (Claude vision dominates), but a candidate for a cheaper
|
||||
pre-gate (e.g. skip dateline-anchored regions) if it becomes a bottleneck.
|
||||
- DEFERRED (harder, needs the seed-before-clustering model): a legal notice that straddles a
|
||||
NARROW straight-cropped article (NT pg3) — to carve it cleanly the host article's box must be
|
||||
shrunk away from the notice, which can't be done by masking alone.
|
||||
|
||||
## Type-2 split validation (end-to-end replay, no API) — 2026-06-09
|
||||
Directive: Type-1 (shared header + common bottom rule) = ONE rectangle (fine); Type-2 (stacked
|
||||
articles, own headline+dateline each, no common rule) = SEPARATE articles. Added the split pass.
|
||||
- **JG 130635 pg2: 14 → 16 crops.** R65 (the კალెక్టర్ over-merge) split into 3 clean articles:
|
||||
R65 కలెక్టర్ `[113,1958,1975,2859]`, R86 సుందరయ్య `[123,2894,1977,4292]`, R112 పోస్టుమార్టం
|
||||
`[133,4325,1975,5113]`. Court notice R89 [L] still its own section. pg1 = 7.
|
||||
- **AJ: 12 / 18 / 14 / 20** — baseline EXACT (after the dateline-OWNERSHIP fix; the first cut wrongly
|
||||
split AJ pg1 R50/R57 and pg3 R35/R79 — headline+subhead sharing one dateline — 13/15, now fixed).
|
||||
- **NT Siddipet: 11 / 22 / 19 / 25** — baseline EXACT. The 2+dl roundups [110,127]/[54,60,62] are
|
||||
single-header-multi-dateline (Type 1) so they have <2 dateline-owning headlines → NOT split;
|
||||
[67,121] are `_raw_rect` → excluded. All correctly preserved.
|
||||
- KNOWN minor issue: R65's left column held a furniture stack (court notice + classifieds logo +
|
||||
a small job ad + a గమనిక notice). The court notice is carved (L89) and the main classifieds
|
||||
(R87) dropped, but the leftover logo (R78 image) bleeds into R86's crop and the job ad + గమనిక
|
||||
bleed into R112's crop (they're <400px / images, below the classifieds-drop gate). Secondary
|
||||
cleanup — extend furniture detection if needed. [RESOLVED below: furniture section.]
|
||||
|
||||
## Furniture section (Type-2 split) — column-aware member assignment — 2026-06-09
|
||||
Directive: when splitting a Type-2 stack, LEAVE classifieds / notices / unrelated content OUT of
|
||||
the article crops, but KEEP that section visible on the debug empty-canvas map. Implemented
|
||||
**geometrically (no OCR)** inside the split: each member is assigned to the nearest headline
|
||||
at/above it ONLY IF it also sits within that headline's COLUMN x-span (±0.3 col). A member that
|
||||
lands in a headline's y-band but a DIFFERENT column is unrelated content sharing the page — it
|
||||
falls out as LEFTOVER and is grouped into a `_furniture` section block. Furniture blocks are:
|
||||
(1) EXCLUDED from article crops — `crop_all_article_blocks` skips saving them, and because each
|
||||
article sub-block's bbox is rebuilt from its in-column members only, the furniture column isn't
|
||||
even inside the article rectangle; (2) DRAWN on the debug boundary map as a hatched GREY
|
||||
"FURNITURE #id" box; (3) NEVER saved as a crop. The split fires only on JG R65, so this touches
|
||||
ONLY that page — AJ/NT untouched.
|
||||
- **JG pg2:** R65 → R65 కలెక్టర్ + R86 సుందరయ్య (x682, was x123 w/ the classifieds logo) + R112
|
||||
పోస్టుమార్టం (x682, clean) + R89 [L] court notice + **F44 furniture** [123,4139,626,5113]
|
||||
(classifieds logo + job ad + గమనిక — debug-only, not cropped). 16 saved crops; boundary map shows
|
||||
the FURNITURE box. a09_H86 & a13_H112 verified clean (no furniture bleed).
|
||||
- **AJ 12/18/14/20** and **NT 11/22/19/25** — baselines EXACT.
|
||||
|
||||
## Type-2 split — paragraph_title anchors + ';' dateline + section discriminator — 2026-06-09
|
||||
Two more JG pg2 over-merges were reported (R97 = గుండె చికిత్స + మృతుడి పరామర్శ; R64 = జాతీయ రహదారి +
|
||||
ఉపసర్పంచుల చెక్ పవర్). Three root causes, three fixes:
|
||||
1. **2nd headline detected as `paragraph_title`, not `doc_title`** (R58, R84) → my split's anchors
|
||||
were doc_title-only. FIX: anchors = `doc_title` OR `paragraph_title`, with COLUMN-AWARE dateline
|
||||
ownership (each dateline → nearest headline above WHOSE x-span covers it; a caption in another
|
||||
column can't steal it). Captions/sub-heads still own no dateline ⇒ never an anchor.
|
||||
2. **2nd dateline's colon OCR'd as a semicolon** (R97: 'చిల్పూరు, మే 19 ;') → `_dateline_in_text`
|
||||
required ':'. FIX: accept ';' too (guards: digit + short prefix + no sentence punctuation).
|
||||
3. **R64 was `_raw_rect`** (banner-rectangle extended the wide headline to the next banner, NO
|
||||
spanning rule) so the split skipped it. FIX: the split's Type-1 exclusion is now the `_section`
|
||||
flag (set ONLY by the section-banner pass, which requires a real spanning bottom rule), not the
|
||||
coarse `_raw_rect` flag. R64 (no rule) → splits; R67/R121 (real section) → stay one rectangle.
|
||||
- **JG pg2 16→18:** R64→R64+R84, R97→R97+R58 (verified: each crop is one complete article).
|
||||
- Side effects, all VERIFIED correct (same rule, genuinely distinct articles — not fragmentation):
|
||||
NT pg2 22→23 (అంగన్వాడీ R127 off the ప్రజావాణి section), NT pg3 19→20 (పర్యావరణ R60 off), AJ pg4
|
||||
20→21 (గజ్వేల్ R12 — a real dateline the ';' fix recovered; an existing pass then split it).
|
||||
R110 (ప్రజావాణి) stayed whole as a `_section` ⇒ the discriminator protects real sections.
|
||||
|
||||
## Orphan-PHOTO binding — an image may never stand alone — 2026-06-09
|
||||
RULE (user): an article may be orphan, but an IMAGE may not — every photo must belong to some
|
||||
article. A final pass in `cluster_all_article_blocks` binds each ORPHAN-PHOTO block (no
|
||||
doc_title/paragraph_title headline AND no dateline; image-only, OR image + caption only, OR
|
||||
image-area ≥50%) to the best NEWS article (furniture/legal blocks are excluded as targets): the
|
||||
article whose top is just BELOW the photo in the same column (lead photo), else just above, else
|
||||
the nearest column-overlapping article. A TEXT/body orphan is LEFT ALONE.
|
||||
- **Sakshi pg1 23→22, pg2 27→20:** every orphan photo bound (R28→R78 lead photo verified — the
|
||||
'collector inspecting BL-1' photo + caption now sit in R78; pg2 R38/R42/R48/R52/R60/R63 all
|
||||
bound). **0 image orphans remain** on either page. The text orphan R18 (pg1) correctly stays.
|
||||
- **JG pg1 7→6:** orphan photo R25 bound into its article.
|
||||
- **AJ 12/18/14/21** and **NT 11/23/20/25** — UNCHANGED (no qualifying image orphans on those).
|
||||
- NOTE: Sakshi itself has rough article structure (headlines/datelines under-detected, no rules) —
|
||||
some bound photos land on a column-overlapping article that may need per-case review; but the
|
||||
rule (no floating image) now holds. Deeper Sakshi clustering is a separate task.
|
||||
- **Respect horizontal separators in the photo bind (refinement):** a photo binds to an ADJACENT
|
||||
article (gap ≤200px) even if a rule sits between them — that rule is the article's own headline
|
||||
border and the photo is its lead photo (JG R28→R78, 7px gap). But a FAR fallback bind is REJECTED
|
||||
if a horizontal rule LONGER than a caption (>0.6 col) lies between the photo and the article —
|
||||
the user's cross-paper line rule. This kept the Sakshi pg2 "student photo" R52 (top of page) from
|
||||
binding down through two FULL-WIDTH rules + a page of white space into R118 (the భక్తులకు/
|
||||
Kaleshwaram story); R52 now binds to R127 in its own band, and `a08_H118` is clean. Verified:
|
||||
Sakshi pg1 22 / pg2 20 (0 image orphans); AJ 12/18/14/21, NT 11/23/20/25, JG 6/18 all unchanged.
|
||||
|
||||
## Sakshi page-1 deep fix round — 2026-06-10 (visual review of all 22 pg1 crops → 14 BAD)
|
||||
A crop-by-crop visual audit of Sakshi JG pg1 found 14/22 BAD crops. Root causes & fixes, ALL
|
||||
Sakshi-gated (AJ 12/18/14/21, NT 11/23/20/25, JG 6/18 re-validated EXACT after every change):
|
||||
- **Masthead drop for Sakshi** (`drop_masthead_regions`, `paper=="sakshi"` branch, every page):
|
||||
drop every region that ends ABOVE the topmost headline-type region (sanity: that line must be
|
||||
in the top 30%). pg1: weather box R64, photo-brief R62/R59, nameplate R63, and the page-date
|
||||
strip R71 — which OCR'd as a DATELINE and seeded a fake DL71 article. pg2: R68/R71/R84/R104.
|
||||
- **`detect_sakshi_headline_bands`** (called after `promote_paragraph_titles`, pipeline + replay)
|
||||
— the big one. Sakshi's display headlines are often NOT boxed by PaddleOCR at all. Two passes:
|
||||
1. **WIDEN**: a doc_title grows sideways over adjacent UNCOVERED large-ink columns — its
|
||||
un-boxed kicker half (R52 'అనూహ్య స్పందన' + red kicker 'రిబేట్ ఆఫర్కు'). Widest titles first;
|
||||
extensions join the coverage map so a narrow neighbour can't steal a wide headline's kicker.
|
||||
Ink within 25px of a foreign region's edge is the neighbour's own glyph overflow — ignored.
|
||||
2. **SYNTHESIZE**: an uncovered big-type band (55–280px tall, ≥0.75 col wide, ink 5–60%, text
|
||||
following below, never above the first real headline) becomes a synthetic `doc_title`
|
||||
(`_synth_band`) anchor. Found BOTH missing pg1 banners (lift-1 'జూలై 31...' R99 and SIR
|
||||
'మ్యాపింగ్లో జిల్లాకు అగ్రస్థానం' R100) and pg2's గమనిక box R139. CRITICAL detail: two
|
||||
headlines can share pixel rows with only a ~50px gutter (same size as a word gap) — a gap
|
||||
splits a band run ONLY if it contains a known text-column LEFT edge (≥35px wide); plain
|
||||
gap-size segmentation merges both banners into one anchor (measured: pg1 12 crops, 45-member
|
||||
monster).
|
||||
- **Box-edge rule disarm** (`_is_box_edge` in `_barrier_between`, Sakshi only): a horizontal rule
|
||||
with a PARALLEL partner 80–400px away (≥70% overlap) is a quote/bullet-box border, never a story
|
||||
separator. Without it the lift-1 bullet-box borders fenced the article's own columns off.
|
||||
- **Photo-bottom border disarm** (`_in_photo`, Sakshi only): a rule within 14px BELOW an image,
|
||||
horizontally inside the photo span ±25px, is the photo's frame/caption rule (PaddleOCR's box
|
||||
ends a few px above the printed border, so the interior test missed it). Without it R61/R46/R23
|
||||
(lift-1 caption + col-3 body) fell into the story below.
|
||||
- **Caption never a headline line** (headline-stack recovery, all papers — baselines unaffected):
|
||||
a figure_title directly under an image (≤90px) is a CAPTION; stop the stack there. Without it
|
||||
the synth SIR headline pulled the Indiramma photo's caption R69 down as a "wrapped line".
|
||||
- **No lead-photo rebind into a `_synth_band` headline**: a synth band's lead photo is BELOW it by
|
||||
construction; a photo+caption ABOVE it belongs to the story above (R36/R69 stay with R77).
|
||||
- **Continuation-column fold** (Sakshi only, end of clusterer): a TEXT-only orphan block directly
|
||||
beside an article block with the SAME vertical band (top ±90px, ≥80% overlap, gap ≤80px, no
|
||||
vertical rule between) is the other column of the same box → merge (pg1 R18 → R79; the text even
|
||||
continues mid-word 'విద్యా సంస్థ|లకు' across the two).
|
||||
- **Stray-image re-home** (Sakshi only): an image member vertically DETACHED from the rest of its
|
||||
block but fully inside ANOTHER article's box moves there. A 3-column synth banner column-overlaps
|
||||
everything below it, so R50's tiny సాక్షి-ఎఫెక్ట్ clipping R44 (whose own narrow headline does
|
||||
NOT column-overlap it) had fallen to the banner 1100px above.
|
||||
- **Narrow-crop masking** (`crop_all_article_blocks`, all papers): narrow (≤1100px) crops now white
|
||||
out regions OWNED BY OTHER blocks (gpad=2) before the ink-trim — kills the sliced-glyph slivers
|
||||
at crop edges. Un-owned ink is left alone (it may be the crop's own un-boxed headline). Members
|
||||
are repasted, so nothing of the article itself can be erased. Counts unchanged on all papers.
|
||||
- **Review overlays**: `crop_all_article_blocks(..., overlay=True)` (used by `_replay_sakshi.py`)
|
||||
draws member boxes on the review crops — blue=anchor, magenta=synth band, green=member.
|
||||
- **RESULT (Sakshi JG pg1): 22 → 16 crops, every reduction a genuine reunification.** Visual
|
||||
re-audit of all 16: 14 GOOD / 2 MINOR / 0 BAD (was 8 GOOD / 14 BAD). The rebate feature package
|
||||
(was shredded into P94+H52+DL71+DL11 with sliced letters) is ONE crop; lift-1 and SIR-mapping
|
||||
(whose headlines have NO region) are complete articles anchored by synth headlines; H77 is
|
||||
exactly the Indiramma story; H54/H78/H55 no longer hold neighbours' content. pg2: 20 → 17
|
||||
(top photo-gallery orphans folded into their stories; not yet visually audited).
|
||||
- **NEW Sakshi baselines: pg1 → 16, pg2 → 17.**
|
||||
- Known remaining (MINOR): a01_H55 loses the unboxed last line of its మ్యూజియాలజీ sub-brief
|
||||
(no region covers it; the next block's white-out grazes it); the EAPCET ad image R33 sits
|
||||
mid-article in H55 (it IS physically inside the article band; ad detection deferred).
|
||||
- Known remaining (pg2, PRE-EXISTING): the Type-2 split's column-aware leftover pass marks the
|
||||
విద్యార్థిని ఆత్మహత్య article as FURNITURE (R4/R10 F) → it is NOT cropped at all. Present in the
|
||||
pre-fix baseline too. Needs its own round. [RESOLVED in the pg2 round below.]
|
||||
|
||||
## Sakshi page-2 round — 2026-06-10 (visual audit of all pg2 crops; user-reported defects)
|
||||
Fixes, validated after each change (AJ 12/18/14/21, NT 11/23/20/25 incl. 2+dl=[110]-only on pg2,
|
||||
JG 6/18 — all EXACT):
|
||||
- **a04_H118 body truncated at the column boundary** (col5 ends mid-word 'నిర్మా-', col6 holds
|
||||
'ణం…'): the col6 body R20 was stolen by the headless dateline R14's GROW-UP, which climbed PAST
|
||||
the R14 story's own subhead R121 because `_is_caption` lets a 197px two-paragraph text through
|
||||
(≤200px + a photo 82px above). FIX (all papers, baselines unchanged): grow-up STOPS after
|
||||
claiming a `paragraph_title` — the heading IS the article's top; nothing above it is ours.
|
||||
- **విద్యార్థిని ఆత్మహత్య never cropped** (whole story = furniture): its heading R88 IS detected
|
||||
(paragraph_title) but the R41 Type-2 split's anchors don't span col4 → all 8 regions fell out
|
||||
as LEFTOVER → furniture. FIX (all papers; gates keep AJ/NT/JG exact): a leftover group that
|
||||
LEADS with its own COLUMN-WIDE heading (≥0.6 of the group width — a narrow WANTED label stays
|
||||
furniture) and has body text → emit as an ARTICLE (kind P), not furniture.
|
||||
- **a13_H93/'విషాదయాత్ర' cut mid-sentence, its tail + tributes in the girl's crop**: the col4
|
||||
leftover zone holds TWO stacked items (girl's story y3658-4643, శ్రీనివాస్ tail y4723-5938) with
|
||||
a separator rule at y4679 between them. FIX (Sakshi only): (1) leftover clustering never merges
|
||||
across a separator rule; (2) a heading-less leftover group whose band MATCHES an adjacent-column
|
||||
split article (top ±90px, ≥80% overlap, gap ≤80px) is that article's column CONTINUATION → its
|
||||
members merge there (the tail's text literally resumes H93's "...అయితే వైద్యులు" mid-sentence).
|
||||
ORDER MATTERS: the wide-heading→ARTICLE check runs FIRST, else the girl's story (gap-close to
|
||||
H99's band) band-attaches into H99. Both passes are Sakshi-gated: un-gated they re-shuffled an
|
||||
NT pg2 leftover into R105 (2+dl-blocks [110]→[110,105]) — caught by the 2+dl indicator and
|
||||
re-gated.
|
||||
- **a03_P129/a05_H91: dead farmer's portrait R47 + caption R115 stuck at the briefs column's
|
||||
bottom, white hole in his own story's crop**: the stray-image re-home pass couldn't see R47 as
|
||||
detached because its caption R115 sat below it inside the same block. FIX: re-home treats an
|
||||
image + its caption (figure_title ≤90px below, ≥40% overlap) as ONE UNIT — excluded from the
|
||||
envelope test and moved together (→ H91, inside whose box they sit).
|
||||
- **గమనిక notice box synthesized as a headline** (R139, its own bogus crop): a filled red header
|
||||
measures ink 0.51; real Sakshi display headlines measure 0.30-0.35. FIX: synth band ink ceiling
|
||||
0.60 → 0.45; the notice text returns to the classifieds-column furniture (not cropped).
|
||||
- **RESULT (Sakshi JG pg2): 20 → 17 crops.** Visual audit of all 17: 11 GOOD / 4 MINOR / 2 BAD →
|
||||
after the H93/P88 boundary fix the BAD pair re-audited GOOD. The H118 two-column body, the
|
||||
విద్యార్థిని article (new crop P88), H91's portrait, and the P129 briefs column all verified.
|
||||
- Known remaining (pg2, magazine-style kids/summer feature band only): H82/H127 share the gallery
|
||||
collage and H82's story conclusion ('–దుగ్గొండి' sign-off + 'నీతి' moral box) renders inside
|
||||
H127's crop — a collage-page attribution problem, low priority for the news pipeline. The
|
||||
classifieds crops (P136/P111) bundle neighbouring ads and clip one ref number (MINOR).
|
||||
|
||||
## POLITICAL crops now BLOCK-SNAP to the geometric blocks — 2026-06-10
|
||||
`crop_political_articles` used to re-derive each Claude-selected article's rectangle from the raw
|
||||
member_region_ids union plus ~400 lines of parallel ad-hoc geometry (banner walls, foreign-headline
|
||||
clips, floors, grow-right) — none of which carried the geometric-crop fixes. Now it BLOCK-SNAPS:
|
||||
- It clusters the page once (`cluster_all_article_blocks`) and renders every block crop via
|
||||
`crop_all_article_blocks` into a temp dir — the exact validated pipeline (furniture drop,
|
||||
un-boxed headline recovery, neighbour masking, box-edge rules, continuation folds).
|
||||
- Each political article is mapped to the geometric block owning the MAJORITY (≥50%) of its
|
||||
member regions; that block's crop is shipped as `article.png` (`method:
|
||||
"smart_extractor_blocksnap"`, info.json carries the block's full member list).
|
||||
- A block already claimed by an earlier article on the page is not re-used (no duplicate crops);
|
||||
any article that fails to map falls back to the legacy path unchanged.
|
||||
- The pipeline call passes `dateline_starts` + `sep_lines` through so the clustering matches the
|
||||
all_article_crops output exactly.
|
||||
- VALIDATION (no API — `_replay_political.py` replays saved `page_NNN.political_result.json`
|
||||
member lists through the new path): Sakshi JG pg1 2/2 snapped (the rebate package + DL5, both
|
||||
verified visually as the block-quality crops); AJ Siddipet pg2/3/4 4/4 snapped (10-13 of 12-13
|
||||
member votes, incl. the R48/R33 banner blocks); NT Jangaon pg1 2/2 snapped (13/13, 4/4). ZERO
|
||||
legacy fallbacks needed on the corpus.
|
||||
- NOTE: replayed member lists come from OLD paid runs (stale region understanding) — e.g. the
|
||||
Sakshi 'Transfers delayed!' entry maps to the rebate block because its old members [66,29] sit
|
||||
there now. On the next paid run Claude selects members against the CURRENT regions (incl. the
|
||||
synthesized Sakshi headlines, which are in regions.json and the prompt's region list), so the
|
||||
member→block vote will be consistent end-to-end.
|
||||
|
||||
## New-run defects round (Sakshi_Jangaon District_20260513, first PAID run on new code) — 2026-06-10
|
||||
User-reported bad crops on the fresh paper; three more Sakshi-gated passes (validated: old-run
|
||||
Sakshi pg1 16 / pg2 17 UNCHANGED; AJ 12/18/14/21, NT 11/23/20/25 [110], JG 6/18 all EXACT):
|
||||
- **pg2 a02_H106 was a 695×5055 column strip** (statue story + 4000px of masked white):
|
||||
TWO causes. (a) The dance-photo caption R104 (page top) fell down-column into H106 —
|
||||
its photo R44 lived in another block. FIX: **stray caption re-home** — a figure_title member
|
||||
moves to the block that owns the image it abuts (±90px above/below, with **-30px overlap
|
||||
tolerance**: PaddleOCR's photo box overlaps the caption strip by a few px, R104 vs R44 = -11px,
|
||||
which defeated a 0-gap test on the first attempt). Donor block shrinks back to its members.
|
||||
(b) The aviation story's heading is a `paragraph_title` 1200px below the statue story's
|
||||
doc_title in-column → never promoted → whole stack merged. FIX: **stacked-story heading
|
||||
promotion** — a pt ≥0.55 col wide with content directly beneath (≤150px) and the nearest
|
||||
in-column base anchor **>900px** above becomes an anchor. The gate was first 600px and broke
|
||||
the old-run rebate package (its sub-head R94 sits 614px under the widened R52 headline and
|
||||
re-split, whiting R88's box over the stats infographic — caught by re-validating the old run);
|
||||
900px keeps feature sub-heads folded and still promotes genuinely stacked stories.
|
||||
- **pg2 a08_H100 stretched ~900px up with a foreign fragment above its own headline** (the NPDCL
|
||||
story's tail folded down-column into H100). FIX: **stray text re-home** — a plain-text member
|
||||
of an H block lying entirely ABOVE the anchor headline's top is never that article's content
|
||||
(kickers/decks are title-typed); move it to the smallest other article box containing it.
|
||||
- Verified visually: new-run a10_H106 (639×1326, exactly the statue story), a09_H100 (complete,
|
||||
no stray top), old-run a02_H52 (infographic numbers 15,941/5.79/11,376/3.72/1,00,20,087 intact).
|
||||
- New-run pages have NOT had a full visual audit (only the reported crops + block maps checked);
|
||||
pg1 = 14 crops / pg2 = 16 on replay.
|
||||
|
||||
## NT Adilabad flood-special front page — NT rule split + late structural cut — 2026-06-10
|
||||
NamastheTelangana_Adilabad_20260528 pg1 produced 5 page-scale OVERLAPPING mega-blocks. This page
|
||||
is DETECTION-LIMITED at the source: 65 regions only, 4 doc_titles for ~8 stories, and BOTH big
|
||||
feature headlines ('రెక్కల కష్టం.. నీళ్లపాలు', 'వడ్ల తరలింపు ఎక్కడిదాకా?') are INSIDE PaddleOCR
|
||||
image boxes — invisible to every geometric pass incl. the synth-band detector (coverage test).
|
||||
With anchors missing, the image-must-belong bind + grow/merge built page-tall blocks. Fixes:
|
||||
- **NT horizontal-rule split enabled** (was Sakshi-only): same machinery, but only at rules
|
||||
≥1.8 col (per the line study a ≥2-col rule is an article boundary on NT; the boxed grid's
|
||||
~1-col caption/box rules must not cut). _replay_adilabad.py added (NTA_RUN env overridable).
|
||||
- **NT LATE structural cut** (end of clusterer, after grow/merge/photo binds): the mid-pipeline
|
||||
split runs BEFORE the passes that built the mega-block, so DL5 [668,901,4084,6302] was never
|
||||
re-checked against the 4.4-col rule at y=4764 (and at mid-split time the bottom band's R30
|
||||
headline wasn't yet a member, so the new-start gate failed). Final blocks (not locked/raw_rect/
|
||||
section/furniture) are re-cut at ≥1.8-col rules with the underline guard; a rule ≥2.2 col cuts
|
||||
even with no detected start below. DL5 → DL56 (the whole flood feature, verified coherent) +
|
||||
H30 ('తడిసిన వడ్లు కొనాలి' bottom band, verified clean). pg1 5 → 6 crops.
|
||||
- VALIDATION: NT Siddipet 11/23/20/25 EXACT (2+dl [110],[54,62],[67,121]); NT Jangaon 6/18 EXACT;
|
||||
Adilabad pg2 31 crops unchanged (no shredding). AJ/Sakshi untouched (gate).
|
||||
- HONEST REMAINDER: H44 still spans the page top (left story + photo row + nameplate share the
|
||||
band; the 60%-block-span guard correctly refuses partial rules on a page-wide block) and the
|
||||
H59/DL9 boxes still overlap neighbours. Only a better layout model (headline bands inside
|
||||
photo boxes) or the paid pipeline's Claude-vision pass can fully fix this page. NT masthead
|
||||
drop never fired here (nameplate is INSIDE image R46, no header region) — benign, the strip
|
||||
rides atop the photo-row crop.
|
||||
|
||||
## ⚠ REPLAY-TOOLING BUG (found 2026-06-10, fixed): _ACTIVE_PAPER was never set for NT
|
||||
`_replay_jangaon.py` / `_replay_namaste.py` never set `se._ACTIVE_PAPER`, so every prior "NT
|
||||
validated EXACT" run measured with ALL paper-gated clustering passes OFF while the real pipeline
|
||||
runs them ON. (AJ has no gated passes, Sakshi's replay always set it — only NT was affected.)
|
||||
Both scripts now set it; `_replay_jangaon.py` takes JG_RUN env (default = the 130635 run; the
|
||||
user-facing run of the same paper is ..._20260608_124720). FIRST true gated-NT measurement:
|
||||
NT Siddipet 11/23/20/25 + 2+dl [110],[54,62],[67,121] EXACT (gated passes are no-ops there ✓),
|
||||
JG both runs 6/18, Adilabad 6/31.
|
||||
|
||||
## NT Jangaon pg1 (user-reported: a01_DL3 white holes, a04_H28 over-merge, a05_DL2 foreign photo)
|
||||
Root cause is the same family as Sakshi/Adilabad: THREE un-detected display headlines (brush-font
|
||||
'భానుడి భగభగ', script 'నమ్మిండు..', DL2's heading). The heat feature's lower content (vendor +
|
||||
ice-cream photos, captions, continuation column) folded DOWN to the 'ఆలస్యంపై రైతుల ఆగ్రహం'
|
||||
headline 2200px below (nearest-anchor metric); the white holes in a01_DL3 were those stolen
|
||||
regions masked out. Fixes (gated `in ("sakshi","namaste_telangana")` — AJ untouched):
|
||||
- **Re-home family enabled for NT** (stray image+caption unit, stray caption, above-own-headline
|
||||
members). The above-headline re-home is GENERALISED from text-only to text/image/figure_title
|
||||
(title-typed members stay — kickers/decks are legitimate above a headline).
|
||||
- **Synth headline bands enabled for NT — FRONT PAGE ONLY** (`n == 1`): inner NT pages are dense
|
||||
and well-detected; un-gated synth split the protected Siddipet pg4 roundups (25→28, caught).
|
||||
Band height cap 280→400 (tall display/script faces; ink-fraction still rejects photos).
|
||||
- RESULT (JG 124720 pg1, counts unchanged at 6): DL3 = the COMPLETE heat feature (mem 8→13, no
|
||||
white holes, verified visually); H28 starts AT its own headline [y3089, was 838] = exactly the
|
||||
ఆగ్రహం article (verified); DL2 = clean single-column committee article, its foreign tractor
|
||||
photo+caption re-homed to R29's procurement story (verified).
|
||||
- Residual: DL2 remains heading-less (its display heading has no region and the synth band gates
|
||||
didn't admit it) — hard-limitation class; the heading pixels sit above the crop.
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
================================================================================
|
||||
TELUGU POLITICAL-ARTICLE EXTRACTOR - EDGE CASES, BUGS & RULES
|
||||
================================================================================
|
||||
Pipeline: PDF -> PaddleOCR layout regions -> Claude grouping
|
||||
(identify_and_group_political_articles) -> deterministic geometric
|
||||
safeguards in crop_political_articles() -> per-page crops ->
|
||||
political_articles.json. Separator/line + page-bottom detection
|
||||
lives in _lines.py (classical CV, no ML, no API).
|
||||
|
||||
This document lists every edge case / bug / rule handled so far, plus the ones
|
||||
still in progress. Each point: PROBLEM -> RULE/FIX -> STATUS -> VERIFICATION.
|
||||
|
||||
Papers seen (identified by page-1 pixel height):
|
||||
6422 = namaste_telangana (no printer calibration strip)
|
||||
6549 / 6833 = andhra_jyothi (CMYK calibration strip at bottom)
|
||||
7040-7060 = sakshi (CMYK calibration strip at bottom)
|
||||
|
||||
================================================================================
|
||||
1. GROW-RIGHT TO THE BOUNDING VERTICAL WALL [FIXED]
|
||||
================================================================================
|
||||
PROBLEM:
|
||||
An under-grouped article was cropped too NARROW - its body clearly continued
|
||||
into the next column to the right, but Claude grouped only the left column, so
|
||||
the crop stopped mid-article.
|
||||
Example: run 20260602_093820 p003_a003 "రైతన్న లోడెత్తేదెలా?".
|
||||
|
||||
RULE / FIX (in crop_political_articles, after the Rule-B floor block):
|
||||
- Detect a long vertical separator line (len >= 600 px) that sits to the RIGHT
|
||||
of the current crop (x > rx2 + 10) and overlaps the article vertically
|
||||
(> 50% y-overlap). That line is the article's right "wall".
|
||||
- Absorb every text / image / figure_title / paragraph_title region whose
|
||||
center-x falls between the current right edge (rx2) and the wall.
|
||||
- Push the right edge out to the wall: rx2 = wall_x, right_cap = wall_x.
|
||||
- The padding step clamps x2 = min(x2, right_cap) so it never overshoots.
|
||||
|
||||
WIDTH-CAP GUARD (prevents over-grab):
|
||||
too_far = (wall_x - rx2) > max(art_w, 1)
|
||||
If the wall is farther away than the article's own width, it is a page-margin
|
||||
rule swallowing a NEIGHBOUR, not the article's wall -> do NOT grow.
|
||||
Also bail if a FOREIGN doc_title (a different story's headline) lies inside the
|
||||
strip we are about to absorb.
|
||||
Regression that drove this guard: run 20260601_234709 p007_a001 grew from
|
||||
[77,634,1035,1609] to [77,634,4127,2581], eating neighbour "భూముల విలువ పెంపు".
|
||||
|
||||
STATUS: Fixed & committed (HEAD 2345453). Prints "➡️ Grew ...".
|
||||
|
||||
================================================================================
|
||||
2. ROBUST JSON PARSING OF CLAUDE'S GROUPING RESPONSE [FIXED]
|
||||
================================================================================
|
||||
PROBLEM:
|
||||
One page's grouping response was empty / truncated / fence-wrapped, and the
|
||||
fragile parse of content[0].text crashed the WHOLE run:
|
||||
json.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
|
||||
Example: a run crashed on page 10.
|
||||
|
||||
RULE / FIX (smart_extractor.py):
|
||||
- New helper _extract_json_obj(text): strips ```json fences / prose, extracts
|
||||
the outermost {...} object, raises ValueError on empty/garbage.
|
||||
- Gather text from ALL response content blocks (not just block 0).
|
||||
- max_tokens raised to 8192 to avoid truncated JSON.
|
||||
- On (ValueError, json.JSONDecodeError): save page_NNN.badresponse.txt for
|
||||
debugging, then RETRY once in strict mode ("Return ONLY the raw JSON ...").
|
||||
- If the retry also fails: return {"political_articles": [], "rejected": []}
|
||||
so that ONE bad page degrades gracefully instead of killing the run.
|
||||
(json.JSONDecodeError is a subclass of ValueError - both are caught.)
|
||||
|
||||
STATUS: Fixed.
|
||||
|
||||
================================================================================
|
||||
3. RULE-B OVER-FIRE: in-article subhead wrongly treated as a new headline [FIXED]
|
||||
================================================================================
|
||||
PROBLEM:
|
||||
Rule B floors a crop at the next headline that starts a DIFFERENT story in the
|
||||
same column. But a paragraph_title that is really an IN-ARTICLE byline /
|
||||
subhead (narrow, with body text continuing below it) was being treated as a
|
||||
new-article headline, so the crop was floored far too high and dropped 9 of the
|
||||
article's member regions.
|
||||
Example: run 20260603_112014 p003_a001 "తీరని కొనుగోళ్ల వెతలు" - paragraph_title
|
||||
R79 [1193,5226,2035,5271] (an internal subhead) floored the crop at y5226.
|
||||
|
||||
RULE / FIX (Rule B block in crop_political_articles):
|
||||
- A doc_title floors the crop UNCONDITIONALLY (a real new story headline).
|
||||
- A paragraph_title floors ONLY if there is a HORIZONTAL SEPARATOR RULE
|
||||
directly above it (a printed line above a heading => genuine new section).
|
||||
Implemented via _rule_above(): a detected h-line whose y is between the
|
||||
primary headline bottom and the candidate top, overlapping > 40% of the
|
||||
candidate's width.
|
||||
- R79 has NO rule above -> no longer floors (correct).
|
||||
|
||||
VERIFICATION (offline, no API):
|
||||
- 20260603_112014 p003_a001 now keeps all members; bbox grew correctly down.
|
||||
- 20260602_093820 R81 [1162,1879,2063,1926] HAS a rule above (y1707,
|
||||
overlap 787) -> STILL floors correctly (legitimate case preserved).
|
||||
- 20260601_234709 known-good crops unaffected.
|
||||
|
||||
STATUS: Fixed.
|
||||
|
||||
NOTE / FOLLOW-UP: the cross-run downward-growth sweep (>250 px) flagged a few
|
||||
crops that grew DOWN after this change (they were previously floored by a
|
||||
paragraph_title without a rule above). Largest legit one is the 112014 fix
|
||||
itself. Others to re-confirm are NOT over-merges (swallowing a separate article
|
||||
below):
|
||||
20260602_081720 p004_a001 DOWN+1951
|
||||
20260531_231056 p002_a004/a005/a006, p002_a001
|
||||
20260601_005917 p002_a006
|
||||
20260531_205325 p002_a005
|
||||
[STILL TO VALIDATE]
|
||||
|
||||
================================================================================
|
||||
4. PAGE-BOTTOM PRINTER CALIBRATION STRIP DETECTION [FIXED - needs wiring]
|
||||
================================================================================
|
||||
PROBLEM:
|
||||
Andhra Jyothi & Sakshi print a CMYK colour-calibration strip (registration
|
||||
dots + grey bars) just above the bottom paper margin. Article crops whose
|
||||
member regions reach the page bottom (esp. footer-type regions) bleed this
|
||||
strip of coloured dots into the article image.
|
||||
|
||||
RULE / FIX (_lines.py: detect_content_bottom):
|
||||
Returns the y at the TOP of the calibration band (clamp crops to it), or the
|
||||
full height H when there is no strip (nothing to clamp).
|
||||
Algorithm:
|
||||
a. Search the bottom search_frac (12%) of the page.
|
||||
b. Per-row colour fraction col_frac (saturated CMYK: sat>55 & max>80) and ink
|
||||
fraction; the strip = the bottom-most run of rows whose col_frac >= 0.06.
|
||||
c. Require a WHITE PAPER MARGIN below the band down to the page edge
|
||||
(>=90% blank) - a real strip is followed by margin.
|
||||
d. Walk UP from the band bottom while still coloured, tolerating small white
|
||||
gaps between dot rows (<=12 px).
|
||||
e. Guard max_band (160 px): if the band is too tall it is fused with a photo
|
||||
-> bail (return H).
|
||||
f. PEAK-COLOUR DISCRIMINATOR (key false-positive fix): require the band's
|
||||
peak col_frac >= 0.15. Real registration strips are dense multi-hue CMYK
|
||||
dots peaking 0.22-0.45; a single-hue coloured ad/notice box peaks ~0.11.
|
||||
|
||||
FALSE POSITIVE that drove the peak-colour gate:
|
||||
namaste 20260603_113847 p004 has a GREEN-bordered notice box near the bottom
|
||||
(col peak 0.113) embedded in article text. An earlier "white gutter above"
|
||||
gate rejected it but WRONGLY rejected real AJ strips on busy pages (p3/p6 had a
|
||||
photo extending into the gutter). The peak-colour gate (0.15) cleanly
|
||||
separates: namaste box 0.11 -> reject; AJ 0.25 / Sakshi 0.22 / AJ-6549 0.45 ->
|
||||
accept.
|
||||
|
||||
VERIFICATION (offline):
|
||||
AJ-6833 -> clamps ~6674-6687 (drop ~150)
|
||||
AJ-6549 -> clamps ~6377-6401 (drop ~150-172) (was a false NEGATIVE before)
|
||||
Sakshi -> clamps ~6720-6721 (drop ~332)
|
||||
namaste -> H (no clamp) (correct - no strip; green box not clamped)
|
||||
AJ pages with a full-bleed bottom photo -> H (acceptable: no clean strip).
|
||||
|
||||
STATUS: Detector fixed & verified across all 4 papers.
|
||||
PENDING: wire into crop_political_articles as a per-page y2 clamp
|
||||
(y2 = min(y2, content_bottom), computed once per page); then re-verify
|
||||
112014 p003_a001 no longer includes calibration dots + regression-check.
|
||||
|
||||
================================================================================
|
||||
5. MULTI-COLUMN BANNER HEADLINE = ONE ARTICLE SPANNING ALL ITS COLUMNS
|
||||
[FIXED]
|
||||
================================================================================
|
||||
PROBLEM:
|
||||
When a single wide headline (banner) spans MULTIPLE columns, everything beneath
|
||||
it (down to its bottom rule) is ONE article - even though it contains several
|
||||
internal sub-headlines / sub-sections and photos. The foreign-headline clip
|
||||
(Rule A) and Rule B wrongly treat those internal sub-headlines as new stories
|
||||
and truncate the crop, so the banner article comes out severely under-cropped.
|
||||
Example: namaste 20260603_113847 p004 article 1
|
||||
"రైతులను వీడని అన్లోడింగ్ సమస్య"
|
||||
Banner headline id=64 [1264,423,3500,628] (width 2236 = 0.53 of page,
|
||||
crosses the internal vertical rule at x=2388 -> multi-column banner).
|
||||
Bounding vertical walls: x=1232 (left), x=3545 (right).
|
||||
Bottom rule: full-banner-width h-line at y=2756 (x[1268..3512], len 2244).
|
||||
Correct crop ~= [1232, 423, 3545, 2756].
|
||||
Current (buggy) crop = [1264,423,3500,2183] - cut off ~570 px too short and
|
||||
not extended to the side walls.
|
||||
|
||||
RULE (to implement):
|
||||
- BANNER TEST: an article's top headline (doc_title) is a banner if it CROSSES
|
||||
at least one internal vertical separator line (i.e. it spans >1 column).
|
||||
(Equivalently width >= ~0.4 of page width.)
|
||||
- For a banner article:
|
||||
* Horizontal extent = bounded by the vertical separator lines just LEFT and
|
||||
just RIGHT of the headline (left_wall .. right_wall).
|
||||
* Bottom = the LOWEST/own bottom horizontal rule that spans most of the
|
||||
banner width (x-overlap > ~0.6 of banner width) and lies below the
|
||||
headline -> the first such full-width rule below the grouped content.
|
||||
* Crop = [left_wall, headline_top-pad, right_wall, bottom_rule].
|
||||
* SKIP the internal foreign-headline clip and Rule B floor for this article
|
||||
(its sub-headlines are part of it).
|
||||
- "If the multi-column header HAS a bottom line, crop to it; if it does NOT,
|
||||
fall back to the previous (member-union + Rule A/B) logic." (user's words)
|
||||
|
||||
IMPLEMENTED (crop_political_articles, banner_box branch):
|
||||
- BANNER TEST: topmost member doc_title width >= 0.40 * page_width.
|
||||
- left_wall / right_wall = vertical separator lines reaching alongside the
|
||||
headline, just left of / right of it (fallback to member edge if none).
|
||||
- bottom_rule = the first horizontal line BELOW the grouped content whose
|
||||
x-span overlaps > 60% of the banner width (the >60% width test rejects short
|
||||
caption/photo underlines - see point 6). Require bottom_rule > headline_top+200.
|
||||
- Only when BOTH walls-ish extent AND a bottom_rule exist do we set
|
||||
banner_box = [left_wall, headline_top, right_wall, bottom_rule]; this OVERRIDES
|
||||
the per-column clip / Rule-B floor / grow-right results and restores the full
|
||||
member set. No bottom rule -> banner_box stays None -> normal logic (fallback).
|
||||
|
||||
VERIFICATION (offline, namaste 20260603_113847 p4 art1):
|
||||
- Banner fired: x[1232..3545] y[423..2756] -> padded crop [1217,408,3560,2771].
|
||||
- Visual check: crop now contains the full headline + every column beneath it
|
||||
down to the bottom rule (previously cut at y~2183).
|
||||
- Regression: banner does NOT fire on normal single-column-headline articles
|
||||
(threshold 0.40*pw); other pages' crops unchanged.
|
||||
|
||||
STATUS: Fixed & verified offline.
|
||||
|
||||
================================================================================
|
||||
6. HORIZONTAL RULE WITH TEXT/IMAGE DIRECTLY ABOVE IT = UNDERLINE, NOT SEPARATOR
|
||||
[PARTIALLY APPLIED - new rule, affects points 3, 4, 5]
|
||||
================================================================================
|
||||
PROBLEM:
|
||||
Not every horizontal printed line separates two articles. A line that has text
|
||||
or an image DIRECTLY ABOVE it is an UNDERLINE - a caption underline beneath a
|
||||
photo, or a decorative underline under a heading. Using such a line as an
|
||||
article boundary (a Rule-B "rule above", or a banner BOTTOM rule, or a page
|
||||
separator) is wrong.
|
||||
Examples (user-supplied): photo captions like "జక్కల్ శివారులో నిర్మించిన ..."
|
||||
and "నర్సాపూర్లో మాట్లాడుతున్న మాజీ మంత్రి ..." each sit ABOVE a thin rule -
|
||||
those rules underline the caption, they do not divide articles.
|
||||
|
||||
RULE (to implement):
|
||||
When deciding whether a horizontal line is an ARTICLE SEPARATOR (for Rule B's
|
||||
"rule above" check, for the banner bottom rule in point 5, and anywhere a
|
||||
h-line is used as a boundary):
|
||||
- Reject the line if the tight band immediately ABOVE it is mostly INK
|
||||
(text) or is an image/figure region -> it is an underline, not a separator.
|
||||
- A genuine article separator sits in a whitespace gutter (paper above AND
|
||||
below), OR has a NEW headline starting just below it.
|
||||
(This is analogous to the existing _isolated() whitespace-gutter test in
|
||||
_lines.py used for separator-line detection.)
|
||||
|
||||
APPLIED SO FAR:
|
||||
- Banner bottom rule (point 5): only horizontal lines spanning > 60% of the
|
||||
banner width qualify, which already excludes short caption/photo underlines
|
||||
(those are < ~0.5 column wide).
|
||||
- Note: _lines.detect_separator_lines() already runs the _isolated() gutter
|
||||
test, so the h-lines fed to Rule B / banner are whitespace-gutter lines, not
|
||||
arbitrary text strokes.
|
||||
STILL TO DO:
|
||||
- Add an explicit "ink/image directly above" rejection to Rule-B's
|
||||
_rule_above() so a caption underline beneath a photo can never corroborate a
|
||||
paragraph_title floor, even if a future detector change lets one through.
|
||||
|
||||
STATUS: Partially applied (via width test + existing gutter detection);
|
||||
explicit ink-above guard for Rule B still to add.
|
||||
|
||||
================================================================================
|
||||
CROSS-CUTTING NOTES / CONVENTIONS
|
||||
================================================================================
|
||||
- BILLING/SECURITY CONSTRAINT: do NOT call the Claude APIs while iterating. All
|
||||
verification is done OFFLINE via fixture replay of saved page PNGs +
|
||||
regions.json + cached per-page political_result.json.
|
||||
- Calibration strip is NOT an OCR region; crops only reach it via member-region
|
||||
bboxes (especially footer/header/number page-furniture regions) or padding.
|
||||
Consider dropping footer/header/number members from crops as well.
|
||||
- Test harnesses (in /tmp): replay_crop.py, replay_run.py, replay_regress.py
|
||||
(new-vs-stored bbox diff), sweep_floor.py (flags downward growth >250 px),
|
||||
test_bottom.py / test_all.py (detect_content_bottom across papers).
|
||||
================================================================================
|
||||
|
||||
can u creat img with boundaris of ech articl in th empty whit pg wit diffrnt colr ech articl so tht i can see if thy r overlppng r ?
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,296 @@
|
|||
# Telugu Newspaper Political Article Extractor
|
||||
## Complete Process & Prompts Reference
|
||||
|
||||
---
|
||||
|
||||
## STEP-BY-STEP PROCESS
|
||||
|
||||
### Step 1: Upload PDF
|
||||
- User uploads Telugu newspaper PDF on localhost:5000
|
||||
- File: `app.py` (Flask web server)
|
||||
- Cost: Free
|
||||
|
||||
### Step 2: PDF to Page Images
|
||||
- PyMuPDF converts each PDF page to high-res PNG (4200 x 7400 pixels)
|
||||
- File: `extractor.py` → `render_pdf_pages()`
|
||||
- Output: `output/<job_id>/pages/page_001.png`, `page_002.png`, etc.
|
||||
- Cost: Free (local)
|
||||
|
||||
### Step 3: Layout Detection
|
||||
- PaddleOCR LayoutDetection scans each page image
|
||||
- Finds pixel-accurate bounding boxes for every text block, headline, image, table
|
||||
- Each region gets: ID, type (text/title/image/header/etc.), bbox [x1,y1,x2,y2], confidence score
|
||||
- File: `extractor.py` → `detect_regions()`
|
||||
- Output: `output/<job_id>/pages/page_001.regions.json`
|
||||
- Debug: `output/<job_id>/pages/page_001_regions_debug.png` (visual bounding boxes)
|
||||
- Cost: Free (local)
|
||||
- Typically finds 70-130 regions per page
|
||||
|
||||
### Step 4: Article Grouping (Claude API)
|
||||
- Sends page thumbnail image + all region IDs/coordinates to Claude
|
||||
- Claude groups regions into complete articles (which text blocks belong to the same news story)
|
||||
- File: `extractor.py` → `_group_with_claude()`
|
||||
- Model: claude-opus-4-7
|
||||
- Cost: 1 API call per page
|
||||
- Output: `output/<job_id>/pages/page_001.articles.json`
|
||||
|
||||
### Step 5: Crop ALL Articles
|
||||
- Each grouped article is cropped into its own PNG using PaddleOCR's precise bounding boxes
|
||||
- Every article gets a unique ID: p001_a001, p001_a002, etc.
|
||||
- File: `extractor.py` → `crop_articles()`
|
||||
- Cost: Free (local)
|
||||
|
||||
### Step 6: Political Filter (Claude API)
|
||||
- Sends page image + list of article IDs (with headlines and positions) to Claude
|
||||
- Claude evaluates each article with Q1/Q2 questions
|
||||
- Returns only the politically significant IDs
|
||||
- File: `extractor.py` → `_filter_articles_with_claude()`
|
||||
- Model: claude-opus-4-7
|
||||
- Cost: 1 API call per page
|
||||
- Output: `output/<job_id>/filter_reasoning_page1.json`, `political_articles.json`
|
||||
|
||||
### Step 7: Keep or Delete
|
||||
- Articles Claude flagged as significant: kept, updated with political analysis
|
||||
- All other articles: deleted from output folder
|
||||
- Cost: Free (local)
|
||||
|
||||
### Step 8: Generate Outputs
|
||||
- `opposition_daily_brief.txt` — readable brief ranked by priority
|
||||
- `political_articles.json` — structured data
|
||||
- `all_political_images/` — all kept images in one folder
|
||||
- `political_articles.pdf` — all images in single PDF
|
||||
- Cost: Free (local)
|
||||
|
||||
### Step 9 (Optional): Text Extraction
|
||||
- Run `python claude_ocr.py` separately
|
||||
- Sends each kept article image to Claude Vision API
|
||||
- Extracts accurate Telugu text in proper reading order
|
||||
- File: `claude_ocr.py`
|
||||
- Cost: 1 API call per article
|
||||
|
||||
---
|
||||
|
||||
## ALTERNATIVE: Smart Extractor (ONE Claude call per page)
|
||||
|
||||
File: `smart_extractor.py`
|
||||
|
||||
### Steps:
|
||||
1. PDF → page images (same as above)
|
||||
2. PaddleOCR → all regions with precise boxes (same as above)
|
||||
3. ONE Claude call: sends page image + all region IDs → Claude identifies political articles AND groups their region IDs → returns only political groups
|
||||
4. Crop using PaddleOCR's precise boxes for only the political articles
|
||||
5. Generate outputs
|
||||
|
||||
### Difference from app.py:
|
||||
- app.py: 2 Claude calls per page (grouping + filtering)
|
||||
- smart_extractor.py: 1 Claude call per page (combined)
|
||||
|
||||
---
|
||||
|
||||
## GROUPING PROMPT (Step 4)
|
||||
|
||||
Model: claude-opus-4-7
|
||||
|
||||
```
|
||||
You group newspaper page regions into INDIVIDUAL articles. Each news story is a SEPARATE article.
|
||||
|
||||
You receive:
|
||||
1. A thumbnail of the full page (for spatial context).
|
||||
2. A JSON list of regions on the page. Each has:
|
||||
- id (int)
|
||||
- type ("title", "text", "figure", "table", etc.)
|
||||
- bbox [left, top, right, bottom] in pixels (top-left origin)
|
||||
- top_text: a Tesseract OCR snippet from the top of text regions
|
||||
- dateline: if non-null, the region starts an article body (strong signal)
|
||||
|
||||
CRITICAL RULES — BE CONSERVATIVE, SPLIT MORE:
|
||||
1. A `title` or `doc_title` region ALWAYS starts a NEW article. Every title = separate article.
|
||||
2. A region with a non-null `dateline` ALWAYS starts a new article body.
|
||||
3. Text regions attach to the NEAREST title above them IN THE SAME COLUMN ONLY.
|
||||
4. Newspapers have COLUMNS. A region in column 1 NEVER belongs to an article in column 2, even if vertically close.
|
||||
5. When in doubt, SPLIT into separate articles rather than merge. Too many small articles is better than one giant article containing multiple stories.
|
||||
6. An article should typically have 1-5 regions. If an article has more than 6 regions, you are probably merging multiple stories — split them.
|
||||
7. A banner title spanning multiple columns owns ONLY the text directly below it, not the entire page.
|
||||
8. Types "header", "footer", "page_number" — make these their own separate article.
|
||||
9. Figures/images attach to the nearest title above them in THEIR column only.
|
||||
10. NEVER merge two articles that have different headlines or topics into one.
|
||||
|
||||
Return ONLY valid JSON, no prose, no markdown fences:
|
||||
{
|
||||
"articles": [
|
||||
{
|
||||
"article_id": 1,
|
||||
"title_region_id": <int or null>,
|
||||
"member_region_ids": [<int>, ...],
|
||||
"headline_hint": "<short string or null>",
|
||||
"dateline": "<string or null>"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Order articles top-to-bottom, then left-to-right by topmost member region.
|
||||
Every region (except headers/footers) appears in exactly one article.
|
||||
AIM FOR 15-25 articles per page for a typical Telugu newspaper front page.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POLITICAL FILTER PROMPT (Step 6)
|
||||
|
||||
Model: claude-opus-4-7
|
||||
|
||||
```
|
||||
You are a senior opposition party strategist in Telangana state, India.
|
||||
|
||||
I have already cropped the following articles from this newspaper page:
|
||||
|
||||
[article IDs with headlines and positions]
|
||||
|
||||
For EACH article, ask yourself these TWO questions:
|
||||
|
||||
QUESTION 1: "Does this article describe actual DAMAGE, LOSS, DEATH, CORRUPTION, or SUFFERING happening to people in Telangana? And can the government (state OR central) be BLAMED for it — either for causing it, failing to prevent it, or failing to respond to it?"
|
||||
- The article must describe a NEGATIVE EVENT that has already occurred — not a future plan, not an announcement, not a statistic.
|
||||
- There must be a VICTIM — someone who died, lost money, was cheated, is suffering, or was harmed.
|
||||
- The government (Telangana state OR central/BJP) can be blamed — for causing it, failing to prevent it, or failing to respond to it.
|
||||
- Central government failures also qualify IF the article describes actual harm to Telangana citizens (e.g., NEET paper leak harming Telangana students, central policy causing job losses in Telangana).
|
||||
- If the article describes something POSITIVE (new scheme, development, achievement) → answer is NO.
|
||||
- If the article describes a PLAN or ANNOUNCEMENT (not something bad that happened) → answer is NO.
|
||||
- If there is NO victim and NO damage described → answer is NO.
|
||||
- RESPONSIBILITY CHECK: Ask "WHO caused this damage?" If the damage was caused by nature (fire, flood, lightning), individual negligence (reckless driving, personal accident), criminals (theft, murder), or private parties — and the government had NO role in causing or preventing it — answer is NO. Only answer YES if the government is CLEARLY responsible through its policy, negligence, corruption, or failure to act.
|
||||
- If YES → proceed to Question 2
|
||||
- If NO → REJECT this article immediately
|
||||
|
||||
QUESTION 2: "Can the opposition party DIRECTLY USE this article to attack the Telangana government in a press conference, assembly session, or public rally?"
|
||||
- If YES → SELECT this article
|
||||
- If NO → REJECT this article
|
||||
|
||||
BOTH answers must be YES to select. If either answer is NO, reject.
|
||||
|
||||
DEDUPLICATION: If two or more articles cover the SAME issue or event (e.g., same farmer protest, same accident, same scam), only SELECT the ONE with the most complete coverage or the larger article. REJECT the duplicates. Do not keep two articles about the same news story.
|
||||
|
||||
NOW go through EACH article ID I gave you. Ask Q1 and Q2 for each. Only select if BOTH are YES.
|
||||
|
||||
IMPORTANT: This application is for TELANGANA STATE politics only. Farmer issues are the MOST IMPORTANT — always select if farmers are suffering.
|
||||
|
||||
DO NOT SELECT — automatically REJECT:
|
||||
- International news (wars, foreign affairs, immigration)
|
||||
- Government achievements, new schemes, welfare announcements, development projects
|
||||
- Newspaper masthead, headers, advertisements, classifieds
|
||||
- Sports, entertainment, cinema, horoscopes
|
||||
- General statistics without actual damage (birth rate, population, GDP)
|
||||
- News about other states
|
||||
- Resignations — ALWAYS REJECT unless the article explicitly contains words like corruption, scam, fired, forced out, or political pressure. A person resigning for personal, health, family, or workload reasons is NOT a government failure.
|
||||
- PM Modi speeches or party meetings (unless specific policy failure hurting Telangana people)
|
||||
- Individual accidents (road accidents, electric shocks, drownings, fire accidents) — these are NOT government failures, they can happen due to personal negligence or bad luck. Only select if there is a MASS disaster (10+ deaths) or CLEAR systemic government negligence (e.g., bridge collapse, building collapse, factory fire due to no safety inspections).
|
||||
|
||||
Return a JSON object with TWO lists:
|
||||
|
||||
1. "reasoning": for EVERY article (selected or not), explain your thinking:
|
||||
- "id": the article ID
|
||||
- "headline_english": English translation
|
||||
- "q1": "YES" or "NO"
|
||||
- "q1_reason": why (1 sentence)
|
||||
- "q2": "YES" or "NO" (skip if q1 is NO)
|
||||
- "q2_reason": why (1 sentence, skip if q1 is NO)
|
||||
- "decision": "SELECT" or "REJECT"
|
||||
|
||||
2. "selected": only the articles where both Q1 and Q2 are YES:
|
||||
- "id": the article ID
|
||||
- "headline_english": English translation of the headline
|
||||
- "q1_answer": your answer to Question 1 (1 sentence)
|
||||
- "q2_answer": your answer to Question 2 (1 sentence)
|
||||
- "attack_angle": what opposition should say in a press conference (1 sentence)
|
||||
- "priority": "high" or "medium"
|
||||
- "category": one of corruption, governance_failure, public_grievance, law_order, health, education, infrastructure, ruling_party_crisis, farmer_issues
|
||||
|
||||
Return ONLY valid JSON. No markdown. If no articles pass both questions, return {"reasoning": [...], "selected": []}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SMART EXTRACTOR PROMPT (Combined — smart_extractor.py Step 3)
|
||||
|
||||
Model: claude-opus-4-7
|
||||
|
||||
```
|
||||
You are a senior opposition party strategist in Telangana state, India.
|
||||
|
||||
I am showing you a Telugu newspaper page image. I have also detected {num_regions} text/image regions on this page using OCR layout detection. Each region has an ID and precise pixel coordinates.
|
||||
|
||||
REGIONS:
|
||||
[list of all region IDs with types and bbox coordinates]
|
||||
|
||||
YOUR TASK: Look at the newspaper page and identify ONLY the politically significant articles. For each political article, tell me which region IDs belong to it so I can crop them together precisely.
|
||||
|
||||
For EACH article on the page, ask:
|
||||
|
||||
QUESTION 1: "Does this article describe actual DAMAGE, LOSS, DEATH, CORRUPTION, or SUFFERING happening to people in Telangana? And can the government (state OR central) be BLAMED for it?"
|
||||
- Must be a NEGATIVE EVENT that already occurred — not a plan, announcement, or statistic.
|
||||
- Must have a VICTIM — someone who died, lost money, was cheated, is suffering.
|
||||
- Government (Telangana state OR central/BJP) can be blamed — for causing, failing to prevent, or failing to respond.
|
||||
- Central government failures qualify IF actual harm to Telangana citizens.
|
||||
- RESPONSIBILITY CHECK: If damage caused by nature, individual negligence, criminals, or private parties with NO government role → NO.
|
||||
- If POSITIVE (new scheme, development, achievement) → NO.
|
||||
- If PLAN or ANNOUNCEMENT → NO.
|
||||
- If NO victim and NO damage → NO.
|
||||
|
||||
QUESTION 2: "Can the opposition party DIRECTLY USE this article to attack the government?"
|
||||
|
||||
Only include articles where BOTH answers are YES.
|
||||
|
||||
DEDUPLICATION: Same issue appearing in multiple places → group ALL related regions into ONE article.
|
||||
|
||||
TELANGANA STATE politics only. Farmer issues are MOST IMPORTANT.
|
||||
|
||||
DO NOT SELECT:
|
||||
- International news, other states news
|
||||
- Government achievements, new schemes, welfare announcements, development projects
|
||||
- Newspaper masthead, headers, ads, classifieds
|
||||
- Sports, entertainment, cinema, horoscopes
|
||||
- General statistics without actual damage
|
||||
- Resignations (unless corruption/scam/fired/forced out)
|
||||
- PM Modi speeches (unless specific policy failure hurting Telangana)
|
||||
- Individual accidents (road, electric shock, drowning, fire) — only if MASS disaster (10+ deaths) or CLEAR systemic government negligence
|
||||
|
||||
For each selected political article, return:
|
||||
- "headline_telugu": exact Telugu headline from the page
|
||||
- "headline_english": English translation
|
||||
- "member_region_ids": list of region IDs that belong to this article (for precise cropping)
|
||||
- "q1_reason": why this is government failure (1 sentence)
|
||||
- "q2_reason": how opposition can use this (1 sentence)
|
||||
- "attack_angle": what to say in press conference (1 sentence)
|
||||
- "priority": "high" or "medium"
|
||||
- "category": one of corruption, governance_failure, public_grievance, law_order, health, education, infrastructure, ruling_party_crisis, farmer_issues
|
||||
|
||||
Also return "rejected" list with brief reasoning for EVERY rejected article.
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
"political_articles": [...],
|
||||
"rejected": [
|
||||
{"headline": "...", "reason": "..."}
|
||||
]
|
||||
}
|
||||
|
||||
If no political articles found, return {"political_articles": [], "rejected": [...]}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FILES REFERENCE
|
||||
|
||||
| File | Purpose | Runs |
|
||||
|------|---------|------|
|
||||
| `app.py` | Flask web server, upload UI | `python app.py` |
|
||||
| `extractor.py` | All processing logic (Steps 2-8) | Called by app.py |
|
||||
| `smart_extractor.py` | Standalone CLI, combined approach | `python smart_extractor.py newspaper.pdf` |
|
||||
| `claude_ocr.py` | Extract Telugu text from kept images | `python claude_ocr.py` |
|
||||
| `political_filter.py` | Standalone political filter (backup) | `python political_filter.py` |
|
||||
|
||||
## API COSTS PER PAGE
|
||||
|
||||
| Approach | Claude Calls | What |
|
||||
|----------|-------------|------|
|
||||
| app.py | 2 per page | 1 grouping + 1 filtering |
|
||||
| smart_extractor.py | 1 per page | Combined grouping + filtering |
|
||||
| claude_ocr.py | 1 per article | Text extraction (optional) |
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
# Telugu Article Extractor
|
||||
|
||||
A local web app that takes a Telugu newspaper PDF and produces one PNG +
|
||||
one TXT file per article.
|
||||
|
||||
## Pipeline
|
||||
|
||||
```
|
||||
PDF
|
||||
│ Stage 1 PyMuPDF → page_001.png (target: 4200×7400 px, fits aspect)
|
||||
▼
|
||||
Pages
|
||||
│ Stage 2 PaddleOCR PP-Structure → regions.json
|
||||
│ (title / text / figure rectangles with bboxes)
|
||||
▼
|
||||
Regions
|
||||
│ Stage 3 Article grouping → articles.json
|
||||
│ Primary: Claude API (spatial reasoning over regions,
|
||||
│ sees page thumbnail + region JSON)
|
||||
│ Fallback: column-aware + dateline-anchored Python rules
|
||||
│ • title region starts a new article
|
||||
│ • "<place>, మే <day> (ఆంధ్రజ్యోతి):" dateline
|
||||
│ also starts a new article
|
||||
│ • regions partitioned by column first to avoid
|
||||
│ cross-column contamination
|
||||
▼
|
||||
Articles (bboxes)
|
||||
│ Stage 4 PIL crop → article.png per article
|
||||
▼
|
||||
Article PNGs
|
||||
│ Stage 5 Tesseract (lang=tel) → article.txt per article
|
||||
▼
|
||||
Done. Browse in the UI, download all as zip.
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. System dependencies
|
||||
|
||||
```bash
|
||||
# Ubuntu / Debian
|
||||
sudo apt update
|
||||
sudo apt install -y tesseract-ocr tesseract-ocr-tel libgl1
|
||||
```
|
||||
|
||||
`tesseract-ocr-tel` is the Telugu language data — required for the per-article
|
||||
OCR step.
|
||||
|
||||
`libgl1` is needed by paddlepaddle on headless Linux.
|
||||
|
||||
### 2. Python environment
|
||||
|
||||
```bash
|
||||
cd telugu_extractor
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
First run of paddlepaddle/paddleocr will download model weights (~400 MB)
|
||||
into `~/.paddleocr/`. This happens once.
|
||||
|
||||
### 3. (Optional) Enable Claude grouping
|
||||
|
||||
Stage 3 (article grouping) works two ways:
|
||||
|
||||
- **Without an API key**: falls back to column-aware + dateline Python
|
||||
rules. Works fine for tidy pages; struggles on banner headlines and
|
||||
cross-column layouts.
|
||||
- **With an API key**: Claude looks at a thumbnail of the page plus
|
||||
the regions JSON and does the spatial reasoning. Much better on
|
||||
complex layouts. Costs ~$0.01–0.05 per page.
|
||||
|
||||
To enable, set the environment variable before running:
|
||||
|
||||
```bash
|
||||
export ANTHROPIC_API_KEY="your-api-key-here"
|
||||
```
|
||||
|
||||
Get a key at https://console.anthropic.com/. If the variable isn't set
|
||||
or the API call fails, the app silently falls back to the Python rules.
|
||||
|
||||
### 4. Run
|
||||
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
|
||||
Then open <http://localhost:5000>.
|
||||
|
||||
## How to use
|
||||
|
||||
1. On the homepage, choose a PDF and pick a target render size.
|
||||
Defaults: 4200 × 7400 px (≈ 600 DPI for a tabloid newspaper page).
|
||||
Each page is scaled to fit *inside* this box preserving aspect.
|
||||
|
||||
2. Click "Start extraction". A background job kicks off and the page
|
||||
redirects to a job view that polls for status.
|
||||
|
||||
3. When the job finishes, every article is shown as a card with:
|
||||
- The cropped image (`article.png`)
|
||||
- A link to its OCR'd text (`article.txt`)
|
||||
- The detected dateline (e.g. `చిన్నగూడూరు, మే 15 (ఆంధ్రజ్యోతి):`)
|
||||
if the grouper found one
|
||||
- The first non-empty line of OCR text as a headline preview
|
||||
|
||||
4. Click "Download all (zip)" to grab everything in one file.
|
||||
|
||||
## What's in each job folder
|
||||
|
||||
```
|
||||
output/<timestamp>/
|
||||
├── input.pdf the uploaded PDF
|
||||
├── meta.json job metadata
|
||||
├── pages/
|
||||
│ ├── page_001.png rendered page
|
||||
│ ├── page_001.regions.json raw PaddleOCR layout output
|
||||
│ └── page_001.articles.json grouping result
|
||||
└── articles/
|
||||
└── p001_a001/
|
||||
├── article.png per-article crop
|
||||
├── article.txt per-article OCR
|
||||
└── info.json bbox + dateline + member regions
|
||||
```
|
||||
|
||||
Everything is on disk and inspectable. If a crop looks wrong, you can
|
||||
look at `pages/page_NNN.articles.json` to see exactly which regions
|
||||
were grouped together.
|
||||
|
||||
## Tuning the grouping
|
||||
|
||||
Stage 3 has two implementations in `extractor.py`:
|
||||
|
||||
### Path A: Claude API (`_group_with_claude`)
|
||||
|
||||
The system prompt is in `CLAUDE_GROUPING_PROMPT`. It tells Claude:
|
||||
- Use `title` regions as article starts
|
||||
- Use the `dateline` field as a strong "this is an article body start" signal
|
||||
- Respect column boundaries
|
||||
- Handle banner headlines that span columns
|
||||
- Pull quotes inside another article's bbox belong to that article
|
||||
|
||||
To tune, edit the prompt. To debug, look at `pages/page_NNN.articles.json`
|
||||
and check the `grouped_by` field — `"claude"` means the API call worked,
|
||||
`"rules"` means it fell back.
|
||||
|
||||
### Path B: Python rules (`_group_with_rules`)
|
||||
|
||||
Used when no API key is set or the API call fails.
|
||||
|
||||
1. **Column partition** — regions clustered by `left` coordinate.
|
||||
2. **Within each column**: `title` region OR dateline match starts a
|
||||
new article; everything else attaches to the current one.
|
||||
|
||||
To tune the rules:
|
||||
- Adjust `DATELINE_RE` for different paper conventions.
|
||||
- Adjust the column-clustering threshold in `_assign_columns`.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **L-shaped articles**: an article whose body wraps around a photo into
|
||||
a non-rectangular shape can't be captured by one bbox. The current
|
||||
pipeline produces the smallest rect that covers everything, which may
|
||||
include a sliver of a neighboring article. You'd need a polygon-based
|
||||
crop to fix that — out of scope here.
|
||||
|
||||
- **Cross-page continuations** (`మిగతా 3వ పేజీలో`): not stitched. Each
|
||||
page is processed independently.
|
||||
|
||||
- **PaddleOCR layout model is trained mostly on English/Chinese
|
||||
documents.** Expect 80–95% of articles to be bounded correctly out of
|
||||
the box. Edge cases are why the per-job folder keeps the raw
|
||||
`regions.json` — so you can audit and tune.
|
||||
|
||||
## License & data
|
||||
|
||||
All processing is local. The app never sends your PDF or anything
|
||||
extracted from it to a remote service. The PaddleOCR model weights are
|
||||
downloaded once from PaddlePaddle's CDN on first run.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2
|
||||
page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2
|
||||
page 3: 14 crops, 7 datelines | bullet titles flagged:1
|
||||
page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2
|
||||
DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2
|
||||
page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2
|
||||
page 3: 14 crops, 7 datelines | bullet titles flagged:1
|
||||
page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2
|
||||
DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2
|
||||
page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2
|
||||
page 3: 14 crops, 7 datelines | bullet titles flagged:1
|
||||
page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2
|
||||
DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2
|
||||
page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2
|
||||
page 3: 14 crops, 7 datelines | bullet titles flagged:1
|
||||
page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2
|
||||
DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2
|
||||
page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2
|
||||
page 3: 14 crops, 7 datelines | bullet titles flagged:1
|
||||
page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2
|
||||
DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2
|
||||
page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2
|
||||
page 3: 14 crops, 7 datelines | bullet titles flagged:1
|
||||
page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2
|
||||
DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
R16 text bbox=[119, 616, 612, 1899] phones=3 kw=[] :: జనగామ, మే 19 (నమస్తే తెలంగాణ) : ఆల్ ఇండియా కెమిస్
|
||||
R89 paragraph_title bbox=[121, 2887, 595, 2978] phones=0 kw=['in the court'] :: IN THE COURT OF THE HONBLE JUNIOR CIVIL JUDGE AT G
|
||||
R93 text bbox=[174, 4010, 545, 4080] phones=1 kw=['advocate'] :: ADVOCATE - JANGAON Cell: 9848259371
|
||||
R87 text bbox=[150, 5143, 604, 6267] phones=8 kw=['classified', 'contact'] :: For Classified Ads Please Contact... 9182777552 HA
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import sys, json, contextlib, io
|
||||
sys.path.insert(0, ".")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
|
||||
|
||||
def blocks_for(pg, strip_mc):
|
||||
png = D / f"page_{pg:03d}.png"
|
||||
regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
regs = se.drop_masthead_regions(regs, "andhra_jyothi", pg, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi")
|
||||
bars = separator_barriers(str(png), regs)
|
||||
if strip_mc:
|
||||
bars = [{k: v for k, v in b.items() if k not in ("mc", "anchor")} for b in bars]
|
||||
bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars)
|
||||
return {b["anchor_id"]: tuple(sorted(b["members"])) for b in bl}
|
||||
|
||||
|
||||
for pg in (1, 2, 3, 4):
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
cur = blocks_for(pg, False)
|
||||
base = blocks_for(pg, True)
|
||||
print(f"==== PAGE {pg} ====")
|
||||
changed = False
|
||||
for k in sorted(set(cur) | set(base)):
|
||||
if cur.get(k) != base.get(k):
|
||||
changed = True
|
||||
print(f" anchor {k}: base={base.get(k)}")
|
||||
print(f" curr={cur.get(k)}")
|
||||
if not changed:
|
||||
print(" (no change from mc clamp)")
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import sys, json
|
||||
sys.path.insert(0, ".")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
png = D / "page_001.png"
|
||||
regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi")
|
||||
bars = separator_barriers(str(png), regs)
|
||||
bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars)
|
||||
allmem = set()
|
||||
for b in sorted(bl, key=lambda b: (b["bbox"][1], b["bbox"][0])):
|
||||
allmem |= set(b["members"])
|
||||
print(f" {b['kind']:>1} anchor={b['anchor_id']:>3} bbox={b['bbox']} members={sorted(b['members'])}")
|
||||
present = {r["id"] for r in regs if r.get("type") not in ("header","number")}
|
||||
print("MISSING (not in any block):", sorted(present - allmem))
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import sys, json
|
||||
sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
|
||||
def headline_above(regions, start_bboxes, body, max_gap):
|
||||
cx = (body[0] + body[2]) / 2
|
||||
cands = [r for r in regions
|
||||
if (r.get("type") == "doc_title" or r.get("_promoted_from"))
|
||||
and r["bbox"][0] <= cx <= r["bbox"][2]
|
||||
and r["bbox"][3] <= body[1] + 40
|
||||
and (body[1] - r["bbox"][3]) <= max_gap]
|
||||
if not cands:
|
||||
return None, None
|
||||
h = max(cands, key=lambda r: r["bbox"][3])
|
||||
gap = body[1] - h["bbox"][3]
|
||||
for ob in start_bboxes:
|
||||
if ob is body:
|
||||
continue
|
||||
ocx = (ob[0] + ob[2]) / 2
|
||||
if h["bbox"][3] < ob[1] < body[1] and cx - 120 <= ocx <= cx + 120:
|
||||
return None, gap
|
||||
return h["id"], gap
|
||||
|
||||
for pg in (1, 2, 3, 4):
|
||||
png = D / f"page_{pg:03d}.png"
|
||||
regions = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
regions = se.drop_masthead_regions(regions, "andhra_jyothi", pg, png)
|
||||
ds = se.find_article_starts_by_dateline(regions, str(png), "andhra_jyothi")
|
||||
sb = [s["bbox"] for s in ds]
|
||||
print(f"\n==== PAGE {pg} ====")
|
||||
for s in ds:
|
||||
rid = s["region_id"]
|
||||
row = []
|
||||
for g in (900, 1000, 1100, 1300):
|
||||
hid, gap = headline_above(regions, sb, s["bbox"], g)
|
||||
row.append(f"g{g}:R{hid}" )
|
||||
print(f" DL R{rid:>3} gap_to_nearest_doc_title above -> " + " ".join(row))
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1483,838,4073,3081] 2590x2243 mem=13 {'text': 8, 'image': 3, 'figure_title': 2}
|
||||
R 4 DL bbox=[105,846,1467,4295] 1362x3449 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,3089,3031,4921] 1533x1832 mem=13 {'text': 8, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 2 DL bbox=[3039,3957,4081,6269] 1042x2312 mem=4 {'text': 2, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,3211,6283] 1711x1271 mem=5 {'doc_title': 1, 'text': 2, 'figure_title': 1, 'image': 1}
|
||||
[Containment-merge] x4
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3}
|
||||
R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3}
|
||||
R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3}
|
||||
R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 78 F bbox=[123,4139,626,4285] 503x146 mem=1 {'image': 1} IMG-ONLY(no text) SINGLE-region
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 82 F bbox=[137,4423,618,4782] 481x359 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 44 F bbox=[133,4811,616,5113] 483x302 mem=1 {'text': 1} SINGLE-region
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3}
|
||||
R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3}
|
||||
R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3}
|
||||
R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3}
|
||||
R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,2023,2859] 1910x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[113,5731,3267,6318] 3154x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=13 {'text': 8, 'image': 3, 'figure_title': 2}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,3089,3031,4921] 1533x1832 mem=13 {'doc_title': 1, 'text': 8, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 2 DL bbox=[3092,3957,4079,4960] 987x1003 mem=1 {'text': 1} SINGLE-region
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=8 {'text': 3, 'image': 2, 'doc_title': 1, 'figure_title': 2}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4078,1567] 1385x1162 mem=11 {'doc_title': 1, 'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=3 {'text': 1, 'image': 1, 'doc_title': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=13 {'text': 8, 'image': 3, 'figure_title': 2}
|
||||
R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2}
|
||||
R 28 H bbox=[1498,3089,3031,4921] 1533x1832 mem=13 {'doc_title': 1, 'text': 8, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 2 DL bbox=[3092,3957,4079,4960] 987x1003 mem=1 {'text': 1} SINGLE-region
|
||||
R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2}
|
||||
R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=8 {'text': 3, 'image': 2, 'doc_title': 1, 'figure_title': 2}
|
||||
[Containment-merge] x2
|
||||
[Headline-merge] x2
|
||||
[Banner rectangle] x4
|
||||
|
||||
=== page 2: 18 crops, 17 datelines ===
|
||||
R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 H bbox=[2693,405,4078,1567] 1385x1162 mem=11 {'doc_title': 1, 'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=3 {'text': 1, 'image': 1, 'doc_title': 1}
|
||||
R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1}
|
||||
R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1}
|
||||
R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5}
|
||||
R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region
|
||||
[Containment-merge] x10
|
||||
[Banner rectangle] x8
|
||||
|
||||
DONE -> output/NamastheTelangana_Jangaon_20260520_20260608_124720/all_article_crops_review
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
AJ pg1: 12 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
AJ pg2: 18 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
AJ pg3: 14 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
AJ pg4: 20 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
NT pg1: 11 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
NT pg2: 22 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
NT pg3: 19 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
NT pg4: 24 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
JG pg1: 7 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
JG pg2: 12 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
AJ pg1 pitch755 hbars10 base12 | thr0.6: 12 (drop6) | thr0.8: 12 (drop7) | thr1.0: 12 (drop7)
|
||||
AJ pg2 pitch719 hbars19 base18 | thr0.6: 18 (drop5) | thr0.8: 18 (drop8) | thr1.0: 18 (drop9)
|
||||
AJ pg3 pitch728 hbars15 base14 | thr0.6: 14 (drop7) | thr0.8: 13 (drop9) | thr1.0: 13 (drop9)
|
||||
AJ pg4 pitch728 hbars25 base20 | thr0.6: 20 (drop11) | thr0.8: 20 (drop13) | thr1.0: 20 (drop13)
|
||||
NT pg1 pitch536 hbars24 base11 | thr0.6: 11 (drop5) | thr0.8: 11 (drop8) | thr1.0: 11 (drop9)
|
||||
NT pg2 pitch527 hbars47 base22 | thr0.6: 22 (drop7) | thr0.8: 22 (drop10) | thr1.0: 22 (drop15)
|
||||
NT pg3 pitch525 hbars25 base19 | thr0.6: 19 (drop3) | thr0.8: 19 (drop4) | thr1.0: 19 (drop7)
|
||||
NT pg4 pitch523 hbars43 base25 | thr0.6: 25 (drop5) | thr0.8: 25 (drop8) | thr1.0: 21 (drop25)
|
||||
JG pg1 pitch601 hbars15 base7 | thr0.6: 7 (drop5) | thr0.8: 7 (drop6) | thr1.0: 7 (drop9)
|
||||
JG pg2 pitch594 hbars17 base12 | thr0.6: 12 (drop0) | thr0.8: 12 (drop0) | thr1.0: 12 (drop9)
|
||||
|
|
@ -0,0 +1,416 @@
|
|||
"""Separator-rule detection for newspaper pages (classical CV, no ML / no API).
|
||||
|
||||
Detects the thin printed grey/black straight lines the paper uses to divide
|
||||
stories, with a TEXT-ISOLATION filter to reject false positives from dense
|
||||
Telugu text (a real rule sits in a whitespace gutter; a text stroke has ink
|
||||
immediately above/below it).
|
||||
|
||||
Public:
|
||||
detect_separator_lines(png_path) -> {"h": [...], "v": [...], "size": (W,H)}
|
||||
each line is a dict: {x1,y1,x2,y2,len,gray} (gray = mean intensity).
|
||||
"""
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
|
||||
def _candidates(bw, horizontal, min_len, max_thick=55):
|
||||
if horizontal:
|
||||
k = cv2.getStructuringElement(cv2.MORPH_RECT, (min_len // 2, 1))
|
||||
else:
|
||||
k = cv2.getStructuringElement(cv2.MORPH_RECT, (1, min_len // 2))
|
||||
opened = cv2.morphologyEx(bw, cv2.MORPH_OPEN, k, iterations=1)
|
||||
# bridge small collinear gaps along the line direction
|
||||
if horizontal:
|
||||
opened = cv2.dilate(opened, cv2.getStructuringElement(cv2.MORPH_RECT, (25, 3)))
|
||||
else:
|
||||
opened = cv2.dilate(opened, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 25)))
|
||||
cnts, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
out = []
|
||||
for c in cnts:
|
||||
x, y, w, h = cv2.boundingRect(c)
|
||||
if horizontal and w >= min_len and h <= max_thick:
|
||||
out.append((x, y + h // 2, x + w, y + h // 2, w))
|
||||
if (not horizontal) and h >= min_len and w <= max_thick:
|
||||
out.append((x + w // 2, y, x + w // 2, y + h, h))
|
||||
return out
|
||||
|
||||
|
||||
def _isolated(gray, line, horizontal, ink_thresh=110, gap=(5, 16),
|
||||
max_adjacent_ink=0.12):
|
||||
"""A true separator sits in a whitespace gutter: the tight band on BOTH sides
|
||||
(parallel to the line) is mostly paper. Returns (is_isolated, mean_gray)."""
|
||||
H, W = gray.shape
|
||||
x1, y1, x2, y2, ln = line
|
||||
if horizontal:
|
||||
seg = gray[y1, x1:x2]
|
||||
lo, hi = gap
|
||||
above = gray[max(0, y1 - hi):max(0, y1 - lo), x1:x2]
|
||||
below = gray[min(H, y1 + lo):min(H, y1 + hi), x1:x2]
|
||||
else:
|
||||
seg = gray[y1:y2, x1]
|
||||
lo, hi = gap
|
||||
above = gray[y1:y2, max(0, x1 - hi):max(0, x1 - lo)]
|
||||
below = gray[y1:y2, min(W, x1 + lo):min(W, x1 + hi)]
|
||||
if seg.size == 0 or above.size == 0 or below.size == 0:
|
||||
return False, 255
|
||||
ink_a = float((above < ink_thresh).mean())
|
||||
ink_b = float((below < ink_thresh).mean())
|
||||
isolated = (ink_a <= max_adjacent_ink) and (ink_b <= max_adjacent_ink)
|
||||
return isolated, float(seg.mean())
|
||||
|
||||
|
||||
def detect_separator_lines(png_path, h_frac=0.045, v_frac=0.06):
|
||||
img = cv2.imread(str(png_path))
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
H, W = gray.shape
|
||||
blur = cv2.GaussianBlur(gray, (3, 3), 0)
|
||||
bw = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
|
||||
|
||||
h_min = int(h_frac * W)
|
||||
v_min = int(v_frac * H)
|
||||
h_out, v_out = [], []
|
||||
for ln in _candidates(bw, True, h_min):
|
||||
iso, g = _isolated(gray, ln, True)
|
||||
if iso:
|
||||
h_out.append({"x1": ln[0], "y1": ln[1], "x2": ln[2], "y2": ln[3],
|
||||
"len": ln[4], "gray": round(g, 1)})
|
||||
for ln in _candidates(bw, False, v_min):
|
||||
iso, g = _isolated(gray, ln, False)
|
||||
if iso:
|
||||
v_out.append({"x1": ln[0], "y1": ln[1], "x2": ln[2], "y2": ln[3],
|
||||
"len": ln[4], "gray": round(g, 1)})
|
||||
return {"h": h_out, "v": v_out, "size": (W, H)}
|
||||
|
||||
|
||||
def detect_content_bottom(png_path, search_frac=0.12, color_thr=0.06,
|
||||
blank_color=0.02, blank_ink=0.035, peak_thr=0.15,
|
||||
max_band=160, min_gap=25, min_margin=18):
|
||||
"""Find the y below which a page holds only the printer's COLOUR-CALIBRATION
|
||||
strip (the row of CMYK registration dots + grey bars) and the bottom paper
|
||||
margin — i.e. the bottom of real article content.
|
||||
|
||||
The calibration strip is a thin band of strongly-saturated colour dots near
|
||||
the page bottom, isolated by a white paper margin BELOW it (down to the page
|
||||
edge) and a white gap ABOVE it (separating it from article content). Crops
|
||||
should be clamped to the returned y so the dots never bleed into an article.
|
||||
|
||||
Returns the y at the TOP of the calibration band, or the full page height H
|
||||
when no such strip is found (nothing to clamp)."""
|
||||
img = cv2.imread(str(png_path))
|
||||
if img is None:
|
||||
return None
|
||||
H, W = img.shape[:2]
|
||||
b, g, r = img[..., 0].astype(np.int16), img[..., 1].astype(np.int16), img[..., 2].astype(np.int16)
|
||||
mx = np.maximum(np.maximum(r, g), b)
|
||||
mn = np.minimum(np.minimum(r, g), b)
|
||||
sat = mx - mn
|
||||
colored = (sat > 55) & (mx > 80) # saturated colour (registration dots)
|
||||
dark = mx < 110 # ink / dark
|
||||
col_frac = colored.mean(axis=1) # per-row colour fraction
|
||||
ink_frac = dark.mean(axis=1) # per-row ink fraction
|
||||
blank = (col_frac < blank_color) & (ink_frac < blank_ink)
|
||||
|
||||
y0 = int(H * (1 - search_frac))
|
||||
# The calibration strip is a band of strongly-coloured rows; identify it as the
|
||||
# bottom-most run of rows whose colour fraction clears `color_thr`.
|
||||
strip_rows = [y for y in range(y0, H) if col_frac[y] >= color_thr]
|
||||
if not strip_rows:
|
||||
return H # no coloured strip near the bottom
|
||||
band_bottom = strip_rows[-1]
|
||||
# A real calibration strip is followed by white paper margin to the page edge.
|
||||
below = blank[band_bottom + 1:H]
|
||||
if below.size < min_margin or float(below.mean()) < 0.9:
|
||||
return H
|
||||
# Walk up from band_bottom while still in the coloured band (tolerate the small
|
||||
# white gaps between dot rows).
|
||||
band_top = band_bottom
|
||||
gap = 0
|
||||
y = band_bottom - 1
|
||||
while y > y0:
|
||||
if col_frac[y] >= color_thr:
|
||||
band_top = y
|
||||
gap = 0
|
||||
else:
|
||||
gap += 1
|
||||
if gap > 12:
|
||||
break
|
||||
y -= 1
|
||||
if (band_bottom - band_top + 1) > max_band:
|
||||
return H # too tall -> fused with a photo, bail
|
||||
# A genuine printer calibration strip is a dense row of saturated CMYK
|
||||
# registration dots: its peak per-row colour fraction is high (~0.22-0.45 across
|
||||
# Andhra Jyothi / Sakshi). A single-hue coloured ad/notice box embedded in
|
||||
# article text peaks far lower (~0.11) -> reject it as a false positive.
|
||||
peak = float(col_frac[band_top:band_bottom + 1].max())
|
||||
if peak < peak_thr:
|
||||
return H
|
||||
return band_top
|
||||
|
||||
|
||||
def _hspan_overlap(ax1, ax2, bx1, bx2):
|
||||
ix = max(0, min(ax2, bx2) - max(ax1, bx1))
|
||||
return ix / max(1, min(ax2 - ax1, bx2 - bx1))
|
||||
|
||||
|
||||
def _faint_rule_above(gray, hbbox, max_gap=170, min_gap=6, gray_lo=140, gray_hi=215,
|
||||
cover=0.6, max_dark=0.06):
|
||||
"""Find a faint GREY horizontal rule sitting in the whitespace directly above a
|
||||
(multi-column) header. Such a light rule reads as background to the ink-based
|
||||
Otsu detector in `detect_separator_lines`, so we look for a thin row that is
|
||||
mostly uniform mid-grey across the header's width and is isolated by white paper
|
||||
above and below. Returns the rule's y, or None. (Used only above multi-column
|
||||
headers, where it marks the article's TOP boundary.)"""
|
||||
H, W = gray.shape
|
||||
hx1, hy, hx2 = hbbox[0], hbbox[1], hbbox[2]
|
||||
y_hi = max(0, hy - min_gap)
|
||||
y_lo = max(0, hy - max_gap)
|
||||
for y in range(y_hi, y_lo, -1):
|
||||
row = gray[y, hx1:hx2].astype(np.int16)
|
||||
if row.size == 0:
|
||||
continue
|
||||
mid = float(((row >= gray_lo) & (row <= gray_hi)).mean())
|
||||
dark = float((row < gray_lo).mean())
|
||||
if mid >= cover and dark <= max_dark:
|
||||
above = gray[max(0, y - 6):max(0, y - 2), hx1:hx2]
|
||||
below = gray[min(H, y + 2):min(H, y + 6), hx1:hx2]
|
||||
if (above.size and below.size
|
||||
and float((above > gray_hi).mean()) > 0.85
|
||||
and float((below > gray_hi).mean()) > 0.85):
|
||||
return y
|
||||
return None
|
||||
|
||||
|
||||
def _faint_grey_band_above(gray, hbbox, max_gap=185, min_gap=6, max_thick=12,
|
||||
gray_lo=135, gray_hi=232, cover=0.8, max_dark=0.08,
|
||||
white_thr=235, white_cover=0.9):
|
||||
"""Find a faint GREY horizontal rule (1-`max_thick` px thick) sitting in the
|
||||
whitespace directly above a SINGLE-column header. Per the layout convention a
|
||||
grey rule whose length matches the article/header width marks the boundary
|
||||
between two stacked stories, so the next story's headline must not fold into
|
||||
the article above the rule. Such light rules read as background to the ink-based
|
||||
Otsu detector in `detect_separator_lines`, and `_faint_rule_above` only accepts
|
||||
a 1-px isolated rule, so a thicker grey band is missed; here we group the band
|
||||
and require it to span the header's width and be isolated by white paper above
|
||||
and below. Returns the band's centre y, or None."""
|
||||
H, W = gray.shape
|
||||
hx1, hy, hx2 = int(hbbox[0]), int(hbbox[1]), int(hbbox[2])
|
||||
y_hi = max(0, hy - min_gap)
|
||||
y_lo = max(0, hy - max_gap)
|
||||
cols = slice(hx1, hx2)
|
||||
grey_rows = []
|
||||
for y in range(y_lo, y_hi):
|
||||
row = gray[y, cols].astype(np.int16)
|
||||
if row.size == 0:
|
||||
continue
|
||||
mid = float(((row >= gray_lo) & (row <= gray_hi)).mean())
|
||||
dark = float((row < gray_lo).mean())
|
||||
if mid >= cover and dark <= max_dark:
|
||||
grey_rows.append(y)
|
||||
if not grey_rows:
|
||||
return None
|
||||
bands = []
|
||||
s = p = grey_rows[0]
|
||||
for y in grey_rows[1:]:
|
||||
if y == p + 1:
|
||||
p = y
|
||||
else:
|
||||
bands.append((s, p)); s = p = y
|
||||
bands.append((s, p))
|
||||
for top, bot in sorted(bands, key=lambda b: -b[1]): # nearest the header first
|
||||
if bot - top + 1 > max_thick:
|
||||
continue
|
||||
above = gray[max(0, top - 4):top, cols]
|
||||
below = gray[bot + 1:min(H, bot + 5), cols]
|
||||
if (above.size and below.size
|
||||
and float((above > white_thr).mean()) >= white_cover
|
||||
and float((below > white_thr).mean()) >= white_cover):
|
||||
return (top + bot) // 2
|
||||
return None
|
||||
|
||||
|
||||
def _faint_grey_band_below(gray, bbox, max_gap=150, min_gap=4, max_thick=12,
|
||||
gray_lo=135, gray_hi=232, cover=0.8, max_dark=0.08,
|
||||
white_thr=235, white_cover=0.9):
|
||||
"""Mirror of `_faint_grey_band_above`, searching DOWNWARD: find the faint grey
|
||||
rule that sits in the whitespace just below an article (within `max_gap` px of
|
||||
its bottom edge) and spans its column width. That rule is the article's BOTTOM
|
||||
boundary, so the crop can be cut precisely at it. Returns the band's top y (the
|
||||
cut line), or None when no clean full-width grey rule is found below."""
|
||||
H, W = gray.shape
|
||||
bx1, by, bx2 = int(bbox[0]), int(bbox[3]), int(bbox[2])
|
||||
y_lo = min(H, by + min_gap)
|
||||
y_hi = min(H, by + max_gap)
|
||||
cols = slice(bx1, bx2)
|
||||
grey_rows = []
|
||||
for y in range(y_lo, y_hi):
|
||||
row = gray[y, cols].astype(np.int16)
|
||||
if row.size == 0:
|
||||
continue
|
||||
mid = float(((row >= gray_lo) & (row <= gray_hi)).mean())
|
||||
dark = float((row < gray_lo).mean())
|
||||
if mid >= cover and dark <= max_dark:
|
||||
grey_rows.append(y)
|
||||
if not grey_rows:
|
||||
return None
|
||||
bands = []
|
||||
s = p = grey_rows[0]
|
||||
for y in grey_rows[1:]:
|
||||
if y == p + 1:
|
||||
p = y
|
||||
else:
|
||||
bands.append((s, p)); s = p = y
|
||||
bands.append((s, p))
|
||||
for top, bot in sorted(bands, key=lambda b: b[0]): # nearest below first
|
||||
if bot - top + 1 > max_thick:
|
||||
continue
|
||||
# Skip the 1-px anti-aliased fade row hugging the rule before checking for
|
||||
# the white paper gutter above and below it.
|
||||
above = gray[max(0, top - 7):max(0, top - 2), cols]
|
||||
below = gray[bot + 2:min(H, bot + 7), cols]
|
||||
if (above.size and below.size
|
||||
and float((above > white_thr).mean()) >= white_cover
|
||||
and float((below > white_thr).mean()) >= white_cover):
|
||||
return top
|
||||
return None
|
||||
|
||||
|
||||
def separator_barriers(png_path, regions, near=80, min_overlap=0.3,
|
||||
title_types=("doc_title", "paragraph_title", "figure_title"),
|
||||
multicol_frac=0.22):
|
||||
"""Article-boundary rules: the horizontal printed lines that mark the END of a
|
||||
story. Per the layout convention, a rule with NORMAL text (or whitespace) above
|
||||
it separates two stacked articles, while a rule sitting right under a BOLD
|
||||
headline/title is a decorative flourish and must NOT split anything.
|
||||
|
||||
We approximate 'bold above' by a title-type region (doc_title / paragraph_title
|
||||
/ figure_title) whose bottom edge is within `near` px above the rule and that
|
||||
horizontally overlaps it. Such rules are dropped; the rest are returned as
|
||||
barriers {y, x1, x2} for the clusterer to forbid cross-line folding.
|
||||
|
||||
Additionally, for every MULTI-COLUMN header (a doc_title at least `multicol_frac`
|
||||
of the page width), we look for a faint grey rule directly above it and add it as
|
||||
a barrier spanning the header's width: that rule is the article's TOP boundary, so
|
||||
nothing above it folds into the multi-column article below."""
|
||||
res = detect_separator_lines(png_path)
|
||||
|
||||
# A real article separator sits in a WHITESPACE GUTTER between two stacked
|
||||
# boxes; it never lands deep inside a body-text region. PaddleOCR's morphology
|
||||
# occasionally mistakes a dense Telugu text stroke for a thin rule, producing a
|
||||
# phantom line straight through a paragraph. Reject any detected rule whose
|
||||
# midpoint falls well inside (margin-shrunk) a 'text' box it column-overlaps.
|
||||
_text_boxes = [r["bbox"] for r in regions if r.get("type") == "text"]
|
||||
|
||||
def _in_text(y, lx1, lx2, margin=28):
|
||||
mx = (lx1 + lx2) / 2
|
||||
for tx1, ty1, tx2, ty2 in _text_boxes:
|
||||
if (tx1 <= mx <= tx2
|
||||
and ty1 + margin <= y <= ty2 - margin
|
||||
and _hspan_overlap(lx1, lx2, tx1, tx2) >= min_overlap):
|
||||
return True
|
||||
return False
|
||||
|
||||
# Column width (median text-region width). A horizontal line counts as an article
|
||||
# separator only when it spans most of a column. NOTE: a strict ≥1.0× column floor is
|
||||
# too aggressive — a SINGLE-column article's own boundary rule is itself <1 column wide,
|
||||
# so ≥1.0× drops real separators and merges articles (measured: NT pg4 R121 → 2 datelines).
|
||||
# 0.6× column is the safe floor: it removes only the short caption / decorative underlines
|
||||
# and merges NO articles on AJ / NT / JG.
|
||||
_twid = sorted((r["bbox"][2] - r["bbox"][0]) for r in regions if r.get("type") == "text")
|
||||
_pitch = _twid[len(_twid) // 2] if _twid else 0
|
||||
_len_floor = 0.6 * _pitch
|
||||
|
||||
bars = []
|
||||
for L in res["h"]:
|
||||
y, lx1, lx2 = L["y1"], L["x1"], L["x2"]
|
||||
if _in_text(y, lx1, lx2):
|
||||
continue
|
||||
if _pitch and (lx2 - lx1) < _len_floor:
|
||||
continue # too short to be an article separator (caption/underline)
|
||||
bold_above = False
|
||||
title_w_above = 0
|
||||
for r in regions:
|
||||
b = r["bbox"]
|
||||
if (b[3] <= y and (y - b[3]) <= near
|
||||
and r.get("type") in title_types
|
||||
and _hspan_overlap(lx1, lx2, b[0], b[2]) >= min_overlap):
|
||||
bold_above = True
|
||||
title_w_above = max(title_w_above, b[2] - b[0])
|
||||
# A rule under a bold title is a decorative flourish ONLY when it merely
|
||||
# underlines that title (rule width ≈ title width). A rule spanning much
|
||||
# WIDER than the title above it runs across several columns — e.g. a photo
|
||||
# caption (figure_title) sits above ONE column while the rule runs the FULL
|
||||
# article width — so it is a genuine article boundary and must be kept.
|
||||
if (not bold_above) or ((lx2 - lx1) > 1.5 * title_w_above):
|
||||
bars.append({"y": y, "x1": lx1, "x2": lx2})
|
||||
|
||||
gray = cv2.cvtColor(cv2.imread(str(png_path)), cv2.COLOR_BGR2GRAY)
|
||||
W = gray.shape[1]
|
||||
_img_boxes = [r["bbox"] for r in regions if r.get("type") == "image"]
|
||||
|
||||
def _lead_photo_above(yb, hx1, hx2, gap=80):
|
||||
"""A faint rule directly under the article's OWN lead photo is that photo's
|
||||
caption underline, not the article's top boundary. If an image sits flush
|
||||
(within `gap`px) above the rule and overlaps the header's width, the rule must
|
||||
NOT bound the article — otherwise the lead photo gets cut off."""
|
||||
for ix1, iy1, ix2, iy2 in _img_boxes:
|
||||
if (0 <= yb - iy2 <= gap
|
||||
and _hspan_overlap(hx1, hx2, ix1, ix2) >= min_overlap):
|
||||
return True
|
||||
return False
|
||||
|
||||
for r in regions:
|
||||
if r.get("type") != "doc_title":
|
||||
continue
|
||||
b = r["bbox"]
|
||||
if (b[2] - b[0]) < multicol_frac * W:
|
||||
continue # single-column header → skip
|
||||
yb = _faint_rule_above(gray, b)
|
||||
if yb is not None and not _lead_photo_above(yb, b[0], b[2]):
|
||||
bars.append({"y": yb, "x1": b[0], "x2": b[2],
|
||||
"mc": True, "anchor": r["id"]})
|
||||
|
||||
# Same rule for SINGLE-column headers: a faint grey rule spanning the header's
|
||||
# width directly above it bounds the article ABOVE it, so the header (and its
|
||||
# story) cannot fold upward across the rule. Plain barrier (no mc clamp).
|
||||
for r in regions:
|
||||
if r.get("type") not in ("doc_title", "paragraph_title"):
|
||||
continue
|
||||
b = r["bbox"]
|
||||
if (b[2] - b[0]) >= multicol_frac * W:
|
||||
continue # multi-column → handled above
|
||||
yb = _faint_grey_band_above(gray, b)
|
||||
if yb is not None and not _lead_photo_above(yb, b[0], b[2]):
|
||||
bars.append({"y": yb, "x1": b[0], "x2": b[2]})
|
||||
|
||||
# Vertical column-divider rules. detect_separator_lines already requires each
|
||||
# line to sit in a whitespace gutter (isolated on both sides), so photo/text
|
||||
# internal strokes are filtered out. These fence rightward column-growth: an
|
||||
# article must not grow across a printed vertical rule into the next column.
|
||||
for L in res["v"]:
|
||||
bars.append({"vert": True, "x": (L["x1"] + L["x2"]) // 2,
|
||||
"y1": min(L["y1"], L["y2"]), "y2": max(L["y1"], L["y2"])})
|
||||
return bars
|
||||
|
||||
|
||||
def overlay(png_path, lines, out_path):
|
||||
img = cv2.imread(str(png_path))
|
||||
for L in lines["h"]:
|
||||
cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (0, 0, 255), 6)
|
||||
for L in lines["v"]:
|
||||
cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (255, 0, 0), 6)
|
||||
cv2.imwrite(str(out_path), img)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
from pathlib import Path
|
||||
p = Path(sys.argv[1])
|
||||
res = detect_separator_lines(p)
|
||||
print(f"{p.name} {res['size']} H={len(res['h'])} V={len(res['v'])}")
|
||||
for L in sorted(res["h"], key=lambda d: d["y1"]):
|
||||
print(f" H y={L['y1']:>5} x[{L['x1']:>4}..{L['x2']:>4}] len={L['len']:>4} gray={L['gray']}")
|
||||
for L in sorted(res["v"], key=lambda d: d["x1"]):
|
||||
print(f" V x={L['x1']:>5} y[{L['y1']:>4}..{L['y2']:>4}] len={L['len']:>4} gray={L['gray']}")
|
||||
out = Path(sys.argv[2]) if len(sys.argv) > 2 else Path(f"/tmp/lines_{p.stem}.png")
|
||||
overlay(p, res, out)
|
||||
print("overlay:", out)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
WITH ≥1col floor: 24 blocks
|
||||
R67 H 4DL members=[5, 7, 28, 34, 42, 48, 50, 67, 68, 73, 74, 80, 100, 102, 107, 127, 135]
|
||||
R121 H 2DL members=[12, 14, 21, 39, 59, 111, 116, 121]
|
||||
anchors: R23,R67,R81,R85,R87,R89,R90,R91,R93,R94,R95,R96,R97,R98,R101,R103,R108,R118,R119,R121,R122,R128,R131,R132
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110, 105] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 28 crops, 25 datelines, 2+dl-blocks=[80] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4
|
||||
page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] |
|
||||
page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] |
|
||||
page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] |
|
||||
DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
=== page 1: 5 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL5 [668,901,4084,6302] 3416x5401 mem=22
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 5 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL5 [668,901,4084,6302] 3416x5401 mem=22
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 5 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL5 [668,901,4084,6302] 3416x5401 mem=22
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 5 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL5 [668,901,4084,6302] 3416x5401 mem=22
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 5 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL5 [668,901,4084,6302] 3416x5401 mem=22
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 5 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL5 [668,901,4084,6302] 3416x5401 mem=22
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 5 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL5 [668,901,4084,6302] 3416x5401 mem=22
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL56 [1265,901,4079,4724] 2814x3823 mem=11
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL56 [1265,901,4079,4724] 2814x3823 mem=11
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL56 [1265,901,4079,4724] 2814x3823 mem=11
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL56 [1265,901,4079,4724] 2814x3823 mem=11
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL56 [1265,901,4079,4724] 2814x3823 mem=11
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL56 [1265,901,4079,4724] 2814x3823 mem=11
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=21
|
||||
DL56 [1265,901,4079,4724] 2814x3823 mem=11
|
||||
DL9 [105,2334,1197,6302] 1092x3968 mem=5
|
||||
H59 [112,2762,3229,4860] 3117x2098 mem=13
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
DONE -> output/NamastheTelangana_Adilabad_20260528_20260610_160056/all_article_crops_review
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 2: 30 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,4979] 468x1493 mem=3
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [610,4170,1497,4966] 887x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
DL26 [154,4987,1498,5443] 1344x456 mem=3
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [114,5467,1498,6269] 1384x802 mem=3
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [590,5993,1498,6302] 908x309 mem=2
|
||||
=== page 2: 30 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,4979] 468x1493 mem=3
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [610,4170,1497,4966] 887x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
DL26 [154,4987,1498,5443] 1344x456 mem=3
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [114,5467,1498,6269] 1384x802 mem=3
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [590,5993,1498,6302] 908x309 mem=2
|
||||
=== page 2: 30 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,4979] 468x1493 mem=3
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [610,4170,1497,4966] 887x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
DL26 [154,4987,1498,5443] 1344x456 mem=3
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [114,5467,1498,6269] 1384x802 mem=3
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [590,5993,1498,6302] 908x309 mem=2
|
||||
=== page 2: 30 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,4979] 468x1493 mem=3
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [610,4170,1497,4966] 887x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
DL26 [154,4987,1498,5443] 1344x456 mem=3
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [114,5467,1498,6269] 1384x802 mem=3
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [590,5993,1498,6302] 908x309 mem=2
|
||||
=== page 2: 30 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,4979] 468x1493 mem=3
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [610,4170,1497,4966] 887x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
DL26 [154,4987,1498,5443] 1344x456 mem=3
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [114,5467,1498,6269] 1384x802 mem=3
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [590,5993,1498,6302] 908x309 mem=2
|
||||
=== page 2: 30 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,4979] 468x1493 mem=3
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [610,4170,1497,4966] 887x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
DL26 [154,4987,1498,5443] 1344x456 mem=3
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [114,5467,1498,6269] 1384x802 mem=3
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [590,5993,1498,6302] 908x309 mem=2
|
||||
=== page 2: 30 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,4979] 468x1493 mem=3
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [610,4170,1497,4966] 887x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
DL26 [154,4987,1498,5443] 1344x456 mem=3
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [114,5467,1498,6269] 1384x802 mem=3
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [590,5993,1498,6302] 908x309 mem=2
|
||||
DONE -> output/NamastheTelangana_Adilabad_20260528_20260610_160056/all_article_crops_review
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 1: 6 crops, 6 datelines ===
|
||||
H44 [106,111,4084,3144] 3978x3033 mem=23
|
||||
DL9 [105,2334,1200,6302] 1095x3968 mem=6
|
||||
DL13 [1320,2761,4079,4724] 2759x1963 mem=14
|
||||
H59 [115,3752,3228,4860] 3113x1108 mem=7
|
||||
H41 [2577,4793,4084,6309] 1507x1516 mem=4
|
||||
H30 [668,4829,3208,6302] 2540x1473 mem=11
|
||||
─ NT late rule-split: R5 → 2 bands at structural rules [4764]
|
||||
🖼 Orphan photo: R38 → article R5 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
=== page 2: 31 crops, 30 datelines ===
|
||||
H80 [1833,465,3228,1814] 1395x1349 mem=6
|
||||
H65 [3293,465,4079,987] 786x522 mem=2
|
||||
H84 [106,501,1776,1820] 1670x1319 mem=6
|
||||
H43 [3292,1014,4079,1562] 787x548 mem=2
|
||||
DL9 [3292,1590,4079,2136] 787x546 mem=2
|
||||
H78 [1838,1678,2517,1805] 679x127 mem=2
|
||||
DL7 [104,1851,923,2566] 819x715 mem=3
|
||||
H74 [981,1883,2350,3060] 1369x1177 mem=4
|
||||
H72 [2408,1884,3227,2713] 819x829 mem=2
|
||||
DL5 [3292,2167,4079,2759] 787x592 mem=2
|
||||
DL23 [104,2596,922,2998] 818x402 mem=2
|
||||
H58 [2408,2772,3226,3479] 818x707 mem=2
|
||||
DL13 [3292,2787,4079,3333] 787x546 mem=2
|
||||
DL20 [106,3050,923,3478] 817x428 mem=2
|
||||
H60 [981,3117,2351,3479] 1370x362 mem=3
|
||||
DL1 [3293,3382,4079,4190] 786x808 mem=2
|
||||
P67 [131,3486,599,5211] 468x1725 mem=4
|
||||
DL10 [1559,3528,3226,4291] 1667x763 mem=4
|
||||
P63 [677,3558,1499,4144] 822x586 mem=2
|
||||
H50 [678,4170,1497,4966] 819x796 mem=2
|
||||
DL12 [3292,4217,4079,4815] 787x598 mem=2
|
||||
H71 [1560,4365,3226,4958] 1666x593 mem=3
|
||||
H51 [3292,4842,4079,5479] 787x637 mem=2
|
||||
DL41 [1561,4960,3225,5110] 1664x150 mem=2
|
||||
H54 [678,4987,1498,5443] 820x456 mem=2
|
||||
H76 [1559,5171,3228,5881] 1669x710 mem=5
|
||||
H53 [677,5467,1498,5964] 821x497 mem=2
|
||||
H83 [3291,5509,4079,6303] 788x794 mem=3
|
||||
H56 [1559,5944,3228,6302] 1669x358 mem=3
|
||||
H46 [680,5993,1498,6302] 818x309 mem=2
|
||||
O79 [152,6141,590,6257] 438x116 mem=1
|
||||
🖼 Orphan photo: R90 → article R67 (an image must belong to an article)
|
||||
DONE -> output/NamastheTelangana_Adilabad_20260528_20260610_160056/all_article_crops_review
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import sys, json, contextlib, io
|
||||
sys.path.insert(0, ".")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
for pg in (2, 3, 4):
|
||||
png = D / f"page_{pg:03d}.png"
|
||||
regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
regs = se.drop_masthead_regions(regs, "andhra_jyothi", pg, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi")
|
||||
bars = separator_barriers(str(png), regs)
|
||||
bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars)
|
||||
dl_ids = {s["region_id"] for s in ds}
|
||||
n_dl = sum(1 for b in bl if any(m in dl_ids for m in b["members"]))
|
||||
orph = [b for b in bl if b["kind"] == "O"]
|
||||
print(f"==== PAGE {pg}: {len(bl)} blocks, {n_dl} dateline, {len(orph)} orphan ====")
|
||||
for b in orph:
|
||||
print(f" O anchor={b['anchor_id']} bbox={b['bbox']} members={sorted(b['members'])}")
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
"""TEST (read-only): finalize article boundaries using the RIGHTMOST dead-end (nearest big
|
||||
vertical wall to the right, else page edge) and the TOPMOST dead-end (masthead bottom, for
|
||||
top-row articles). Draw both the original block boundary (thin gray) and the dead-end-snapped
|
||||
boundary (thick colour) on a blank canvas, plus the big vertical walls (red) and the masthead
|
||||
band. No smart_extractor change, no API. Test on 1-2 pages."""
|
||||
import os, tempfile, json, io, contextlib, statistics
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers, detect_separator_lines
|
||||
|
||||
BIG_FRAC = 0.45
|
||||
|
||||
def big_walls(png):
|
||||
res = detect_separator_lines(png); W, H = res["size"]
|
||||
out = []
|
||||
for L in res["v"]:
|
||||
y1, y2 = min(L["y1"], L["y2"]), max(L["y1"], L["y2"])
|
||||
if (y2 - y1) >= BIG_FRAC * H:
|
||||
out.append({"x": (L["x1"]+L["x2"])//2, "y1": y1, "y2": y2})
|
||||
return out, (W, H)
|
||||
|
||||
def masthead_bottom(png, raw, paper, pg, W, H):
|
||||
# compute from RAW regions (before masthead removal) so the dropped band's bottom is visible
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
dd = se.dedup_overlapping_regions([dict(r) for r in raw])
|
||||
kept = se.drop_masthead_regions([dict(r) for r in dd], paper, pg, png)
|
||||
drop_bottom = max((r["bbox"][3] for r in dd
|
||||
if r["id"] not in {k["id"] for k in kept}), default=0)
|
||||
res = detect_separator_lines(png)
|
||||
wide = sorted([L for L in res["h"] if (L["x2"]-L["x1"]) >= 0.30*W
|
||||
and L["y1"] < 0.20*H], key=lambda L: L["y1"])
|
||||
top_rule = wide[0]["y1"] if wide else 0
|
||||
return max(drop_bottom, top_rule)
|
||||
|
||||
def run(pdir, pg, paper, tag):
|
||||
png = f"{pdir}/page_{pg:03d}.png"
|
||||
raw = json.loads(Path(f"{pdir}/page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
regs = se.dedup_overlapping_regions(raw); regs = se.merge_stacked_title_lines(regs, png)
|
||||
regs = se.drop_masthead_regions(regs, paper, pg, png); regs = se.promote_paragraph_titles(regs, png, paper); regs = se.mark_bullet_titles(regs, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, png, paper)
|
||||
_p = se.cluster_all_article_blocks(regs, ds, sep_lines=separator_barriers(png, regs))
|
||||
if se.recover_orphan_text_headlines(_p, regs, png): ds = se.find_article_starts_by_dateline(regs, png, paper)
|
||||
bars = separator_barriers(png, regs)
|
||||
blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
walls, (W, H) = big_walls(png)
|
||||
cright = max((r["bbox"][2] for r in regs), default=W)
|
||||
mh = masthead_bottom(png, raw, paper, pg, W, H)
|
||||
top_row_cut = mh + 320 # an article whose top is within this band is "top row"
|
||||
|
||||
def deadends(b):
|
||||
x1, y1, x2, y2 = b["bbox"]; cx = (x1 + x2) / 2; bh = y2 - y1
|
||||
# rightmost dead-end: nearest big wall right of the block centre that spans it; else page edge
|
||||
rcand = [w["x"] for w in walls if w["x"] > cx
|
||||
and max(0, min(y2, w["y2"]) - max(y1, w["y1"])) >= 0.4 * bh]
|
||||
right = min(rcand) if rcand else cright
|
||||
right = max(right, x2) # never shrink
|
||||
# topmost dead-end: top-row article → up to masthead bottom
|
||||
top = mh if (y1 <= top_row_cut and mh > 0) else y1
|
||||
top = min(top, y1) # never shrink downward
|
||||
return [x1, top, right, y2]
|
||||
|
||||
img = Image.new("RGB", (W, H), "white"); d = ImageDraw.Draw(img)
|
||||
try: font = ImageFont.truetype("DejaVuSans-Bold.ttf", 30)
|
||||
except Exception: font = ImageFont.load_default()
|
||||
if mh > 4:
|
||||
d.rectangle([0, 0, W, mh], fill=(232,232,232)); d.line([0,mh,W,mh], fill=(140,140,140), width=5)
|
||||
d.text((14, max(2, mh//2-16)), "MASTHEAD (top dead-end)", fill=(110,110,110), font=font)
|
||||
for w in walls:
|
||||
d.line([w["x"], w["y1"], w["x"], w["y2"]], fill=(235,70,70), width=8)
|
||||
pal = se._ARTICLE_COLORS
|
||||
for i, b in enumerate(blocks):
|
||||
ox1, oy1, ox2, oy2 = b["bbox"]; nx1, ny1, nx2, ny2 = deadends(b); c = pal[i % len(pal)]
|
||||
d.rectangle([ox1, oy1, ox2, oy2], outline=(180,180,180), width=3) # original (gray)
|
||||
d.rectangle([nx1, ny1, nx2, ny2], outline=c, width=8) # dead-end (color)
|
||||
lab = f"#{b['anchor_id']} [{b['kind']}]"
|
||||
d.rectangle([nx1+5, ny1+6, nx1+16+len(lab)*15, ny1+42], fill=c)
|
||||
d.text((nx1+11, ny1+9), lab, fill="white", font=font)
|
||||
out = f"{pdir}/page_{pg:03d}_partition_debug.png"; img.save(out)
|
||||
print(f"{tag} pg{pg}: {len(blocks)} blocks, {len(walls)} walls, masthead_bottom={int(mh)} -> {out}")
|
||||
|
||||
run("output/NamastheTelangana_Siddipet_20260602_20260604_214937/pages", 2, "namaste_telangana", "NT")
|
||||
run("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages", 1, "andhra_jyothi", "AJ")
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import sys, types; sys.modules.setdefault("fitz", types.ModuleType("fitz"))
|
||||
import os, tempfile, json
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104")
|
||||
png = str(RUN/"pages/page_001.png")
|
||||
regions = json.loads((RUN/"pages/page_001.regions.json").read_text())["regions"]
|
||||
regions = se.dedup_overlapping_regions(regions)
|
||||
regions = se.merge_stacked_title_lines(regions, png)
|
||||
regions = se.drop_masthead_regions(regions, "sakshi", 1, png)
|
||||
regions = se.promote_paragraph_titles(regions, png, "sakshi")
|
||||
dls = se.find_article_starts_by_dateline(regions, png, "sakshi")
|
||||
seps = separator_barriers(png, regions)
|
||||
blocks = se.cluster_all_article_blocks(regions, dls, sep_lines=seps)
|
||||
rmap = {r['id']:r for r in regions}
|
||||
for b in blocks:
|
||||
if b['anchor_id']==71:
|
||||
print("BLOCK:", {k:v for k,v in b.items() if k!='members'})
|
||||
print("members:")
|
||||
for m in sorted(b['members']+[b['anchor_id']], key=lambda m: rmap[m]['bbox'][1] if m in rmap else 0):
|
||||
r = rmap.get(m)
|
||||
print(" ", m, r['type'] if r else '?', r['bbox'] if r else '?')
|
||||
json.dump({'blocks':[{'anchor':b['anchor_id'],'kind':b['kind'],'bbox':b['bbox'],'members':b['members']} for b in blocks]}, open('/tmp/blocks71.json','w'))
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import sys, json
|
||||
sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
for pg in (1, 2, 3, 4):
|
||||
png = D / f"page_{pg:03d}.png"
|
||||
regions = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
regions = se.drop_masthead_regions(regions, "andhra_jyothi", pg, png)
|
||||
ds = se.find_article_starts_by_dateline(regions, str(png), "andhra_jyothi")
|
||||
bars = separator_barriers(str(png), regions)
|
||||
blocks = se.cluster_all_article_blocks(regions, dateline_starts=ds, sep_lines=bars)
|
||||
rmap = {r["id"]: r for r in regions}
|
||||
print(f"\n==== PAGE {pg} ====")
|
||||
for b in blocks:
|
||||
anchor = rmap.get(b["anchor_id"])
|
||||
if not anchor:
|
||||
continue
|
||||
atop = anchor["bbox"][1]
|
||||
# members whose ENTIRE box is above the anchor headline top
|
||||
above_mems = [m for m in b["members"]
|
||||
if m != b["anchor_id"] and rmap[m]["bbox"][3] <= atop + 20]
|
||||
if above_mems and b["kind"] == "H":
|
||||
print(f" block H anchor={b['anchor_id']} (top y={atop}) has {len(above_mems)} member(s) ABOVE it:")
|
||||
for m in above_mems:
|
||||
rb = rmap[m]["bbox"]
|
||||
print(f" R{m} {rmap[m]['type']:<14} y[{rb[1]}..{rb[3]}] x[{rb[0]}..{rb[2]}]")
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import sys, json, contextlib, io
|
||||
sys.path.insert(0, ".")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers, detect_separator_lines
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
png = D / "page_001.png"
|
||||
regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png)
|
||||
|
||||
res = detect_separator_lines(png)
|
||||
print(f"=== {len(res['h'])} raw horizontal lines ===")
|
||||
for L in sorted(res["h"], key=lambda d: d["y1"]):
|
||||
print(f" H y={L['y1']:>5} x[{L['x1']:>4}..{L['x2']:>4}] len={L['len']:>4} gray={L['gray']}")
|
||||
|
||||
print("\n=== separator_barriers (after filters) ===")
|
||||
bars = separator_barriers(str(png), regs)
|
||||
for L in sorted(bars, key=lambda d: d["y"]):
|
||||
print(f" bar y={L['y']:>5} x[{L['x1']:>4}..{L['x2']:>4}] mc={L.get('mc')}")
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import sys, json, contextlib, io
|
||||
sys.path.insert(0, ".")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers, detect_separator_lines
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
png = D / "page_001.png"
|
||||
regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi")
|
||||
|
||||
print(f"=== {len(ds)} dateline starts ===")
|
||||
for s in sorted(ds, key=lambda s: s["bbox"][1]):
|
||||
print(f" DL region={s['region_id']:>3} bbox={s['bbox']} headline={s.get('headline_region')}")
|
||||
|
||||
byid = {r["id"]: r for r in regs}
|
||||
print("\n=== all regions sorted by y ===")
|
||||
for r in sorted(regs, key=lambda r: (r["bbox"][1], r["bbox"][0])):
|
||||
b = r["bbox"]
|
||||
print(f" R{r['id']:>3} {r['type']:<16} bbox={b}")
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import sys, json, contextlib, io
|
||||
sys.path.insert(0, ".")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers, detect_separator_lines
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
png = D / "page_001.png"
|
||||
regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png)
|
||||
|
||||
byid = {r["id"]: r for r in regs}
|
||||
# focus region 35 and 55
|
||||
for rid in (35, 55):
|
||||
if rid in byid:
|
||||
r = byid[rid]
|
||||
print(f"R{rid} type={r['type']} bbox={r['bbox']}")
|
||||
else:
|
||||
print(f"R{rid} NOT in regs (dropped?)")
|
||||
|
||||
print("\n-- all regions near x 150..750, y 1100..1600 --")
|
||||
for r in sorted(regs, key=lambda r: r["bbox"][1]):
|
||||
b = r["bbox"]
|
||||
if b[1] < 1700 and b[3] > 1050 and b[0] < 760:
|
||||
print(f" R{r['id']:>3} {r['type']:<16} bbox={b}")
|
||||
|
||||
print("\n-- raw horizontal lines near y=1375 --")
|
||||
res = detect_separator_lines(png)
|
||||
for L in sorted(res["h"], key=lambda d: d["y1"]):
|
||||
if 1300 < L["y1"] < 1450:
|
||||
print(f" H y={L['y1']} x[{L['x1']}..{L['x2']}] len={L['len']} gray={L['gray']}")
|
||||
|
||||
print("\n-- separator_barriers near y=1375 --")
|
||||
bars = separator_barriers(str(png), regs)
|
||||
for L in sorted(bars, key=lambda d: d["y"]):
|
||||
if 1300 < L["y"] < 1450:
|
||||
print(f" bar y={L['y']} x[{L['x1']}..{L['x2']}] mc={L.get('mc')}")
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import sys, json, contextlib, io
|
||||
sys.path.insert(0, ".")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
png = D / "page_001.png"
|
||||
regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi")
|
||||
bars = separator_barriers(str(png), regs)
|
||||
bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars)
|
||||
|
||||
print("bars near y=1375:", [b for b in bars if 1300 < b["y"] < 1450])
|
||||
print()
|
||||
dl_ids = {s["region_id"] for s in ds}
|
||||
for b in sorted(bl, key=lambda b: (b["bbox"][1], b["bbox"][0])):
|
||||
kind = b["kind"]
|
||||
print(f" {kind} anchor={b['anchor_id']:>3} bbox={b['bbox']} members={sorted(b['members'])}")
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import os, tempfile, contextlib, io, json
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
se._ACTIVE_PAPER = "sakshi"
|
||||
RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"); D = RUN / "pages"
|
||||
png = str(D / "page_001.png")
|
||||
regs = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs = se.dedup_overlapping_regions(regs); regs = se.merge_stacked_title_lines(regs, png)
|
||||
regs = se.drop_masthead_regions(regs, "sakshi", 1, png)
|
||||
regs = se.drop_classifieds_regions(regs, png); regs = se.tag_legal_notices(regs, png)
|
||||
regs = se.promote_paragraph_titles(regs, png, "sakshi")
|
||||
regs = se.detect_sakshi_headline_bands(regs, png)
|
||||
regs = se.mark_bullet_titles(regs, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, png, "sakshi")
|
||||
bars = separator_barriers(png, regs)
|
||||
_p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_p, regs, png):
|
||||
ds = se.find_article_starts_by_dateline(regs, png, "sakshi")
|
||||
blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
WATCH = [44, 16, 36, 69, 61, 46, 23, 4, 74, 49, 17, 88, 33, 28, 3, 53, 56]
|
||||
own = {}
|
||||
for b in blocks:
|
||||
for m in set(b["members"]) | {b["anchor_id"]}:
|
||||
own.setdefault(m, []).append(f"{b['kind']}{b['anchor_id']}")
|
||||
print("region owners:")
|
||||
for w in WATCH:
|
||||
print(f" R{w:>3} -> {own.get(w, ['(NONE)'])}")
|
||||
print("\nhorizontal bars near lift-1 (y3300-4100) and R50 zone (y4350-4900):")
|
||||
for L in bars:
|
||||
if not L.get("vert") and "y" in L and (3300 <= L["y"] <= 4100 or 4350 <= L["y"] <= 4900):
|
||||
print(f" y={L['y']} x={L['x1']}-{L['x2']} w={L['x2']-L['x1']}")
|
||||
print("\ndateline regions:", sorted(s["region_id"] for s in ds))
|
||||
print("\npipeline lines mentioning watched regions / passes:")
|
||||
for l in buf.getvalue().splitlines():
|
||||
if any(k in l for k in ("R44", "R69", "R61", "R46", "R23", "rebind", "Sakshi", "Orphan photo", "Masthead", "📐")):
|
||||
print(" ", l.strip())
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import os, tempfile, contextlib, io, json
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
se._ACTIVE_PAPER = "sakshi"
|
||||
RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"); D = RUN / "pages"
|
||||
png = str(D / "page_002.png")
|
||||
regs = json.loads((D / "page_002.regions.json").read_text())["regions"]
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs = se.dedup_overlapping_regions(regs); regs = se.merge_stacked_title_lines(regs, png)
|
||||
regs = se.drop_masthead_regions(regs, "sakshi", 2, png)
|
||||
regs = se.drop_classifieds_regions(regs, png); regs = se.tag_legal_notices(regs, png)
|
||||
regs = se.promote_paragraph_titles(regs, png, "sakshi")
|
||||
regs = se.detect_sakshi_headline_bands(regs, png)
|
||||
regs = se.mark_bullet_titles(regs, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, png, "sakshi")
|
||||
bars = separator_barriers(png, regs)
|
||||
_p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_p, regs, png):
|
||||
ds = se.find_article_starts_by_dateline(regs, png, "sakshi")
|
||||
blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
rm = {r["id"]: r for r in regs}
|
||||
print("BLOCKS:")
|
||||
for b in sorted(blocks, key=lambda b: (b["bbox"][1], b["bbox"][0])):
|
||||
x1, y1, x2, y2 = b["bbox"]
|
||||
f = " FURN" if b.get("_furniture") else ""
|
||||
print(f" {b['kind']}{b['anchor_id']:<4} [{x1},{y1},{x2},{y2}] mem={sorted(set(b['members']))}{f}")
|
||||
WATCH = [20, 29, 34, 51, 3, 14, 31, 65, 87, 105, 121, 76, 8, 10, 36, 46, 81]
|
||||
own = {}
|
||||
for b in blocks:
|
||||
tag = ("F" if b.get("_furniture") else b["kind"]) + str(b["anchor_id"])
|
||||
for m in set(b["members"]) | {b["anchor_id"]}:
|
||||
own.setdefault(m, []).append(tag)
|
||||
print("\nWATCH owners:", {f"R{w}": own.get(w, "NONE") for w in WATCH})
|
||||
print("\nbars y2380-2820 / y3400-3700 / y4640-4760:")
|
||||
for L in bars:
|
||||
if not L.get("vert") and "y" in L and (2380 <= L["y"] <= 2820 or 3400 <= L["y"] <= 3700 or 4640 <= L["y"] <= 4760):
|
||||
print(f" y={L['y']} x={L['x1']}-{L['x2']} w={L['x2']-L['x1']}")
|
||||
print("\ndatelines:", sorted(s["region_id"] for s in ds))
|
||||
print("\npipeline lines:")
|
||||
for l in buf.getvalue().splitlines():
|
||||
if any(k in l for k in ("Type-2", "rule-split", "📐", "Masthead", "⇤", "re-home", "📸", "Orphan photo", "carve", "furniture")):
|
||||
print(" ", l.strip())
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
R121 bbox=[2113, 2214, 3502, 3634] kind=H raw=True
|
||||
R12 text y[1996,2719] x[2979,3480] DATELINE
|
||||
R39 image y[2214,2622] x[2113,2939]
|
||||
R111 figure_title y[2628,2725] x[2196,2856]
|
||||
R121 doc_title y[2799,2898] x[2422,3493]
|
||||
R59 image y[2902,3115] x[2981,3502]
|
||||
R21 text y[2907,3621] x[2419,2945] DATELINE
|
||||
R116 figure_title y[3123,3163] x[3113,3376]
|
||||
R14 text y[3195,3622] x[2977,3502]
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
page WxH=4200x6422; 12 blocks
|
||||
|
||||
R65 bbox=[113, 1958, 1977, 6279] kind=H raw=True locked=False #members=36
|
||||
R65 datelines: [43, 47, 26, 21]
|
||||
vertical walls: [(616, 4683, 6292), (141, 4683, 6292), (123, 4123, 6309), (637, 4122, 6309), (2015, 1949, 5689), (3300, 1929, 6308), (2669, 404, 1905)]
|
||||
wide H-seps (>0.5W): [(1936, 114, 4091), (5709, 686, 3276)]
|
||||
|
||||
all block anchors+bbox:
|
||||
R109 H bbox=[119, 393, 612, 1899] ndl=1
|
||||
R79 H bbox=[2693, 405, 4087, 1833] ndl=1
|
||||
R55 H bbox=[679, 415, 2630, 1919] ndl=1
|
||||
R77 H bbox=[2692, 1594, 4087, 1903] ndl=1
|
||||
R14 DL bbox=[2045, 1950, 3265, 3097] ndl=1
|
||||
R65 H bbox=[113, 1958, 1977, 6279] ndl=4
|
||||
R96 H bbox=[3326, 1964, 4087, 3638] ndl=1
|
||||
R64 H bbox=[2046, 3116, 3264, 4832] ndl=2
|
||||
R97 H bbox=[3322, 3756, 4087, 5831] ndl=1
|
||||
R110 H bbox=[2044, 4858, 3265, 5685] ndl=1
|
||||
R59 H bbox=[680, 5731, 3267, 6318] ndl=1
|
||||
R7 DL bbox=[3308, 5839, 4087, 6305] ndl=1
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import os, tempfile, contextlib, io, json, shutil
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
se._ACTIVE_PAPER = "namaste_telangana"
|
||||
RUN = Path(os.environ.get("NTA_RUN", "output/NamastheTelangana_Adilabad_20260528_20260610_160056"))
|
||||
D = RUN / "pages"; P = "namaste_telangana"
|
||||
OUT = RUN / "all_article_crops_review"
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
pages = sorted(int(p.stem.split("_")[1]) for p in D.glob("page_*.png"))
|
||||
for pg in pages:
|
||||
png = str(D / f"page_{pg:03d}.png")
|
||||
regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs = se.dedup_overlapping_regions(regs); regs = se.merge_stacked_title_lines(regs, png)
|
||||
regs = se.drop_masthead_regions(regs, P, pg, png); regs = se.drop_classifieds_regions(regs, png)
|
||||
regs = se.tag_legal_notices(regs, png); regs = se.promote_paragraph_titles(regs, png, P)
|
||||
if pg == 1: regs = se.detect_sakshi_headline_bands(regs, png) # NT: front-page only
|
||||
regs = se.mark_bullet_titles(regs, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, png, P)
|
||||
bars = separator_barriers(png, regs)
|
||||
_p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_p, regs, png):
|
||||
ds = se.find_article_starts_by_dateline(regs, png, P)
|
||||
blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
n = se.crop_all_article_blocks(png, regs, str(OUT), pg, dateline_starts=ds,
|
||||
sep_lines=bars, overlay=True)
|
||||
print(f"=== page {pg}: {n} crops, {len(ds)} datelines ===")
|
||||
for b in sorted(blocks, key=lambda b: (b["bbox"][1], b["bbox"][0])):
|
||||
x1, y1, x2, y2 = b["bbox"]
|
||||
f = " FURN" if b.get("_furniture") else ""
|
||||
print(f" {b['kind']}{b['anchor_id']:<4} [{x1},{y1},{x2},{y2}] {x2-x1}x{y2-y1} mem={len(b['members'])}{f}")
|
||||
for l in sorted({l.strip() for l in buf.getvalue().splitlines()
|
||||
if "rule-split" in l or "Masthead" in l or "Orphan photo" in l}):
|
||||
print(" ", l)
|
||||
print("DONE ->", OUT)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import os,tempfile,contextlib,io,json,shutil
|
||||
tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp",exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages"
|
||||
OUT=RUN/"all_article_crops_final"; PAPER="andhra_jyothi"
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
for pg in (1,2,3,4):
|
||||
png=str(D/f"page_{pg:03d}.png")
|
||||
regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] # 0.5 saved
|
||||
buf=io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs=se.dedup_overlapping_regions(regs)
|
||||
regs=se.merge_stacked_title_lines(regs,png)
|
||||
regs=se.drop_masthead_regions(regs,PAPER,pg,png)
|
||||
regs=se.drop_classifieds_regions(regs,png)
|
||||
regs=se.tag_legal_notices(regs,png)
|
||||
regs=se.promote_paragraph_titles(regs,png,PAPER)
|
||||
regs=se.mark_bullet_titles(regs,png)
|
||||
bars=separator_barriers(png,regs)
|
||||
ds=se.find_article_starts_by_dateline(regs,png,PAPER)
|
||||
_probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,PAPER)
|
||||
blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars)
|
||||
n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars)
|
||||
log=buf.getvalue()
|
||||
tags={k:sum(1 for l in log.splitlines() if k in l) for k in
|
||||
["bullet titles flagged","Headline-strip","Floor-trim","Block dateline split",
|
||||
"Multi-column body","orphan overlap"]}
|
||||
tags={k:v//2 if k in ("Headline-strip","Floor-trim","Multi-column body","Block dateline split","orphan overlap") else v for k,v in tags.items()}
|
||||
print(f"page {pg}: {n} crops, {len(ds)} datelines | "+", ".join(f"{k}:{v}" for k,v in tags.items() if v))
|
||||
print("DONE ->",OUT)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
"""Re-crop EVERY article on all 4 pages using the EXISTING smart_extractor code
|
||||
(no Claude / no paid API). Runs the FULL pre-processing chain the real pipeline uses
|
||||
(dedup -> merge stacked titles -> drop masthead -> promote paragraph-titles -> dateline
|
||||
scan -> separators -> cluster/crop), so the replay crops match real output. Tesseract
|
||||
temp files are redirected off /tmp so OCR can read them. Output goes to a fresh dir."""
|
||||
import os, tempfile, json
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp") # keep Tesseract off /tmp
|
||||
os.environ["TMPDIR"] = tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
RUN = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919")
|
||||
PAGES = RUN / "pages"
|
||||
OUT = RUN / "all_article_crops_new" # fresh output dir
|
||||
PAPER = "andhra_jyothi"
|
||||
|
||||
for pg in (1, 2, 3, 4):
|
||||
png = str(PAGES / f"page_{pg:03d}.png")
|
||||
regions = json.loads((PAGES / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
|
||||
# Full pre-processing chain (matches the real pipeline order):
|
||||
regions = se.dedup_overlapping_regions(regions)
|
||||
regions = se.merge_stacked_title_lines(regions, png)
|
||||
regions = se.drop_masthead_regions(regions, PAPER, pg, png)
|
||||
regions = se.promote_paragraph_titles(regions, png, PAPER) # paragraph_title -> doc_title
|
||||
dateline_starts = se.find_article_starts_by_dateline(regions, png, PAPER)
|
||||
sep_lines = separator_barriers(png, regions)
|
||||
|
||||
n = se.crop_all_article_blocks(png, regions, str(OUT), pg,
|
||||
dateline_starts=dateline_starts, sep_lines=sep_lines)
|
||||
print(f"page {pg}: {len(dateline_starts)} datelines -> {n} article crop(s) written")
|
||||
|
||||
print(f"\nCrops written under: {OUT}")
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import sys, json, shutil, os
|
||||
sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
png = D / "page_001.png"
|
||||
regions = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
regions2 = se.drop_masthead_regions(regions, "andhra_jyothi", 1, png)
|
||||
ds = se.find_article_starts_by_dateline(regions2, str(png), "andhra_jyothi")
|
||||
bars = separator_barriers(str(png), regions2)
|
||||
blocks = se.cluster_all_article_blocks(regions2, dateline_starts=ds, sep_lines=bars)
|
||||
|
||||
dl_ids = {s["region_id"] for s in ds}
|
||||
dl_anchors = {b["anchor_id"] for b in blocks if any(m in dl_ids for m in b["members"])}
|
||||
print(f"{len(ds)} datelines -> {len(dl_anchors)} dateline blocks: {sorted(dl_anchors)}")
|
||||
for b in sorted(blocks, key=lambda d: (d["bbox"][1], d["bbox"][0])):
|
||||
if b["anchor_id"] in dl_anchors:
|
||||
print(f" {b['kind']} anchor={b['anchor_id']:>3} bbox={b['bbox']} members={sorted(b['members'])}")
|
||||
|
||||
out = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/dateline_crops")
|
||||
if out.exists():
|
||||
shutil.rmtree(out)
|
||||
out.mkdir(parents=True)
|
||||
n = se.crop_all_article_blocks(str(png), regions2, str(out), 1,
|
||||
dateline_starts=ds, sep_lines=bars,
|
||||
only_anchor_ids=dl_anchors)
|
||||
print(f"\ndateline crops written: {n}")
|
||||
for f in sorted(os.listdir(out / "page_001")):
|
||||
print(" ", f)
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import os,tempfile,contextlib,io,json,shutil
|
||||
tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp",exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages"
|
||||
OUT=RUN/"all_article_crops_hstrip"; PAPER="andhra_jyothi"
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
for pg in (1,2,3,4):
|
||||
png=str(D/f"page_{pg:03d}.png")
|
||||
regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
buf=io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png)
|
||||
regs=se.drop_masthead_regions(regs,PAPER,pg,png); regs=se.promote_paragraph_titles(regs,png,PAPER)
|
||||
bars=separator_barriers(png,regs)
|
||||
ds=se.find_article_starts_by_dateline(regs,png,PAPER)
|
||||
blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars)
|
||||
ext=[l for l in buf.getvalue().splitlines() if "Headline-strip" in l]
|
||||
print(f"page {pg}: {n} crops | {len(ext)} headline-strip extension(s)")
|
||||
for l in ext: print(" ",l.strip())
|
||||
print("DONE")
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import os,tempfile,contextlib,io,json,shutil
|
||||
tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp",exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
se._ACTIVE_PAPER = "namaste_telangana" # gates paper-specific clustering passes (pipeline sets this too)
|
||||
RUN=Path(os.environ.get("JG_RUN","output/NamastheTelangana_Jangaon_20260520_20260609_130635")); D=RUN/"pages"
|
||||
OUT=RUN/"all_article_crops_review"; P="namaste_telangana"
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
for pg in (1,2):
|
||||
png=str(D/f"page_{pg:03d}.png")
|
||||
regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
buf=io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png)
|
||||
regs=se.drop_masthead_regions(regs,P,pg,png); regs=se.drop_classifieds_regions(regs,png); regs=se.tag_legal_notices(regs,png); regs=se.promote_paragraph_titles(regs,png,P)
|
||||
if pg==1: regs=se.detect_sakshi_headline_bands(regs,png) # NT: front-page display headlines only
|
||||
regs=se.mark_bullet_titles(regs,png)
|
||||
ds=se.find_article_starts_by_dateline(regs,png,P)
|
||||
bars=separator_barriers(png,regs)
|
||||
_probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,P)
|
||||
blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars)
|
||||
n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars)
|
||||
log=buf.getvalue()
|
||||
rm={r['id']:r for r in regs}; dlids={s['region_id'] for s in ds}
|
||||
print(f"\n=== page {pg}: {n} crops, {len(ds)} datelines ===")
|
||||
for b in sorted(blocks,key=lambda b:(b['bbox'][1],b['bbox'][0])):
|
||||
x1,y1,x2,y2=b['bbox']; w,h=x2-x1,y2-y1
|
||||
ndl=sum(1 for m in b['members'] if m in dlids)
|
||||
types={}
|
||||
for m in b['members']:
|
||||
t=rm.get(m,{}).get('type','?'); types[t]=types.get(t,0)+1
|
||||
ntext=types.get('text',0); nimg=types.get('image',0)
|
||||
flags=[]
|
||||
if ndl>=2: flags.append(f"{ndl}DL(roundup?)")
|
||||
if ntext==0 and nimg>0: flags.append("IMG-ONLY(no text)")
|
||||
if len(b['members'])==1: flags.append("SINGLE-region")
|
||||
if b['kind']=='O': flags.append("ORPHAN")
|
||||
print(f" R{b['anchor_id']:>3} {b['kind']} {'RAW' if b.get('_raw_rect') else ' '} "
|
||||
f"bbox=[{x1},{y1},{x2},{y2}] {w}x{h} mem={len(b['members'])} {types} "
|
||||
f"{' '.join(flags)}")
|
||||
for key in ("Section banner","Containment-merge","Headline-merge","Banner rectangle"):
|
||||
c=[l.strip() for l in log.splitlines() if key in l]
|
||||
if c: print(f" [{key}] x{len(c)//2 if key in ('Headline-merge','Containment-merge','Section banner','Banner rectangle') else len(c)}")
|
||||
print("\nDONE ->",OUT)
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import os,tempfile,contextlib,io,json,shutil
|
||||
tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp",exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
se._ACTIVE_PAPER = "namaste_telangana" # gates paper-specific clustering passes (pipeline sets this too)
|
||||
RUN=Path("output/NamastheTelangana_Siddipet_20260602_20260604_214937"); D=RUN/"pages"
|
||||
OUT=RUN/"all_article_crops_final"; P="namaste_telangana"
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
for pg in (1,2,3,4):
|
||||
png=str(D/f"page_{pg:03d}.png")
|
||||
regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
buf=io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png)
|
||||
regs=se.drop_masthead_regions(regs,P,pg,png); regs=se.drop_classifieds_regions(regs,png); regs=se.tag_legal_notices(regs,png); regs=se.promote_paragraph_titles(regs,png,P)
|
||||
if pg==1: regs=se.detect_sakshi_headline_bands(regs,png) # NT: front-page display headlines only
|
||||
regs=se.mark_bullet_titles(regs,png)
|
||||
ds=se.find_article_starts_by_dateline(regs,png,P)
|
||||
bars=separator_barriers(png,regs)
|
||||
_probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,P)
|
||||
blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars)
|
||||
n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars)
|
||||
log=buf.getvalue()
|
||||
tags={k:sum(1 for l in log.splitlines() if k in l) for k in
|
||||
["Caption bound","Caption orphan dropped","bullet titles flagged","Headline-strip",
|
||||
"Floor-trim","Block dateline split","Multi-column body","orphan overlap"]}
|
||||
tags={k:(v//2 if k in ("Headline-strip","Floor-trim","Multi-column body","Block dateline split","orphan overlap") else v) for k,v in tags.items()}
|
||||
over=[b['anchor_id'] for b in blocks if len([m for m in b['members'] if m in {s['region_id'] for s in ds}])>=2]
|
||||
print(f"page {pg}: {n} crops, {len(ds)} datelines, 2+dl-blocks={over or 'none'} | "+", ".join(f"{k}:{v}" for k,v in tags.items() if v))
|
||||
print("DONE ->",OUT)
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import sys, json
|
||||
sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
png = D / "page_001.png"
|
||||
regions = json.loads((D / "page_001.regions.json").read_text())["regions"]
|
||||
print(f"raw regions: {len(regions)}")
|
||||
|
||||
# 1) masthead drop
|
||||
regions2 = se.drop_masthead_regions(regions, "andhra_jyothi", 1, png)
|
||||
dropped = {r['id'] for r in regions} - {r['id'] for r in regions2}
|
||||
print(f"masthead dropped ids: {sorted(dropped)} -> {len(regions2)} regions")
|
||||
|
||||
# 2) dateline starts
|
||||
ds = se.find_article_starts_by_dateline(regions2, str(png), "andhra_jyothi")
|
||||
print(f"dateline starts: {len(ds)}")
|
||||
for s in ds:
|
||||
print(f" DL region_id={s['region_id']} headline_id={s.get('headline_id')} bbox={s['bbox']}")
|
||||
|
||||
# 3) separator barriers
|
||||
bars = separator_barriers(str(png), regions2)
|
||||
print(f"separator barriers: {len(bars)}")
|
||||
|
||||
# 4) cluster
|
||||
blocks = se.cluster_all_article_blocks(regions2, dateline_starts=ds, sep_lines=bars)
|
||||
print(f"\nblocks: {len(blocks)}")
|
||||
dl_ids = {s['region_id'] for s in ds}
|
||||
for b in sorted(blocks, key=lambda d: (d['bbox'][1], d['bbox'][0])):
|
||||
mem = b['members']
|
||||
has_dl = any(m in dl_ids for m in mem)
|
||||
print(f" block anchor={b['anchor_id']} kind={b['kind']} dl={has_dl} bbox={b['bbox']} members={sorted(mem)}")
|
||||
|
||||
# 5) render crops to /tmp for visual check
|
||||
import shutil
|
||||
out = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_test")
|
||||
if out.exists():
|
||||
shutil.rmtree(out)
|
||||
out.mkdir(parents=True)
|
||||
n = se.crop_all_article_blocks(str(png), regions2, str(out), 1,
|
||||
dateline_starts=ds, sep_lines=bars)
|
||||
print(f"\ncrops written: {n} -> {out}/page_001")
|
||||
import os
|
||||
for f in sorted(os.listdir(out / "page_001")):
|
||||
print(" ", f)
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import sys, json
|
||||
sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor")
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages")
|
||||
for pg in (2, 3):
|
||||
png = D / f"page_{pg:03d}.png"
|
||||
regions = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
regions = se.drop_masthead_regions(regions, "andhra_jyothi", pg, png)
|
||||
ds = se.find_article_starts_by_dateline(regions, str(png), "andhra_jyothi")
|
||||
bars = separator_barriers(str(png), regions)
|
||||
blocks = se.cluster_all_article_blocks(regions, dateline_starts=ds, sep_lines=bars)
|
||||
dl_ids = {s['region_id'] for s in ds}
|
||||
print(f"\n==== PAGE {pg} datelines={len(ds)} bars={len(bars)} blocks={len(blocks)} ====")
|
||||
# each dateline must sit in a block that ALSO has a headline/title anchor
|
||||
for s in ds:
|
||||
rid = s['region_id']
|
||||
owner = None
|
||||
for b in blocks:
|
||||
if rid in b['members'] or rid == b['anchor_id']:
|
||||
owner = b; break
|
||||
kind = owner['kind'] if owner else '??'
|
||||
ndl = sum(1 for m in owner['members'] if m in dl_ids) if owner else 0
|
||||
flag = ''
|
||||
if owner is None:
|
||||
flag = 'LOST'
|
||||
elif kind == 'DL':
|
||||
flag = 'headless(DL)'
|
||||
elif ndl > 1:
|
||||
flag = f'MERGED({ndl} datelines)'
|
||||
print(f" DL R{rid} -> block anchor={owner['anchor_id'] if owner else None} kind={kind} {flag}")
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import os, tempfile, contextlib, io, json, sys, shutil
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
# Replays the POLITICAL crop step (no API): saved political_result.json member ids
|
||||
# + freshly recomputed region prep chain -> crop_political_articles (block-snap).
|
||||
RUNS = [
|
||||
("sakshi", Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"), [1]),
|
||||
("andhra_jyothi", Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"), [2, 3, 4]),
|
||||
("namaste_telangana", Path("output/NamastheTelangana_Jangaon_20260520_20260608_124720"), [1]),
|
||||
]
|
||||
for paper, RUN, pages in RUNS:
|
||||
se._ACTIVE_PAPER = paper
|
||||
D = RUN / "pages"
|
||||
OUT = RUN / "articles_review"
|
||||
if OUT.exists():
|
||||
shutil.rmtree(OUT)
|
||||
for pg in pages:
|
||||
png = str(D / f"page_{pg:03d}.png")
|
||||
prf = D / f"page_{pg:03d}.political_result.json"
|
||||
if not prf.exists() or not os.path.exists(png):
|
||||
continue
|
||||
political = json.load(open(prf)).get("political_articles", [])
|
||||
if not political:
|
||||
continue
|
||||
regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs = se.dedup_overlapping_regions(regs)
|
||||
regs = se.merge_stacked_title_lines(regs, png)
|
||||
regs = se.drop_masthead_regions(regs, paper, pg, png)
|
||||
regs = se.drop_classifieds_regions(regs, png)
|
||||
regs = se.tag_legal_notices(regs, png)
|
||||
regs = se.promote_paragraph_titles(regs, png, paper)
|
||||
if paper == "sakshi":
|
||||
regs = se.detect_sakshi_headline_bands(regs, png)
|
||||
regs = se.mark_bullet_titles(regs, png)
|
||||
ds = se.find_article_starts_by_dateline(regs, png, paper)
|
||||
bars = separator_barriers(png, regs)
|
||||
_p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_p, regs, png):
|
||||
ds = se.find_article_starts_by_dateline(regs, png, paper)
|
||||
recs = se.crop_political_articles(png, political, regs, OUT, pg,
|
||||
dateline_starts=ds, sep_lines=bars)
|
||||
print(f"=== {RUN.name} page {pg}: {len(political)} political → {len(recs)} crops")
|
||||
for l in buf.getvalue().splitlines():
|
||||
if any(k in l for k in ("Block-snap", "Cropped:", "Clipped", "Floored", "Grew",
|
||||
"Banner", "block-snap unavailable")):
|
||||
print(" ", l.strip())
|
||||
print("DONE")
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import os,tempfile,contextlib,io,json,shutil
|
||||
tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp",exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages"
|
||||
OUT=RUN/"all_article_crops_rescue"; PAPER="andhra_jyothi"
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
for pg in (1,2,3,4):
|
||||
png=str(D/f"page_{pg:03d}.png")
|
||||
regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] # 0.5 saved
|
||||
buf=io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png)
|
||||
regs=se.drop_masthead_regions(regs,PAPER,pg,png); regs=se.promote_paragraph_titles(regs,png,PAPER)
|
||||
bars=separator_barriers(png,regs)
|
||||
regs=se.rescue_headlines_above_photos(regs,png,PAPER,bars) # NEW
|
||||
ds=se.find_article_starts_by_dateline(regs,png,PAPER)
|
||||
blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars)
|
||||
resc=[l for l in buf.getvalue().splitlines() if "HEADLINE RESCUE" in l]
|
||||
print(f"page {pg}: {n} crops | {len(resc)} headline(s) rescued")
|
||||
for l in resc: print(" ",l.strip())
|
||||
print("DONE")
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import os,tempfile,contextlib,io,json,shutil
|
||||
tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp",exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
se._ACTIVE_PAPER = "sakshi" # gate Sakshi-specific clustering passes
|
||||
RUN=Path(os.environ.get("SAK_RUN","output/Sakshi_Jangaon_District_20260520_20260609_210104")); D=RUN/"pages"
|
||||
OUT=RUN/"all_article_crops_review"; P="sakshi"
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
for pg in (1,2):
|
||||
png=str(D/f"page_{pg:03d}.png")
|
||||
regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
buf=io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png)
|
||||
regs=se.drop_masthead_regions(regs,P,pg,png); regs=se.drop_classifieds_regions(regs,png); regs=se.tag_legal_notices(regs,png); regs=se.promote_paragraph_titles(regs,png,P)
|
||||
regs=se.detect_sakshi_headline_bands(regs,png)
|
||||
regs=se.mark_bullet_titles(regs,png)
|
||||
ds=se.find_article_starts_by_dateline(regs,png,P)
|
||||
bars=separator_barriers(png,regs)
|
||||
_probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,P)
|
||||
blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars)
|
||||
se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars)
|
||||
n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars,overlay=True)
|
||||
log=buf.getvalue()
|
||||
rm={r['id']:r for r in regs}; dlids={s['region_id'] for s in ds}
|
||||
print(f"\n=== page {pg}: {n} crops, {len(ds)} datelines ===")
|
||||
img_orphans=[]
|
||||
for b in sorted(blocks,key=lambda b:(b['bbox'][1],b['bbox'][0])):
|
||||
x1,y1,x2,y2=b['bbox']; w,h=x2-x1,y2-y1
|
||||
types={}
|
||||
for m in b['members']:
|
||||
t=rm.get(m,{}).get('type','?'); types[t]=types.get(t,0)+1
|
||||
ntext=types.get('text',0); nimg=types.get('image',0)
|
||||
is_art=any(rm.get(m,{}).get('type') in ('doc_title','paragraph_title') for m in b['members']) or any(m in dlids for m in b['members'])
|
||||
flags=[]
|
||||
if nimg>0 and not is_art: flags.append("IMG-ORPHAN?")
|
||||
if b['kind']=='O': flags.append("ORPHAN")
|
||||
if nimg>0 and not is_art and ntext==0: img_orphans.append(b['anchor_id'])
|
||||
print(f" R{b['anchor_id']:>3} {b['kind']} bbox=[{x1},{y1},{x2},{y2}] {w}x{h} mem={len(b['members'])} {types} {' '.join(flags)}")
|
||||
binds=sorted({l.strip() for l in log.splitlines()
|
||||
if "Orphan photo" in l or "Masthead" in l or "📐" in l or "rule-split" in l})
|
||||
print(f" >>> image-only orphans REMAINING: {img_orphans}")
|
||||
for l in binds: print(f" {l}")
|
||||
print("\nDONE ->",OUT)
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import os,tempfile,contextlib,io
|
||||
tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir
|
||||
os.makedirs("_tess_tmp",exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages"
|
||||
OUT=RUN/"all_article_crops_t045"; PAPER="andhra_jyothi"
|
||||
import shutil
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
for pg in (1,2,3,4):
|
||||
png=str(D/f"page_{pg:03d}.png")
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
regs=se.detect_regions(png, threshold=0.45) # NEW cutoff
|
||||
regs=se.dedup_overlapping_regions(regs)
|
||||
regs=se.merge_stacked_title_lines(regs,png)
|
||||
regs=se.drop_masthead_regions(regs,PAPER,pg,png)
|
||||
regs=se.promote_paragraph_titles(regs,png,PAPER)
|
||||
ds=se.find_article_starts_by_dateline(regs,png,PAPER)
|
||||
bars=separator_barriers(png,regs)
|
||||
n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars)
|
||||
nreg=len(regs)
|
||||
print(f"page {pg}: {nreg} regions, {len(ds)} datelines, {n} crops")
|
||||
print("DONE ->",OUT)
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
=== page 1: 22 crops, 17 datelines ===
|
||||
R 55 H bbox=[2796,291,4114,2002] 1318x1711 mem=8 {'image': 2, 'text': 5, 'doc_title': 1}
|
||||
R 94 P bbox=[2113,299,2785,3703] 672x3404 mem=5 {'paragraph_title': 1, 'text': 4}
|
||||
R 52 H bbox=[1080,371,2766,2350] 1686x1979 mem=6 {'doc_title': 1, 'image': 3, 'paragraph_title': 1, 'text': 1}
|
||||
R 71 DL bbox=[769,913,1375,1781] 606x868 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 11 DL bbox=[694,1789,1440,2678] 746x889 mem=1 {'text': 1}
|
||||
R 77 H bbox=[2793,1973,4114,3303] 1321x1330 mem=10 {'text': 6, 'image': 1, 'figure_title': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 66 P bbox=[694,2686,1391,3745] 697x1059 mem=4 {'paragraph_title': 1, 'text': 3}
|
||||
R 51 P bbox=[1399,2686,2105,3458] 706x772 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 78 H bbox=[749,3466,2070,6049] 1321x2583 mem=11 {'text': 8, 'image': 1, 'figure_title': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,3509,4114,6094] 1321x2585 mem=13 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 1}
|
||||
R 4 DL bbox=[2113,3707,2752,4876] 639x1169 mem=2 {'text': 1, 'image': 1}
|
||||
R 3 DL bbox=[750,3753,1388,4588] 638x835 mem=1 {'text': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=4 {'doc_title': 1, 'text': 3}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,1391,6637] 619x555 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 18 O bbox=[1430,6086,2049,6635] 619x549 mem=1 {'text': 1} ORPHAN
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
🖼 Orphan photo: R28 → article R78 (an image must belong to an article)
|
||||
🖼 Orphan photo: R28 → article R78 (an image must belong to an article)
|
||||
🖼 Orphan photo: R28 → article R78 (an image must belong to an article)
|
||||
🖼 Orphan photo: R28 → article R78 (an image must belong to an article)
|
||||
|
||||
=== page 2: 20 crops, 11 datelines ===
|
||||
R 61 O bbox=[777,474,1506,2308] 729x1834 mem=8 {'image': 3, 'text': 3, 'figure_title': 2} IMG-ORPHAN? ORPHAN
|
||||
R 82 H bbox=[695,478,2747,2308] 2052x1830 mem=10 {'text': 3, 'image': 4, 'figure_title': 2, 'doc_title': 1}
|
||||
R 55 O bbox=[2549,479,2801,1028] 252x549 mem=2 {'image': 1, 'text': 1} IMG-ORPHAN? ORPHAN
|
||||
R129 P bbox=[80,482,769,1053] 689x571 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 72 H bbox=[2755,482,3519,2232] 764x1750 mem=8 {'image': 3, 'text': 3, 'doc_title': 1, 'figure_title': 1}
|
||||
R127 H bbox=[3353,482,4115,2215] 762x1733 mem=9 {'text': 4, 'image': 3, 'figure_title': 1, 'doc_title': 1}
|
||||
R 24 O bbox=[80,1061,687,2305] 607x1244 mem=4 {'image': 1, 'figure_title': 1, 'text': 2} IMG-ORPHAN? ORPHAN
|
||||
R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'doc_title': 1, 'text': 1, 'image': 2}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R113 H bbox=[72,2417,709,4641] 637x2224 mem=7 {'doc_title': 1, 'text': 3, 'image': 2, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 4 F bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,6617] 478x1638 mem=6 {'text': 5, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 77 H bbox=[1217,5969,2752,6682] 1535x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
🖼 Orphan photo: R42 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R52 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R63 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R60 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R38 → article R72 (an image must belong to an article)
|
||||
🖼 Orphan photo: R48 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R42 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R52 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R63 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R60 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R38 → article R72 (an image must belong to an article)
|
||||
🖼 Orphan photo: R48 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R42 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R52 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R63 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R60 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R38 → article R72 (an image must belong to an article)
|
||||
🖼 Orphan photo: R48 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R42 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R52 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R63 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R60 → article R82 (an image must belong to an article)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
=== page 1: 19 crops, 16 datelines ===
|
||||
R 55 H bbox=[2796,1049,4114,2002] 1318x953 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 52 H bbox=[664,1067,2749,2657] 2085x1590 mem=8 {'doc_title': 1, 'text': 3, 'image': 2, 'paragraph_title': 2}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 94 P bbox=[2113,1941,2755,3257] 642x1316 mem=4 {'paragraph_title': 1, 'text': 3}
|
||||
R 77 H bbox=[2793,1973,4114,3315] 1321x1342 mem=8 {'text': 6, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 66 P bbox=[693,2665,1391,3349] 698x684 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 51 P bbox=[1399,2665,2105,3349] 706x684 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R100 H bbox=[2113,2860,4114,4876] 2001x2016 mem=10 {'doc_title': 1, 'text': 5, 'image': 3, 'figure_title': 1}
|
||||
R 99 H bbox=[750,3357,2068,4588] 1318x1231 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 78 H bbox=[749,3891,2070,6049] 1321x2158 mem=10 {'doc_title': 1, 'text': 8, 'figure_title': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=4 {'doc_title': 1, 'text': 3}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [664, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 21 crops, 11 datelines ===
|
||||
R 61 O bbox=[777,474,1506,2308] 729x1834 mem=8 {'image': 3, 'text': 3, 'figure_title': 2} IMG-ORPHAN? ORPHAN
|
||||
R 82 H bbox=[695,478,2747,2308] 2052x1830 mem=10 {'text': 3, 'image': 4, 'figure_title': 2, 'doc_title': 1}
|
||||
R 55 O bbox=[2549,479,2801,1028] 252x549 mem=2 {'image': 1, 'text': 1} IMG-ORPHAN? ORPHAN
|
||||
R129 P bbox=[80,482,769,1053] 689x571 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 72 H bbox=[2755,482,3519,2232] 764x1750 mem=8 {'image': 3, 'text': 3, 'doc_title': 1, 'figure_title': 1}
|
||||
R127 H bbox=[3353,482,4115,2215] 762x1733 mem=9 {'text': 4, 'image': 3, 'figure_title': 1, 'doc_title': 1}
|
||||
R 24 O bbox=[80,1061,687,2305] 607x1244 mem=4 {'image': 1, 'figure_title': 1, 'text': 2} IMG-ORPHAN? ORPHAN
|
||||
R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'doc_title': 1, 'text': 1, 'image': 2}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R113 H bbox=[72,2417,709,4641] 637x2224 mem=7 {'doc_title': 1, 'text': 3, 'image': 2, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 99 H bbox=[650,3656,2071,6145] 1421x2489 mem=10 {'image': 1, 'text': 7, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 10 F bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 4 F bbox=[2002,4723,2752,5938] 750x1215 mem=4 {'text': 2, 'paragraph_title': 2}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 77 H bbox=[1104,5969,2752,6682] 1648x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51)
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1104, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R72 (an image must belong to an article)
|
||||
🖼 Orphan photo: R42 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R48 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R52 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R60 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R63 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[664,1067,2755,3314] 2091x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [664, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2736] 646x2237 mem=8 {'paragraph_title': 1, 'image': 2, 'text': 3, 'figure_title': 2}
|
||||
R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'text': 1, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[650,3656,2071,6145] 1421x2489 mem=10 {'image': 1, 'text': 7, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 10 F bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 4 F bbox=[2002,4723,2752,5938] 750x1215 mem=4 {'text': 2, 'paragraph_title': 2}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 77 H bbox=[1104,5969,2752,6682] 1648x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51)
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1104, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2736] 646x2237 mem=8 {'paragraph_title': 1, 'image': 2, 'text': 3, 'figure_title': 2}
|
||||
R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'text': 1, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 4 F bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,6145] 478x1166 mem=5 {'text': 4, 'paragraph_title': 1}
|
||||
R 77 H bbox=[1147,5193,2752,6694] 1605x1501 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51)
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2736] 646x2237 mem=8 {'paragraph_title': 1, 'image': 2, 'text': 3, 'figure_title': 2}
|
||||
R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 88 P bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,6617] 478x1638 mem=6 {'text': 5, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1}
|
||||
R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 88 P bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,6617] 478x1638 mem=6 {'text': 5, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1}
|
||||
R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1}
|
||||
R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1}
|
||||
R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
=== page 1: 12 crops, 16 datelines ===
|
||||
R 55 H bbox=[2796,1049,4114,2002] 1318x953 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 52 H bbox=[664,1067,2749,2657] 2085x1590 mem=8 {'doc_title': 1, 'text': 3, 'image': 2, 'paragraph_title': 2}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 94 P bbox=[2113,1941,2755,3257] 642x1316 mem=4 {'paragraph_title': 1, 'text': 3}
|
||||
R 77 H bbox=[2793,1973,4114,3315] 1321x1342 mem=8 {'text': 6, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 66 P bbox=[693,2665,1391,6678] 698x4013 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 51 P bbox=[1399,2665,2105,6678] 706x4013 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 99 H bbox=[749,2860,4114,6698] 3365x3838 mem=45 {'text': 30, 'image': 5, 'figure_title': 2, 'paragraph_title': 3, 'doc_title': 5}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3353, 4097, 3452] (un-boxed display headline band, ink=0.32)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [664, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 21 crops, 11 datelines ===
|
||||
R 61 O bbox=[777,474,1506,2308] 729x1834 mem=8 {'image': 3, 'text': 3, 'figure_title': 2} IMG-ORPHAN? ORPHAN
|
||||
R 82 H bbox=[695,478,2747,2308] 2052x1830 mem=10 {'text': 3, 'image': 4, 'figure_title': 2, 'doc_title': 1}
|
||||
R 55 O bbox=[2549,479,2801,1028] 252x549 mem=2 {'image': 1, 'text': 1} IMG-ORPHAN? ORPHAN
|
||||
R129 P bbox=[80,482,769,1053] 689x571 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 72 H bbox=[2755,482,3519,2232] 764x1750 mem=8 {'image': 3, 'text': 3, 'doc_title': 1, 'figure_title': 1}
|
||||
R127 H bbox=[3353,482,4115,2215] 762x1733 mem=9 {'text': 4, 'image': 3, 'figure_title': 1, 'doc_title': 1}
|
||||
R 24 O bbox=[80,1061,687,2305] 607x1244 mem=4 {'image': 1, 'figure_title': 1, 'text': 2} IMG-ORPHAN? ORPHAN
|
||||
R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'doc_title': 1, 'text': 1, 'image': 2}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R113 H bbox=[72,2417,709,4641] 637x2224 mem=7 {'doc_title': 1, 'text': 3, 'image': 2, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 99 H bbox=[650,3656,2071,6145] 1421x2489 mem=10 {'image': 1, 'text': 7, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 10 F bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 4 F bbox=[2002,4723,2752,5938] 750x1215 mem=4 {'text': 2, 'paragraph_title': 2}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 77 H bbox=[1104,5969,2752,6682] 1648x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51)
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1104, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R72 (an image must belong to an article)
|
||||
🖼 Orphan photo: R42 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R48 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R52 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R60 → article R82 (an image must belong to an article)
|
||||
🖼 Orphan photo: R63 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
=== page 1: 13 crops, 14 datelines ===
|
||||
R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'figure_title': 1, 'paragraph_title': 2}
|
||||
R 46 H bbox=[684,1077,2784,3285] 2100x2208 mem=21 {'doc_title': 2, 'text': 11, 'image': 2, 'paragraph_title': 6}
|
||||
R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[99,2678,680,4455] 581x1777 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'doc_title': 1, 'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1}
|
||||
R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2}
|
||||
R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside)
|
||||
|
||||
=== page 2: 16 crops, 15 datelines ===
|
||||
R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=32 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 2}
|
||||
R106 H bbox=[2081,490,2753,5535] 672x5045 mem=6 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 2, 'paragraph_title': 1}
|
||||
R105 P bbox=[78,498,898,1656] 820x1158 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 57 H bbox=[751,2579,2754,4161] 2003x1582 mem=10 {'doc_title': 1, 'text': 7, 'image': 1, 'paragraph_title': 1}
|
||||
R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R121 DL bbox=[70,2805,709,3948] 639x1143 mem=6 {'text': 3, 'image': 1, 'paragraph_title': 1, 'figure_title': 1}
|
||||
R100 H bbox=[752,3306,2070,5044] 1318x1738 mem=5 {'text': 4, 'doc_title': 1}
|
||||
R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1}
|
||||
R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1}
|
||||
R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1}
|
||||
R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4}
|
||||
R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3}
|
||||
R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R12 → 2 bands at rules [4170]
|
||||
🖼 Orphan photo: R36 → article R87 (an image must belong to an article)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
=== page 1: 19 crops, 14 datelines ===
|
||||
R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'text': 9, 'image': 1, 'doc_title': 1, 'figure_title': 1, 'paragraph_title': 2}
|
||||
R 46 H bbox=[684,1077,2784,2187] 2100x1110 mem=8 {'doc_title': 2, 'text': 4, 'image': 1, 'paragraph_title': 1}
|
||||
R 84 P bbox=[1433,1077,2107,2755] 674x1678 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1}
|
||||
R 45 P bbox=[689,2195,1425,3315] 736x1120 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 72 P bbox=[2115,2195,2784,2915] 669x720 mem=5 {'paragraph_title': 1, 'text': 3, 'image': 1}
|
||||
R 65 H bbox=[99,2678,680,4291] 581x1613 mem=4 {'text': 2, 'image': 1, 'doc_title': 1}
|
||||
R 48 P bbox=[1433,2763,2107,3315] 674x552 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 60 P bbox=[2115,2923,2784,3285] 669x362 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1, 'doc_title': 1}
|
||||
R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 86 P bbox=[102,4299,741,4455] 639x156 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1}
|
||||
R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2}
|
||||
R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside)
|
||||
|
||||
=== page 2: 19 crops, 15 datelines ===
|
||||
R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=32 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 2}
|
||||
R127 P bbox=[2081,490,2754,4147] 673x3657 mem=3 {'paragraph_title': 1, 'text': 1, 'figure_title': 1}
|
||||
R105 P bbox=[78,498,898,1518] 820x1020 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R121 DL bbox=[70,1526,743,3817] 673x2291 mem=4 {'text': 2, 'image': 1, 'figure_title': 1}
|
||||
R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 57 H bbox=[754,2579,2751,3639] 1997x1060 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 4 DL bbox=[751,3306,2071,4149] 1320x843 mem=3 {'text': 3}
|
||||
R 81 P bbox=[75,3825,743,3966] 668x141 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1}
|
||||
R100 H bbox=[752,4203,2070,5044] 1318x841 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R106 H bbox=[2114,4209,2753,5535] 639x1326 mem=5 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1}
|
||||
R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1}
|
||||
R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4}
|
||||
R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3}
|
||||
R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R12 → 2 bands at rules [4170]
|
||||
🖼 Orphan photo: R36 → article R87 (an image must belong to an article)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
=== page 1: 14 crops, 14 datelines ===
|
||||
R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'text': 9, 'image': 1, 'doc_title': 1, 'figure_title': 1, 'paragraph_title': 2}
|
||||
R 46 H bbox=[684,1077,2784,3285] 2100x2208 mem=21 {'text': 11, 'image': 2, 'paragraph_title': 6, 'doc_title': 2}
|
||||
R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[99,2678,680,4291] 581x1613 mem=4 {'text': 2, 'image': 1, 'doc_title': 1}
|
||||
R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1, 'doc_title': 1}
|
||||
R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 86 P bbox=[102,4299,741,4455] 639x156 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1}
|
||||
R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2}
|
||||
R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside)
|
||||
|
||||
=== page 2: 16 crops, 15 datelines ===
|
||||
R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=32 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 2}
|
||||
R106 H bbox=[2081,490,2753,5535] 672x5045 mem=6 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 2, 'paragraph_title': 1}
|
||||
R105 P bbox=[78,498,898,1656] 820x1158 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 57 H bbox=[751,2579,2754,4161] 2003x1582 mem=11 {'text': 8, 'image': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R121 DL bbox=[70,2805,709,3948] 639x1143 mem=6 {'text': 3, 'image': 1, 'paragraph_title': 1, 'figure_title': 1}
|
||||
R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1}
|
||||
R100 H bbox=[752,4203,2070,5044] 1318x841 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1}
|
||||
R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1}
|
||||
R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4}
|
||||
R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3}
|
||||
R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R12 → 2 bands at rules [4170]
|
||||
🖼 Orphan photo: R36 → article R87 (an image must belong to an article)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
=== page 1: 14 crops, 14 datelines ===
|
||||
R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'text': 9, 'image': 1, 'doc_title': 1, 'figure_title': 1, 'paragraph_title': 2}
|
||||
R 46 H bbox=[684,1077,2784,3285] 2100x2208 mem=21 {'text': 11, 'image': 2, 'paragraph_title': 6, 'doc_title': 2}
|
||||
R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1}
|
||||
R 65 H bbox=[99,2678,680,4291] 581x1613 mem=4 {'text': 2, 'image': 1, 'doc_title': 1}
|
||||
R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1, 'doc_title': 1}
|
||||
R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 86 P bbox=[102,4299,741,4455] 639x156 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1}
|
||||
R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1}
|
||||
R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2}
|
||||
R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside)
|
||||
|
||||
=== page 2: 16 crops, 15 datelines ===
|
||||
R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=33 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 3}
|
||||
R105 P bbox=[78,498,898,1656] 820x1158 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 57 H bbox=[751,2579,2754,4161] 2003x1582 mem=11 {'text': 8, 'image': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R121 DL bbox=[70,2805,709,3948] 639x1143 mem=6 {'text': 3, 'image': 1, 'paragraph_title': 1, 'figure_title': 1}
|
||||
R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1}
|
||||
R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1}
|
||||
R100 H bbox=[752,4203,2070,5044] 1318x841 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R106 H bbox=[2114,4209,2753,5535] 639x1326 mem=5 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1, 'paragraph_title': 1}
|
||||
R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1}
|
||||
R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1}
|
||||
R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4}
|
||||
R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3}
|
||||
R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R12 → 2 bands at rules [4170]
|
||||
🖼 Orphan photo: R36 → article R87 (an image must belong to an article)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
=== page 1: 19 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2749,2854] 2061x1787 mem=9 {'doc_title': 1, 'text': 4, 'image': 2, 'paragraph_title': 2}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 94 P bbox=[2113,1941,2755,3257] 642x1316 mem=4 {'paragraph_title': 1, 'text': 3}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 66 P bbox=[749,2686,1391,3302] 642x616 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 51 P bbox=[1399,2862,2105,3349] 706x487 mem=2 {'paragraph_title': 1, 'text': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1}
|
||||
R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1}
|
||||
R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1}
|
||||
R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'text': 9, 'image': 2, 'paragraph_title': 5, 'doc_title': 1}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1}
|
||||
R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1}
|
||||
R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1}
|
||||
R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'text': 9, 'image': 2, 'paragraph_title': 5, 'doc_title': 1}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1}
|
||||
R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1}
|
||||
R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1}
|
||||
R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
=== page 1: 16 crops, 16 datelines ===
|
||||
R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1}
|
||||
R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'text': 9, 'image': 2, 'paragraph_title': 5, 'doc_title': 1}
|
||||
R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1}
|
||||
R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1}
|
||||
R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1}
|
||||
R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1}
|
||||
R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1}
|
||||
R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1}
|
||||
R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6}
|
||||
R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1}
|
||||
R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1}
|
||||
R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2}
|
||||
>>> image-only orphans REMAINING: []
|
||||
📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35)
|
||||
📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30)
|
||||
📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside)
|
||||
🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049)
|
||||
|
||||
=== page 2: 17 crops, 11 datelines ===
|
||||
R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1}
|
||||
R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1}
|
||||
R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1}
|
||||
R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1}
|
||||
R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1}
|
||||
R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1}
|
||||
R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1}
|
||||
R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1}
|
||||
R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1}
|
||||
R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1}
|
||||
R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1}
|
||||
R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1}
|
||||
R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1}
|
||||
R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1}
|
||||
R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1}
|
||||
R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2}
|
||||
R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1}
|
||||
R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1}
|
||||
R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1}
|
||||
R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1}
|
||||
>>> image-only orphans REMAINING: []
|
||||
─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252]
|
||||
─ Sakshi rule-split: R74 → 2 bands at rules [1066]
|
||||
📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside)
|
||||
🖼 Orphan photo: R38 → article R127 (an image must belong to an article)
|
||||
🖼 Orphan photo: R61 → article R82 (an image must belong to an article)
|
||||
🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499)
|
||||
|
||||
DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
"""Sandbox simulation of the Sakshi Jangaon page-1/2 crop run.
|
||||
Telugu tesseract is unavailable here, so dateline starts are INJECTED with the
|
||||
exact anchor set the real 20260609_210104 run found (DL anchors from the saved
|
||||
crop filenames). Usage: python3 _sim71.py <tag>
|
||||
Writes block table to stdout and crops to output/.../_sim_crops_<tag>/."""
|
||||
import sys, types
|
||||
sys.modules.setdefault("fitz", types.ModuleType("fitz"))
|
||||
import os, tempfile, contextlib, io, json, shutil
|
||||
tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir
|
||||
os.makedirs("_tess_tmp", exist_ok=True)
|
||||
from pathlib import Path
|
||||
import smart_extractor as se
|
||||
from _lines import separator_barriers
|
||||
|
||||
TAG = sys.argv[1] if len(sys.argv) > 1 else "base"
|
||||
RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"); D = RUN / "pages"
|
||||
OUT = RUN / f"_sim_crops_{TAG}"; P = "sakshi"
|
||||
DL_IDS = {1: [71, 11, 4, 3, 9, 5], 2: []} # real run's headline-less datelines
|
||||
if OUT.exists(): shutil.rmtree(OUT)
|
||||
|
||||
for pg in (1, 2):
|
||||
png = str(D / f"page_{pg:03d}.png")
|
||||
regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"]
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
regs = se.dedup_overlapping_regions(regs)
|
||||
regs = se.merge_stacked_title_lines(regs, png)
|
||||
regs = se.drop_masthead_regions(regs, P, pg, png)
|
||||
regs = se.drop_classifieds_regions(regs, png)
|
||||
regs = se.tag_legal_notices(regs, png)
|
||||
regs = se.promote_paragraph_titles(regs, png, P)
|
||||
regs = se.mark_bullet_titles(regs, png)
|
||||
rm = {r["id"]: r for r in regs}
|
||||
ds = [{"region_id": i, "dateline": "sim:", "bbox": rm[i]["bbox"],
|
||||
"headline_region": None} for i in DL_IDS[pg] if i in rm]
|
||||
bars = separator_barriers(png, regs)
|
||||
blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars)
|
||||
n = se.crop_all_article_blocks(png, regs, str(OUT), pg,
|
||||
dateline_starts=ds, sep_lines=bars)
|
||||
print(f"=== page {pg}: {n} crops, {len(ds)} injected datelines ===")
|
||||
for b in sorted(blocks, key=lambda b: (b["bbox"][1], b["bbox"][0])):
|
||||
x1, y1, x2, y2 = b["bbox"]
|
||||
types = {}
|
||||
for m in b["members"]:
|
||||
t = rm.get(m, {}).get("type", "?"); types[t] = types.get(t, 0) + 1
|
||||
print(f" R{b['anchor_id']:>3} {b['kind']} bbox=[{x1},{y1},{x2},{y2}] "
|
||||
f"{x2-x1}x{y2-y1} mem={len(b['members'])} {types}")
|
||||
for l in buf.getvalue().splitlines():
|
||||
if "Masthead" in l: print(" ", l.strip())
|
||||
print("DONE ->", OUT)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 218 KiB |
|
|
@ -0,0 +1,18 @@
|
|||
ADEA ASEXE shotloo Sr crsrAs
|
||||
Boas dof datwera, Ads Soseor
|
||||
weak? Hiirtht dod Siro. Kew0e vOt
|
||||
BORD arLBSCOS TS SUNG HOTS
|
||||
SS SHS EH ert. SYS OED HU,
|
||||
Brag SomoSodS Dweakl SASHyw
|
||||
TY. 80 OY GSo DHWBwHS S%So Bra
|
||||
oer BS BP wid Sard dren Sewn
|
||||
Sndke dSKo Hnowt, & Ysos!
|
||||
BraS Zodoh soerr Gardsivg
|
||||
DUS HEH OZ dbx Som Soebrey
|
||||
Perle SH Spor Sad Seared. ac
|
||||
GAS SOShowsh dso SO advert
|
||||
Sto, SEBS SrerS ZokoH Sodh ws
|
||||
B%o BLISS SS SyPHHS Ser
|
||||
UPSPAE SOY. wisp Ero HS Koha
|
||||
SE SK0. Stot dSthen Kar aeh'B
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 178 KiB |
|
|
@ -0,0 +1,12 @@
|
|||
BS: GSS Sel Ste (ohowS)
|
||||
Srghoh SES wQos*s eer wpideSo
|
||||
& NODA. 2025 ws8 LeeS* Snifo Tox
|
||||
©%8 S0508 ZHf6* ToXoT09 s0A8
|
||||
SeghoF SQ erp, 90.59 wo Karciws
|
||||
8008. 20m 72,194 0 LY soshoh
|
||||
wokofire 408. warshdS(SgE ssp
|
||||
espe) Soms 2,33,75 Tre, 31.93 wdor
|
||||
608. vert & 3018 5 d45* HOR ay
|
||||
Segboh SOB 3.214 Sow wonsen
|
||||
weberthen BDar%.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
|
|
@ -0,0 +1,18 @@
|
|||
BPSASOU: DeogS adFgroo wdhen L608
|
||||
woxso maaan. oY SAijo mddos
|
||||
Dio AGSL0B. wd Gesey wwe od:
|
||||
BOE nO AE SHE wSsr¥o ¥Oy0N0
|
||||
&. SiSHoE NDS Gadag we nod
|
||||
CRE AHIYHasryon. wond Neds’
|
||||
PH SrSo nddo woo SASS ors
|
||||
Gets. OY aro{go SpSaras Higher, OF
|
||||
ROARS, DAS PASS, Rrcsorer Bo S*ar
|
||||
doS HS Sy b3de Se, Smaysd
|
||||
aPOE URES DS WES BdaryWS SEyhe
|
||||
S850 wdgsore Boorres Ga GE & Hearrs
|
||||
RS Yond OWGE doryim Sod. oHo8
|
||||
wont DeiegS Soxseo ae ads’, bf es
|
||||
8, éé a ALa6, dé 25K4495 aod
|
||||
Bo Exp 0% J actyso Sodd davrd) s08.
|
||||
BaSSoo8 nado BE 4408. 3&% &%7.0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue