Tests / Test tests.test_device_config.test_device_config_store_settings_get_set_and_defaults failed
PaddleOCR's OCR.yaml pipeline defaults to use_doc_orientation_classify
and use_doc_unwarping enabled, which are meant for photographed paper
documents. Applied to a flat, upright device screenshot, UVDoc
geometrically warps the image before detection, and returns box
coordinates in that warped space with no inverse mapping back to the
original image.
Verified on a real screenshot: with unwarping on, the same detected
element ("新项目") shifts from y=158 to y=71 versus the original image,
and 2 boxes near the top edge (status bar time/battery) are dropped
entirely. Disabling both flags by default (still overridable via
explicit kwargs) makes detected boxes match the original screenshot.
80 lines
2.4 KiB
Python
80 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
from core.models import Bounds
|
|
from perception.ocr import OCRBox, PaddleOCREngine, parse_paddle_result, run_ocr
|
|
|
|
|
|
def test_paddle_ocr_engine_disables_doc_preprocessing_by_default() -> None:
|
|
# Screenshots are flat, upright digital captures, not photographed paper
|
|
# documents: PaddleOCR's document-unwarping preprocessing has nothing real
|
|
# to correct and instead warps the image, so detected box coordinates no
|
|
# longer line up with the original screenshot.
|
|
engine = PaddleOCREngine(lang="ch")
|
|
|
|
assert engine.kwargs["use_doc_orientation_classify"] is False
|
|
assert engine.kwargs["use_doc_unwarping"] is False
|
|
|
|
|
|
def test_paddle_ocr_engine_lets_callers_override_doc_preprocessing() -> None:
|
|
engine = PaddleOCREngine(use_doc_unwarping=True)
|
|
|
|
assert engine.kwargs["use_doc_unwarping"] is True
|
|
|
|
|
|
def test_parse_paddle_result_accepts_ndarray_fields() -> None:
|
|
boxes = parse_paddle_result(
|
|
{
|
|
"rec_texts": np.array(["Search"]),
|
|
"rec_scores": np.array([0.95]),
|
|
"rec_boxes": np.array([[1, 2, 10, 12]]),
|
|
}
|
|
)
|
|
|
|
assert boxes == [
|
|
OCRBox(
|
|
text="Search",
|
|
bounds=Bounds(x=1.0, y=2.0, width=9.0, height=10.0),
|
|
confidence=0.95,
|
|
)
|
|
]
|
|
|
|
|
|
class CallableJsonResult:
|
|
def json(self) -> dict[str, object]:
|
|
return {
|
|
"res": {
|
|
"rec_texts": ["Search"],
|
|
"rec_scores": [0.95],
|
|
"rec_boxes": [[1, 2, 10, 12]],
|
|
}
|
|
}
|
|
|
|
|
|
def test_parse_paddle_result_accepts_callable_json_result() -> None:
|
|
assert parse_paddle_result(CallableJsonResult()) == [
|
|
OCRBox(
|
|
text="Search",
|
|
bounds=Bounds(x=1.0, y=2.0, width=9.0, height=10.0),
|
|
confidence=0.95,
|
|
)
|
|
]
|
|
|
|
|
|
class FailingOCREngine:
|
|
def extract(self, image: bytes | str) -> list[OCRBox]:
|
|
raise ValueError(
|
|
"The truth value of an array with more than one element is ambiguous"
|
|
)
|
|
|
|
|
|
def test_run_ocr_degrades_when_ocr_engine_raises() -> None:
|
|
assert run_ocr(b"image", engine=FailingOCREngine()) == [] # type: ignore[arg-type]
|
|
|
|
|
|
def test_run_ocr_strict_mode_preserves_engine_error() -> None:
|
|
with pytest.raises(ValueError, match="truth value"):
|
|
run_ocr(b"image", engine=FailingOCREngine(), strict=True) # type: ignore[arg-type]
|