Stop an edge artefact and a speck filter from destroying a song

Olukainen juomukainen came out unusable, from two separate faults.

The scanner left a dark line down the sheet edge, running the full height
of every page but the first. Being taller than any bracket it won every
overlap in anchor selection and swallowed the page into one system, so
five pages of six proposed no cuts at all. A page's brackets and barlines
are all about one system tall, so a stroke far taller than the typical
one is not notation — relative to the page's own strokes, since a page
holding one big system is legitimate.

The trim then removed each system's bottom line of lyrics. It judged ink
blobs by area, and a letter is nowhere near the threshold; a whole line
of them is dozens of blobs, none of which qualifies. Measure ink per row
and per column instead — a line of text carries plenty in total, and a
fleck's row carries almost none, which is the case the filter was for.

Detection now finds three systems on every page of that score, and every
slice keeps all four voices' words.
This commit is contained in:
Esa Kataja
2026-07-29 12:22:08 +03:00
parent 2a22fc469f
commit 38cb6ce09a
4 changed files with 53 additions and 18 deletions
+8
View File
@@ -71,6 +71,14 @@ def main() -> int:
found = deskew_angle(deskew(page, angle))
assert abs(found + angle) <= 0.15, f"skew {angle}: got {found}"
# A scanner's edge line runs the whole height of the sheet. Being taller
# than every bracket it used to win each overlap and swallow the page into
# one system — Olukainen juomukainen, where five pages of six came out as a
# single slice each.
scanned = _page()
scanned[10 : H - 10, W - 8 : W - 4] = 0
assert len(detect_page(scanned).systems) == 2, "an edge artefact is not a bracket"
# No brackets: every ink run is its own system.
bare = np.full((H, W), 255, np.uint8)
for y in (200, 500, 800):