Fix clipped receipt margins, add time-of-day naming, speed up rotation detection
- vision/document.py: pad_quad() expands the detected quad outward before warping so a straight-line contour fit doesn't clip the first character of every line on a slightly curled/wrinkled receipt - ocr/extract.py + llm/vision.py: extract transaction time (HH:MM) so same-day repeat visits to a vendor get distinct filenames (2023-03-20_1525_walmart.pdf vs. a later same-day trip) - vision/orient.py: downscale before Tesseract OSD/confidence-sweep rotation detection — this was the dominant cost in the detection phase (7x speedup: 472s -> 67s on a 36s test video)
This commit is contained in:
@@ -32,6 +32,19 @@ def apply_rotation(image_bgr: np.ndarray, rotation: int) -> np.ndarray:
|
||||
return image_bgr if code is None else cv2.rotate(image_bgr, code)
|
||||
|
||||
|
||||
def _downscale(image_bgr: np.ndarray, max_dim: int = 1000) -> np.ndarray:
|
||||
"""Shrink before feeding Tesseract: orientation only needs word shapes,
|
||||
not per-character resolution, and _confidence_sweep_rotation runs this
|
||||
up to 4x per document — at full 4K-crop resolution that made rotation
|
||||
detection by far the slowest part of the whole pipeline."""
|
||||
h, w = image_bgr.shape[:2]
|
||||
longest = max(h, w)
|
||||
if longest <= max_dim:
|
||||
return image_bgr
|
||||
scale = max_dim / longest
|
||||
return cv2.resize(image_bgr, (round(w * scale), round(h * scale)), interpolation=cv2.INTER_AREA)
|
||||
|
||||
|
||||
def _osd_rotation(image_bgr: np.ndarray, lang: str) -> int | None:
|
||||
"""Tesseract's orientation-and-script-detection: fast and purpose-built.
|
||||
|
||||
@@ -43,7 +56,7 @@ def _osd_rotation(image_bgr: np.ndarray, lang: str) -> int | None:
|
||||
"""
|
||||
try:
|
||||
osd = pytesseract.image_to_osd(
|
||||
image_bgr, lang=lang, output_type=pytesseract.Output.DICT
|
||||
_downscale(image_bgr), lang=lang, output_type=pytesseract.Output.DICT
|
||||
)
|
||||
except pytesseract.TesseractError:
|
||||
return None
|
||||
@@ -72,10 +85,11 @@ def _confidence_sweep_rotation(
|
||||
Requiring 3+ characters drops almost all of that noise while barely
|
||||
touching real multi-character words.
|
||||
"""
|
||||
small = _downscale(image_bgr)
|
||||
best_rotation = 0
|
||||
best_score = -1.0
|
||||
for rotation in (0, 90, 180, 270):
|
||||
candidate = apply_rotation(image_bgr, rotation)
|
||||
candidate = apply_rotation(small, rotation)
|
||||
data = pytesseract.image_to_data(
|
||||
candidate, lang=lang, config=f"--psm {psm}", output_type=pytesseract.Output.DICT
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user