feat: iterative projection-profile deskew (2-phase variance optimization)
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 25s
CI / test-go-edu-search (push) Successful in 27s
CI / test-python-klausur (push) Failing after 1m53s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 17s

Adds deskew_image_iterative() as 3rd deskew method that directly optimizes
for projection-profile sharpness instead of proxy signals (Hough/word alignment).
Coarse sweep on horizontal profile, fine sweep on vertical profile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-05 13:46:44 +01:00
parent 770aea611f
commit af1b12c97d
2 changed files with 130 additions and 3 deletions

View File

@@ -52,6 +52,7 @@ from cv_vocab_pipeline import (
create_ocr_image,
deskew_image,
deskew_image_by_word_alignment,
deskew_image_iterative,
detect_column_geometry,
detect_document_type,
detect_row_geometry,
@@ -485,10 +486,23 @@ async def auto_deskew(session_id: str):
logger.warning(f"Word alignment deskew failed: {e}")
deskewed_wa_bytes, angle_wa = orig_bytes, 0.0
# Method 3: Iterative Projection-Profile
angle_iterative = 0.0
iterative_debug = {}
try:
deskewed_iter, angle_iterative, iterative_debug = deskew_image_iterative(img_bgr.copy())
except Exception as e:
logger.warning(f"Iterative deskew failed: {e}")
deskewed_iter = img_bgr
duration = time.time() - t0
# Pick best method
if abs(angle_wa) >= abs(angle_hough) or abs(angle_hough) < 0.1:
# Pick best method — prefer iterative when it found a non-zero angle
if abs(angle_iterative) >= 0.05:
method_used = "iterative"
angle_applied = angle_iterative
deskewed_bgr = deskewed_iter
elif abs(angle_wa) >= abs(angle_hough) or abs(angle_hough) < 0.1:
method_used = "word_alignment"
angle_applied = angle_wa
wa_array = np.frombuffer(deskewed_wa_bytes, dtype=np.uint8)
@@ -520,6 +534,7 @@ async def auto_deskew(session_id: str):
deskew_result = {
"angle_hough": round(angle_hough, 3),
"angle_word_alignment": round(angle_wa, 3),
"angle_iterative": round(angle_iterative, 3),
"angle_applied": round(angle_applied, 3),
"method_used": method_used,
"confidence": round(confidence, 2),
@@ -542,7 +557,8 @@ async def auto_deskew(session_id: str):
await update_session_db(session_id, **db_update)
logger.info(f"OCR Pipeline: deskew session {session_id}: "
f"hough={angle_hough:.2f} wa={angle_wa:.2f} -> {method_used} {angle_applied:.2f}")
f"hough={angle_hough:.2f} wa={angle_wa:.2f} iter={angle_iterative:.2f} "
f"-> {method_used} {angle_applied:.2f}")
await _append_pipeline_log(session_id, "deskew", {
"angle_applied": round(angle_applied, 3),