0
tests/__init__.py
Normal file
0
tests/models/__init__.py
Normal file
9
tests/models/image_classification_common.py
Normal file
@@ -0,0 +1,9 @@
|
||||
def check_result_item_keys(result_item):
|
||||
assert result_item.keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"class_ids",
|
||||
"scores",
|
||||
"label_names",
|
||||
}
|
||||
7
tests/models/object_detection_common.py
Normal file
@@ -0,0 +1,7 @@
|
||||
def check_result_item_keys(result_item):
|
||||
assert result_item.keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"boxes",
|
||||
}
|
||||
23
tests/models/test_doc_img_orientation_classifcation.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import DocImgOrientationClassification
|
||||
from ..testing_utils import TEST_DATA_DIR, check_simple_inference_result
|
||||
from .image_classification_common import check_result_item_keys
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def doc_img_orientation_classification_predictor():
|
||||
return DocImgOrientationClassification()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "book_rot180.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(doc_img_orientation_classification_predictor, image_path):
|
||||
result = doc_img_orientation_classification_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
check_result_item_keys(result[0])
|
||||
53
tests/models/test_doc_vlm.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import DocVLM
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def doc_vlm_predictor():
|
||||
return DocVLM()
|
||||
|
||||
|
||||
@pytest.mark.resource_intensive
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "medal_table.png",
|
||||
],
|
||||
)
|
||||
def test_predict(doc_vlm_predictor, image_path):
|
||||
result = doc_vlm_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
assert result[0].keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"result",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.resource_intensive
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
doc_vlm_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
doc_vlm_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
51
tests/models/test_formula_recognition.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import FormulaRecognition
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def formula_recognition_predictor():
|
||||
return FormulaRecognition()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "formula.png",
|
||||
],
|
||||
)
|
||||
def test_predict(formula_recognition_predictor, image_path):
|
||||
result = formula_recognition_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
assert result[0].keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"rec_formula",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
formula_recognition_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
formula_recognition_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
51
tests/models/test_layout_detection.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import LayoutDetection
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
from .object_detection_common import check_result_item_keys
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def layout_detection_predictor():
|
||||
return LayoutDetection()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "doc_with_formula.png",
|
||||
],
|
||||
)
|
||||
def test_predict(layout_detection_predictor, image_path):
|
||||
result = layout_detection_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
check_result_item_keys(result[0])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"img_size": 640},
|
||||
{"threshold": 0.5},
|
||||
{"layout_nms": True},
|
||||
{"layout_unclip_ratio": True},
|
||||
{"layout_merge_bboxes_mode": True},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
layout_detection_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
layout_detection_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
55
tests/models/test_seal_text_detection.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import SealTextDetection
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def seal_text_detection_predictor():
|
||||
return SealTextDetection()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "seal.png",
|
||||
],
|
||||
)
|
||||
def test_predict(seal_text_detection_predictor, image_path):
|
||||
result = seal_text_detection_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
assert result[0].keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"dt_polys",
|
||||
"dt_scores",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"limit_side_len": 640, "limit_type": "min"},
|
||||
{"thresh": 0.5},
|
||||
{"box_thresh": 0.3},
|
||||
{"unclip_ratio": 3.0},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
seal_text_detection_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
seal_text_detection_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
48
tests/models/test_table_cells_detection.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TableCellsDetection
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
from .object_detection_common import check_result_item_keys
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def table_cells_detection_predictor():
|
||||
return TableCellsDetection()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "table.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(table_cells_detection_predictor, image_path):
|
||||
result = table_cells_detection_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
check_result_item_keys(result[0])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"img_size": 640},
|
||||
{"threshold": 0.5},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
table_cells_detection_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
table_cells_detection_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
23
tests/models/test_table_classifcation.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TableClassification
|
||||
from ..testing_utils import TEST_DATA_DIR, check_simple_inference_result
|
||||
from .image_classification_common import check_result_item_keys
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def table_classification_predictor():
|
||||
return TableClassification()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "table.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(table_classification_predictor, image_path):
|
||||
result = table_classification_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
check_result_item_keys(result[0])
|
||||
53
tests/models/test_table_structure_recognition.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TableStructureRecognition
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def table_structure_recognition_predictor():
|
||||
return TableStructureRecognition()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "table.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(table_structure_recognition_predictor, image_path):
|
||||
result = table_structure_recognition_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
assert result[0].keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"bbox",
|
||||
"structure",
|
||||
"structure_score",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
table_structure_recognition_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
table_structure_recognition_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
55
tests/models/test_text_detection.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TextDetection
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def text_detection_predictor():
|
||||
return TextDetection()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "table.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(text_detection_predictor, image_path):
|
||||
result = text_detection_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
assert result[0].keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"dt_polys",
|
||||
"dt_scores",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"limit_side_len": 640, "limit_type": "min"},
|
||||
{"thresh": 0.5},
|
||||
{"box_thresh": 0.3},
|
||||
{"unclip_ratio": 3.0},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
text_detection_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
text_detection_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
51
tests/models/test_text_image_unwarping.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TextImageUnwarping
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def text_image_unwarping_predictor():
|
||||
return TextImageUnwarping()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "book.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(text_image_unwarping_predictor, image_path):
|
||||
result = text_image_unwarping_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
assert result[0].keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"doctr_img",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
text_image_unwarping_predictor,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
text_image_unwarping_predictor,
|
||||
"paddlex_predictor",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
29
tests/models/test_text_recognition.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TextRecognition
|
||||
from ..testing_utils import TEST_DATA_DIR, check_simple_inference_result
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def text_recognition_predictor():
|
||||
return TextRecognition()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "textline.png",
|
||||
],
|
||||
)
|
||||
def test_predict(text_recognition_predictor, image_path):
|
||||
result = text_recognition_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
assert result[0].keys() == {
|
||||
"input_path",
|
||||
"page_index",
|
||||
"input_img",
|
||||
"rec_text",
|
||||
"rec_score",
|
||||
"vis_font",
|
||||
}
|
||||
23
tests/models/test_textline_orientation_classifcation.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TextLineOrientationClassification
|
||||
from ..testing_utils import TEST_DATA_DIR, check_simple_inference_result
|
||||
from .image_classification_common import check_result_item_keys
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def textline_orientation_classification_predictor():
|
||||
return TextLineOrientationClassification()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "textline_rot180.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(textline_orientation_classification_predictor, image_path):
|
||||
result = textline_orientation_classification_predictor.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
check_result_item_keys(result[0])
|
||||
0
tests/pipelines/__init__.py
Normal file
57
tests/pipelines/test_doc_preprocessor.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import DocPreprocessor
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def ocr_engine() -> DocPreprocessor:
|
||||
return DocPreprocessor()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "book_rot180.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(ocr_engine: DocPreprocessor, image_path: str) -> None:
|
||||
"""
|
||||
Test PaddleOCR's doc preprocessor functionality.
|
||||
|
||||
Args:
|
||||
ocr_engine: An instance of `DocPreprocessor`.
|
||||
image_path: Path to the image to be processed.
|
||||
"""
|
||||
result = ocr_engine.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
res = result[0]
|
||||
assert res["angle"] in {0, 90, 180, 270, -1}
|
||||
assert res["rot_img"] is not None
|
||||
assert res["output_img"] is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False},
|
||||
{"use_doc_unwarping": False},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
ocr_engine: DocPreprocessor,
|
||||
params: dict,
|
||||
) -> None:
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
ocr_engine,
|
||||
"paddlex_pipeline",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
43
tests/pipelines/test_doc_understanding.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import DocUnderstanding
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def ocr_engine() -> DocUnderstanding:
|
||||
return DocUnderstanding()
|
||||
|
||||
|
||||
@pytest.mark.resource_intensive
|
||||
@pytest.mark.parametrize(
|
||||
"input",
|
||||
[
|
||||
{
|
||||
"image": str(TEST_DATA_DIR / "medal_table.png"),
|
||||
"query": "识别这份表格的内容",
|
||||
},
|
||||
{
|
||||
"image": str(TEST_DATA_DIR / "table.jpg"),
|
||||
"query": "识别这份表格的内容",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_predict(ocr_engine: DocUnderstanding, input: dict) -> None:
|
||||
"""
|
||||
Test PaddleOCR's doc understanding functionality.
|
||||
|
||||
Args:
|
||||
ocr_engine: An instance of `DocUnderstanding`.
|
||||
input: Input dict to be processed.
|
||||
"""
|
||||
result = ocr_engine.predict(input)
|
||||
|
||||
check_simple_inference_result(result)
|
||||
res = result[0]
|
||||
assert res["result"] is not None
|
||||
assert isinstance(res["result"], str)
|
||||
68
tests/pipelines/test_formula_recognition.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import FormulaRecognitionPipeline
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def formula_recognition_engine() -> FormulaRecognitionPipeline:
|
||||
return FormulaRecognitionPipeline()
|
||||
|
||||
|
||||
# TODO: Should we separate unit tests and integration tests?
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "doc_with_formula.png",
|
||||
],
|
||||
)
|
||||
def test_predict(
|
||||
formula_recognition_engine: FormulaRecognitionPipeline, image_path: str
|
||||
) -> None:
|
||||
"""
|
||||
Test FormulaRecognitionPipeline's formula_recognition functionality.
|
||||
|
||||
Args:
|
||||
formula_recognition_engine: An instance of `FormulaRecognitionPipeline`.
|
||||
image_path: Path to the image to be processed.
|
||||
"""
|
||||
result = formula_recognition_engine.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
res = result[0]
|
||||
assert isinstance(res["formula_res_list"], list)
|
||||
assert len(res["formula_res_list"]) > 0
|
||||
|
||||
|
||||
# TODO: Also check passing `None`
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False},
|
||||
{"use_doc_unwarping": False},
|
||||
{"use_layout_detection": False},
|
||||
{"layout_threshold": 0.5},
|
||||
{"layout_nms": True},
|
||||
{"layout_unclip_ratio": 1.5},
|
||||
{"layout_merge_bboxes_mode": "large"},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
formula_recognition_engine: FormulaRecognitionPipeline,
|
||||
params: dict,
|
||||
) -> None:
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
formula_recognition_engine,
|
||||
"paddlex_pipeline",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
|
||||
|
||||
# TODO: Test init params
|
||||
125
tests/pipelines/test_ocr.py
Normal file
@@ -0,0 +1,125 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import PaddleOCR
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def ocr_engine() -> PaddleOCR:
|
||||
return PaddleOCR()
|
||||
|
||||
|
||||
# TODO: Should we separate unit tests and integration tests?
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "table.jpg",
|
||||
],
|
||||
)
|
||||
def test_predict(ocr_engine: PaddleOCR, image_path: str) -> None:
|
||||
"""
|
||||
Test PaddleOCR's OCR functionality.
|
||||
|
||||
Args:
|
||||
ocr_engine: An instance of `PaddleOCR`.
|
||||
image_path: Path to the image to be processed.
|
||||
"""
|
||||
result = ocr_engine.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
res = result[0]
|
||||
assert len(res["dt_polys"]) > 0
|
||||
assert isinstance(res["rec_texts"], list)
|
||||
assert len(res["rec_texts"]) > 0
|
||||
for text in res["rec_texts"]:
|
||||
assert isinstance(text, str)
|
||||
|
||||
|
||||
# TODO: Also check passing `None`
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False},
|
||||
{"use_doc_unwarping": False},
|
||||
{"use_textline_orientation": False},
|
||||
{"text_det_limit_side_len": 640, "text_det_limit_type": "min"},
|
||||
{"text_det_thresh": 0.5},
|
||||
{"text_det_box_thresh": 0.3},
|
||||
{"text_det_unclip_ratio": 3.0},
|
||||
{"text_rec_score_thresh": 0.5},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
ocr_engine: PaddleOCR,
|
||||
params: dict,
|
||||
) -> None:
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
ocr_engine,
|
||||
"paddlex_pipeline",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
|
||||
|
||||
# TODO: Test init params
|
||||
|
||||
|
||||
def test_lang_and_ocr_version():
|
||||
ocr_engine = PaddleOCR(lang="ch", ocr_version="PP-OCRv5")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv5_server_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "PP-OCRv5_server_rec"
|
||||
ocr_engine = PaddleOCR(lang="chinese_cht", ocr_version="PP-OCRv5")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv5_server_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "PP-OCRv5_server_rec"
|
||||
ocr_engine = PaddleOCR(lang="en", ocr_version="PP-OCRv5")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv5_server_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "PP-OCRv5_server_rec"
|
||||
ocr_engine = PaddleOCR(lang="japan", ocr_version="PP-OCRv5")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv5_server_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "PP-OCRv5_server_rec"
|
||||
ocr_engine = PaddleOCR(lang="ch", ocr_version="PP-OCRv4")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv4_mobile_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "PP-OCRv4_mobile_rec"
|
||||
ocr_engine = PaddleOCR(lang="en", ocr_version="PP-OCRv4")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv4_mobile_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "en_PP-OCRv4_mobile_rec"
|
||||
ocr_engine = PaddleOCR(lang="ch", ocr_version="PP-OCRv3")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv3_mobile_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "PP-OCRv3_mobile_rec"
|
||||
ocr_engine = PaddleOCR(lang="en", ocr_version="PP-OCRv3")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv3_mobile_det"
|
||||
assert ocr_engine._params["text_recognition_model_name"] == "en_PP-OCRv3_mobile_rec"
|
||||
ocr_engine = PaddleOCR(lang="fr", ocr_version="PP-OCRv3")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv3_mobile_det"
|
||||
assert (
|
||||
ocr_engine._params["text_recognition_model_name"] == "latin_PP-OCRv3_mobile_rec"
|
||||
)
|
||||
ocr_engine = PaddleOCR(lang="ar", ocr_version="PP-OCRv3")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv3_mobile_det"
|
||||
assert (
|
||||
ocr_engine._params["text_recognition_model_name"]
|
||||
== "arabic_PP-OCRv3_mobile_rec"
|
||||
)
|
||||
ocr_engine = PaddleOCR(lang="ru", ocr_version="PP-OCRv3")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv3_mobile_det"
|
||||
assert (
|
||||
ocr_engine._params["text_recognition_model_name"]
|
||||
== "cyrillic_PP-OCRv3_mobile_rec"
|
||||
)
|
||||
ocr_engine = PaddleOCR(lang="hi", ocr_version="PP-OCRv3")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv3_mobile_det"
|
||||
assert (
|
||||
ocr_engine._params["text_recognition_model_name"]
|
||||
== "devanagari_PP-OCRv3_mobile_rec"
|
||||
)
|
||||
ocr_engine = PaddleOCR(lang="japan", ocr_version="PP-OCRv3")
|
||||
assert ocr_engine._params["text_detection_model_name"] == "PP-OCRv3_mobile_det"
|
||||
assert (
|
||||
ocr_engine._params["text_recognition_model_name"] == "japan_PP-OCRv3_mobile_rec"
|
||||
)
|
||||
80
tests/pipelines/test_pp_chatocrv4_doc.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import PPChatOCRv4Doc
|
||||
from ..testing_utils import TEST_DATA_DIR
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def pp_chatocrv4_doc_pipeline():
|
||||
return PPChatOCRv4Doc()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "doc_with_formula.png",
|
||||
],
|
||||
)
|
||||
def test_visual_predict(pp_chatocrv4_doc_pipeline, image_path):
|
||||
result = pp_chatocrv4_doc_pipeline.visual_predict(str(image_path))
|
||||
|
||||
assert result is not None
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == 1
|
||||
res = result[0]
|
||||
assert isinstance(res, dict)
|
||||
assert res.keys() == {"visual_info", "layout_parsing_result"}
|
||||
assert isinstance(res["visual_info"], dict)
|
||||
assert isinstance(res["layout_parsing_result"], dict)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False},
|
||||
{"use_doc_unwarping": False},
|
||||
{"use_table_recognition": False},
|
||||
{"layout_threshold": 0.88},
|
||||
{"layout_threshold": [0.45, 0.4]},
|
||||
{"layout_threshold": {0: 0.45, 2: 0.48, 7: 0.4}},
|
||||
{"layout_nms": False},
|
||||
{"layout_unclip_ratio": 1.1},
|
||||
{"layout_unclip_ratio": [1.2, 1.5]},
|
||||
{"layout_unclip_ratio": {0: 1.2, 2: 1.5, 7: 1.8}},
|
||||
{"layout_merge_bboxes_mode": "large"},
|
||||
{"layout_merge_bboxes_mode": {0: "large", 2: "small", 7: "union"}},
|
||||
{"text_det_limit_side_len": 640, "text_det_limit_type": "min"},
|
||||
{"text_det_thresh": 0.5},
|
||||
{"text_det_box_thresh": 0.3},
|
||||
{"text_det_unclip_ratio": 3.0},
|
||||
{"text_rec_score_thresh": 0.5},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
pp_chatocrv4_doc_pipeline,
|
||||
params,
|
||||
):
|
||||
def _dummy_visual_predict(input, **params):
|
||||
yield {"visual_info": {}, "layout_parsing_result": params}
|
||||
|
||||
monkeypatch.setattr(
|
||||
pp_chatocrv4_doc_pipeline.paddlex_pipeline,
|
||||
"visual_predict",
|
||||
_dummy_visual_predict,
|
||||
)
|
||||
|
||||
result = pp_chatocrv4_doc_pipeline.visual_predict(
|
||||
input,
|
||||
**params,
|
||||
)
|
||||
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == 1
|
||||
res = result[0]
|
||||
res = res["layout_parsing_result"]
|
||||
for k, v in params.items():
|
||||
assert res[k] == v
|
||||
|
||||
|
||||
# TODO: Test constructor and other methods
|
||||
80
tests/pipelines/test_pp_doctranslation.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import PPDocTranslation
|
||||
from ..testing_utils import TEST_DATA_DIR
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def pp_doctranslation_pipeline():
|
||||
return PPDocTranslation()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "book.jpg",
|
||||
],
|
||||
)
|
||||
def test_visual_predict(pp_doctranslation_pipeline, image_path):
|
||||
result = pp_doctranslation_pipeline.visual_predict(str(image_path))
|
||||
|
||||
assert result is not None
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == 1
|
||||
res = result[0]
|
||||
assert isinstance(res, dict)
|
||||
assert res.keys() == {"layout_parsing_result"}
|
||||
assert isinstance(res["layout_parsing_result"], dict)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False},
|
||||
{"use_doc_unwarping": False},
|
||||
{"use_table_recognition": False},
|
||||
{"use_formula_recognition": False},
|
||||
{"layout_threshold": 0.88},
|
||||
{"layout_threshold": [0.45, 0.4]},
|
||||
{"layout_threshold": {0: 0.45, 2: 0.48, 7: 0.4}},
|
||||
{"layout_nms": False},
|
||||
{"layout_unclip_ratio": 1.1},
|
||||
{"layout_unclip_ratio": [1.2, 1.5]},
|
||||
{"layout_unclip_ratio": {0: 1.2, 2: 1.5, 7: 1.8}},
|
||||
{"layout_merge_bboxes_mode": "large"},
|
||||
{"layout_merge_bboxes_mode": {0: "large", 2: "small", 7: "union"}},
|
||||
{"text_det_limit_side_len": 640, "text_det_limit_type": "min"},
|
||||
{"text_det_thresh": 0.5},
|
||||
{"text_det_box_thresh": 0.3},
|
||||
{"text_det_unclip_ratio": 3.0},
|
||||
{"text_rec_score_thresh": 0.5},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
pp_doctranslation_pipeline,
|
||||
params,
|
||||
):
|
||||
def _dummy_visual_predict(input, **params):
|
||||
yield {"layout_parsing_result": params}
|
||||
|
||||
monkeypatch.setattr(
|
||||
pp_doctranslation_pipeline.paddlex_pipeline,
|
||||
"visual_predict",
|
||||
_dummy_visual_predict,
|
||||
)
|
||||
|
||||
result = pp_doctranslation_pipeline.visual_predict(
|
||||
input,
|
||||
**params,
|
||||
)
|
||||
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == 1
|
||||
res = result[0]
|
||||
res = res["layout_parsing_result"]
|
||||
for k, v in params.items():
|
||||
assert res[k] == v
|
||||
|
||||
|
||||
# TODO: Test constructor and other methods
|
||||
71
tests/pipelines/test_pp_structurev3.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import PPStructureV3
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def pp_structurev3_pipeline():
|
||||
return PPStructureV3()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "doc_with_formula.png",
|
||||
],
|
||||
)
|
||||
def test_visual_predict(pp_structurev3_pipeline, image_path):
|
||||
result = pp_structurev3_pipeline.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
res = result[0]
|
||||
overall_ocr_res = res["overall_ocr_res"]
|
||||
assert len(overall_ocr_res["dt_polys"]) > 0
|
||||
assert len(overall_ocr_res["rec_texts"]) > 0
|
||||
assert len(overall_ocr_res["rec_polys"]) > 0
|
||||
assert len(overall_ocr_res["rec_boxes"]) > 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False},
|
||||
{"use_doc_unwarping": False},
|
||||
{"use_table_recognition": False},
|
||||
{"use_formula_recognition": False},
|
||||
{"layout_threshold": 0.88},
|
||||
{"layout_threshold": [0.45, 0.4]},
|
||||
{"layout_threshold": {0: 0.45, 2: 0.48, 7: 0.4}},
|
||||
{"layout_nms": False},
|
||||
{"layout_unclip_ratio": 1.1},
|
||||
{"layout_unclip_ratio": [1.2, 1.5]},
|
||||
{"layout_unclip_ratio": {0: 1.2, 2: 1.5, 7: 1.8}},
|
||||
{"layout_merge_bboxes_mode": "large"},
|
||||
{"layout_merge_bboxes_mode": {0: "large", 2: "small", 7: "union"}},
|
||||
{"text_det_limit_side_len": 640, "text_det_limit_type": "min"},
|
||||
{"text_det_thresh": 0.5},
|
||||
{"text_det_box_thresh": 0.3},
|
||||
{"text_det_unclip_ratio": 3.0},
|
||||
{"text_rec_score_thresh": 0.5},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
pp_structurev3_pipeline,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
pp_structurev3_pipeline,
|
||||
"paddlex_pipeline",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
|
||||
|
||||
# TODO: Test constructor and other methods
|
||||
70
tests/pipelines/test_seal_rec.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import SealRecognition
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def ocr_engine() -> SealRecognition:
|
||||
return SealRecognition()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "seal.png",
|
||||
],
|
||||
)
|
||||
def test_predict(ocr_engine: SealRecognition, image_path: str) -> None:
|
||||
"""
|
||||
Test PaddleOCR's seal recognition functionality.
|
||||
|
||||
Args:
|
||||
ocr_engine: An instance of `SealRecognition`.
|
||||
image_path: Path to the image to be processed.
|
||||
"""
|
||||
result = ocr_engine.predict(str(image_path))
|
||||
|
||||
check_simple_inference_result(result)
|
||||
res = result[0]["seal_res_list"][0]
|
||||
assert len(res["dt_polys"]) > 0
|
||||
assert isinstance(res["rec_texts"], list)
|
||||
assert len(res["rec_texts"]) > 0
|
||||
for text in res["rec_texts"]:
|
||||
assert isinstance(text, str)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False, "use_doc_unwarping": False},
|
||||
{"use_layout_detection": False},
|
||||
{"layout_det_res": None},
|
||||
{"layout_threshold": 0.5},
|
||||
{"layout_nms": False},
|
||||
{"layout_unclip_ratio": 1.0},
|
||||
{"layout_merge_bboxes_mode": "large"},
|
||||
{"seal_det_limit_side_len": 736},
|
||||
{"seal_det_limit_type": "min"},
|
||||
{"seal_det_thresh": 0.5},
|
||||
{"seal_det_box_thresh": 0.6},
|
||||
{"seal_det_unclip_ratio": 0.5},
|
||||
{"seal_rec_score_thresh": 0.05},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
ocr_engine: SealRecognition,
|
||||
params: dict,
|
||||
) -> None:
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
ocr_engine,
|
||||
"paddlex_pipeline",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
64
tests/pipelines/test_table_recognition_v2.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import pytest
|
||||
|
||||
from paddleocr import TableRecognitionPipelineV2
|
||||
from ..testing_utils import (
|
||||
TEST_DATA_DIR,
|
||||
check_simple_inference_result,
|
||||
check_wrapper_simple_inference_param_forwarding,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def table_recognition_v2_pipeline():
|
||||
return TableRecognitionPipelineV2()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"image_path",
|
||||
[
|
||||
TEST_DATA_DIR / "table.jpg",
|
||||
],
|
||||
)
|
||||
def test_visual_predict(table_recognition_v2_pipeline, image_path):
|
||||
result = table_recognition_v2_pipeline.predict(
|
||||
str(image_path), use_doc_orientation_classify=False, use_doc_unwarping=False
|
||||
)
|
||||
|
||||
check_simple_inference_result(result)
|
||||
res = result[0]
|
||||
assert len(res["table_res_list"]) > 0
|
||||
assert isinstance(res["table_res_list"][0], dict)
|
||||
assert len(res["table_res_list"][0]["cell_box_list"]) > 0
|
||||
assert isinstance(res["table_res_list"][0]["pred_html"], str)
|
||||
assert isinstance(res["table_res_list"][0]["table_ocr_pred"], dict)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
{"use_doc_orientation_classify": False},
|
||||
{"use_doc_unwarping": False},
|
||||
{"use_layout_detection": False},
|
||||
{"use_ocr_model": False},
|
||||
{"text_det_limit_side_len": 640, "text_det_limit_type": "min"},
|
||||
{"text_det_thresh": 0.5},
|
||||
{"text_det_box_thresh": 0.3},
|
||||
{"text_det_unclip_ratio": 3.0},
|
||||
{"text_rec_score_thresh": 0.5},
|
||||
],
|
||||
)
|
||||
def test_predict_params(
|
||||
monkeypatch,
|
||||
table_recognition_v2_pipeline,
|
||||
params,
|
||||
):
|
||||
check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
table_recognition_v2_pipeline,
|
||||
"paddlex_pipeline",
|
||||
"dummy_path",
|
||||
params,
|
||||
)
|
||||
|
||||
|
||||
# TODO: Test constructor and other methods
|
||||
64
tests/test_cls_postprocess.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import pytest
|
||||
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(os.path.abspath(os.path.join(current_dir, "..")))
|
||||
|
||||
from ppocr.postprocess.cls_postprocess import ClsPostProcess
|
||||
|
||||
|
||||
# Fixtures for common test inputs
|
||||
@pytest.fixture
|
||||
def preds_tensor():
|
||||
return paddle.to_tensor(np.array([[0.1, 0.7, 0.2], [0.3, 0.3, 0.4]]))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def label_list():
|
||||
return {0: "class0", 1: "class1", 2: "class2"}
|
||||
|
||||
|
||||
# Parameterize tests to cover multiple scenarios
|
||||
@pytest.mark.parametrize(
|
||||
"label_list, expected",
|
||||
[
|
||||
({0: "class0", 1: "class1", 2: "class2"}, [("class1", 0.7), ("class2", 0.4)]),
|
||||
(None, [(1, 0.7), (2, 0.4)]),
|
||||
],
|
||||
)
|
||||
def test_cls_post_process_with_and_without_label_list(
|
||||
preds_tensor, label_list, expected
|
||||
):
|
||||
post_process = ClsPostProcess(label_list=label_list)
|
||||
result = post_process(preds_tensor)
|
||||
assert isinstance(result, list), "Result should be a list"
|
||||
assert result == expected, f"Expected {expected}, got {result}"
|
||||
|
||||
|
||||
# Test with a key in the prediction dictionary
|
||||
def test_cls_post_process_with_key(preds_tensor, label_list):
|
||||
preds_dict = {"key": preds_tensor}
|
||||
post_process = ClsPostProcess(label_list=label_list, key="key")
|
||||
result = post_process(preds_dict)
|
||||
expected = [("class1", 0.7), ("class2", 0.4)]
|
||||
assert isinstance(result, list), "Result should be a list"
|
||||
assert result == expected, f"Expected {expected}, got {result}"
|
||||
|
||||
|
||||
# Test with label input
|
||||
def test_cls_post_process_with_label(preds_tensor, label_list):
|
||||
labels = [2, 0]
|
||||
post_process = ClsPostProcess(label_list=label_list)
|
||||
result, label_result = post_process(preds_tensor, labels)
|
||||
expected_result = [("class1", 0.7), ("class2", 0.4)]
|
||||
expected_label_result = [("class2", 1.0), ("class0", 1.0)]
|
||||
assert isinstance(result, list), "Result should be a list"
|
||||
assert result == expected_result, f"Expected {expected_result}, got {result}"
|
||||
assert isinstance(label_result, list), "Label result should be a list"
|
||||
assert (
|
||||
label_result == expected_label_result
|
||||
), f"Expected {expected_label_result}, got {label_result}"
|
||||
BIN
tests/test_files/book.jpg
Normal file
|
After Width: | Height: | Size: 251 KiB |
BIN
tests/test_files/book_rot180.jpg
Normal file
|
After Width: | Height: | Size: 304 KiB |
BIN
tests/test_files/doc_with_formula.png
Normal file
|
After Width: | Height: | Size: 482 KiB |
BIN
tests/test_files/formula.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
tests/test_files/medal_table.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
tests/test_files/seal.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
tests/test_files/table.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
tests/test_files/textline.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
tests/test_files/textline_rot180.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
195
tests/test_formula_model.py
Normal file
@@ -0,0 +1,195 @@
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import paddle
|
||||
import pytest
|
||||
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(os.path.abspath(os.path.join(current_dir, "..")))
|
||||
from ppocr.modeling.backbones.rec_donut_swin import DonutSwinModel, DonutSwinModelOutput
|
||||
from ppocr.modeling.backbones.rec_pphgnetv2 import PPHGNetV2_B4_Formula
|
||||
from ppocr.modeling.backbones.rec_vary_vit import Vary_VIT_B_Formula
|
||||
from ppocr.modeling.heads.rec_unimernet_head import UniMERNetHead
|
||||
from ppocr.modeling.heads.rec_ppformulanet_head import PPFormulaNet_Head
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_image():
|
||||
return paddle.randn([1, 1, 192, 672])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_image_ppformulanet_s():
|
||||
return paddle.randn([1, 1, 384, 384])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_image_ppformulanet_l():
|
||||
return paddle.randn([1, 1, 768, 768])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def encoder_feat():
|
||||
encoded_feat = paddle.randn([1, 126, 1024])
|
||||
return DonutSwinModelOutput(
|
||||
last_hidden_state=encoded_feat,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def encoder_feat_ppformulanet_s():
|
||||
encoded_feat = paddle.randn([1, 144, 2048])
|
||||
return DonutSwinModelOutput(
|
||||
last_hidden_state=encoded_feat,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def encoder_feat_ppformulanet_l():
|
||||
encoded_feat = paddle.randn([1, 144, 1024])
|
||||
return DonutSwinModelOutput(
|
||||
last_hidden_state=encoded_feat,
|
||||
)
|
||||
|
||||
|
||||
def test_unimernet_backbone(sample_image):
|
||||
"""
|
||||
Test UniMERNet backbone.
|
||||
|
||||
Args:
|
||||
sample_image: sample image to be processed.
|
||||
"""
|
||||
backbone = DonutSwinModel(
|
||||
hidden_size=1024,
|
||||
num_layers=4,
|
||||
num_heads=[4, 8, 16, 32],
|
||||
add_pooling_layer=True,
|
||||
use_mask_token=False,
|
||||
)
|
||||
backbone.eval()
|
||||
with paddle.no_grad():
|
||||
result = backbone(sample_image)
|
||||
encoder_feat = result[0]
|
||||
assert encoder_feat.shape == [1, 126, 1024]
|
||||
|
||||
|
||||
def test_unimernet_head(encoder_feat):
|
||||
"""
|
||||
Test UniMERNet head.
|
||||
|
||||
Args:
|
||||
encoder_feat: encoder feature from unimernet backbone.
|
||||
"""
|
||||
head = UniMERNetHead(
|
||||
max_new_tokens=5,
|
||||
decoder_start_token_id=0,
|
||||
temperature=0.2,
|
||||
do_sample=False,
|
||||
top_p=0.95,
|
||||
encoder_hidden_size=1024,
|
||||
is_export=False,
|
||||
length_aware=True,
|
||||
)
|
||||
|
||||
head.eval()
|
||||
with paddle.no_grad():
|
||||
result = head(encoder_feat)
|
||||
assert result.shape == [1, 6]
|
||||
|
||||
|
||||
def test_ppformulanet_s_backbone(sample_image_ppformulanet_s):
|
||||
"""
|
||||
Test PP-FormulaNet-S backbone.
|
||||
|
||||
Args:
|
||||
sample_image_ppformulanet_s: sample image to be processed.
|
||||
"""
|
||||
backbone = PPHGNetV2_B4_Formula(
|
||||
class_num=1024,
|
||||
)
|
||||
backbone.eval()
|
||||
with paddle.no_grad():
|
||||
result = backbone(sample_image_ppformulanet_s)
|
||||
encoder_feat = result[0]
|
||||
assert encoder_feat.shape == [1, 144, 2048]
|
||||
|
||||
|
||||
def test_ppformulanet_s_head(encoder_feat_ppformulanet_s):
|
||||
"""
|
||||
Test PP-FormulaNet-S head.
|
||||
|
||||
Args:
|
||||
encoder_feat_ppformulanet_s: encoder feature from PP-FormulaNet-S backbone.
|
||||
"""
|
||||
head = PPFormulaNet_Head(
|
||||
max_new_tokens=6,
|
||||
decoder_start_token_id=0,
|
||||
decoder_ffn_dim=1536,
|
||||
decoder_hidden_size=384,
|
||||
decoder_layers=2,
|
||||
temperature=0.2,
|
||||
do_sample=False,
|
||||
top_p=0.95,
|
||||
encoder_hidden_size=2048,
|
||||
is_export=False,
|
||||
length_aware=True,
|
||||
use_parallel=True,
|
||||
parallel_step=3,
|
||||
)
|
||||
|
||||
head.eval()
|
||||
with paddle.no_grad():
|
||||
result = head(encoder_feat_ppformulanet_s)
|
||||
assert result.shape == [1, 9]
|
||||
|
||||
|
||||
def test_ppformulanet_l_backbone(sample_image_ppformulanet_l):
|
||||
"""
|
||||
Test PP-FormulaNet-L backbone.
|
||||
|
||||
Args:
|
||||
sample_image_ppformulanet_l: sample image to be processed.
|
||||
"""
|
||||
backbone = Vary_VIT_B_Formula(
|
||||
image_size=768,
|
||||
encoder_embed_dim=768,
|
||||
encoder_depth=12,
|
||||
encoder_num_heads=12,
|
||||
encoder_global_attn_indexes=[2, 5, 8, 11],
|
||||
)
|
||||
backbone.eval()
|
||||
with paddle.no_grad():
|
||||
result = backbone(sample_image_ppformulanet_l)
|
||||
encoder_feat = result[0]
|
||||
assert encoder_feat.shape == [1, 144, 1024]
|
||||
|
||||
|
||||
def test_ppformulanet_l_head(encoder_feat_ppformulanet_l):
|
||||
"""
|
||||
Test PP-FormulaNet-L head.
|
||||
|
||||
Args:
|
||||
encoder_feat_ppformulanet_l: encoder feature from PP-FormulaNet-L Head.
|
||||
"""
|
||||
head = PPFormulaNet_Head(
|
||||
max_new_tokens=6,
|
||||
decoder_start_token_id=0,
|
||||
decoder_ffn_dim=2048,
|
||||
decoder_hidden_size=512,
|
||||
decoder_layers=8,
|
||||
temperature=0.2,
|
||||
do_sample=False,
|
||||
top_p=0.95,
|
||||
encoder_hidden_size=1024,
|
||||
is_export=False,
|
||||
length_aware=False,
|
||||
use_parallel=False,
|
||||
parallel_step=0,
|
||||
)
|
||||
|
||||
head.eval()
|
||||
with paddle.no_grad():
|
||||
result = head(encoder_feat_ppformulanet_l)
|
||||
assert result.shape == [1, 7]
|
||||
181
tests/test_iaa_augment.py
Normal file
@@ -0,0 +1,181 @@
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
import numpy as np
|
||||
import random
|
||||
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(os.path.abspath(os.path.join(current_dir, "..")))
|
||||
|
||||
from ppocr.data.imaug.iaa_augment import IaaAugment
|
||||
|
||||
# Set a fixed random seed to ensure test reproducibility
|
||||
np.random.seed(42)
|
||||
random.seed(42)
|
||||
|
||||
|
||||
# Fixture to provide a sample image for tests
|
||||
@pytest.fixture
|
||||
def sample_image():
|
||||
# Create a 100x100 pixel dummy image with 3 color channels (RGB)
|
||||
return np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
|
||||
|
||||
|
||||
# Fixture to provide sample polygons for tests
|
||||
@pytest.fixture
|
||||
def sample_polys():
|
||||
# Create dummy polygons as sample data
|
||||
polys = [
|
||||
np.array([[10, 10], [20, 10], [20, 20], [10, 20]], dtype=np.float32),
|
||||
np.array([[30, 30], [40, 30], [40, 40], [30, 40]], dtype=np.float32),
|
||||
]
|
||||
return polys
|
||||
|
||||
|
||||
# Helper function to create a data dictionary for testing
|
||||
def create_data(sample_image, sample_polys):
|
||||
return {
|
||||
"image": sample_image.copy(),
|
||||
"polys": [poly.copy() for poly in sample_polys],
|
||||
}
|
||||
|
||||
|
||||
# Test the default behavior of the augmenter (without specified arguments)
|
||||
def test_iaa_augment_default(sample_image, sample_polys):
|
||||
data = create_data(sample_image, sample_polys)
|
||||
augmenter = IaaAugment()
|
||||
transformed_data = augmenter(data)
|
||||
|
||||
# Check the data types and structure of the transformed image and polygons
|
||||
assert isinstance(
|
||||
transformed_data["image"], np.ndarray
|
||||
), "Image should be a numpy array"
|
||||
assert isinstance(
|
||||
transformed_data["polys"], np.ndarray
|
||||
), "Polys should be a numpy array"
|
||||
assert transformed_data["image"].ndim == 3, "Image should be 3-dimensional"
|
||||
|
||||
# Verify that the polygons have been transformed
|
||||
polys_changed = any(
|
||||
not np.allclose(orig_poly, trans_poly)
|
||||
for orig_poly, trans_poly in zip(sample_polys, transformed_data["polys"])
|
||||
)
|
||||
assert polys_changed, "Polygons should have been transformed"
|
||||
|
||||
|
||||
# Test the augmenter with empty arguments, meaning no transformations should occur
|
||||
def test_iaa_augment_none(sample_image, sample_polys):
|
||||
data = create_data(sample_image, sample_polys)
|
||||
augmenter = IaaAugment(augmenter_args=[])
|
||||
transformed_data = augmenter(data)
|
||||
|
||||
# Check that the image and polygons remain unchanged
|
||||
assert np.array_equal(
|
||||
data["image"], transformed_data["image"]
|
||||
), "Image should be unchanged"
|
||||
for orig_poly, transformed_poly in zip(data["polys"], transformed_data["polys"]):
|
||||
assert np.array_equal(
|
||||
orig_poly, transformed_poly
|
||||
), "Polygons should be unchanged"
|
||||
|
||||
|
||||
# Parameterized test to check various augmenter arguments and expected image shapes
|
||||
@pytest.mark.parametrize(
|
||||
"augmenter_args, expected_shape",
|
||||
[
|
||||
([], (100, 100, 3)),
|
||||
([{"type": "Resize", "args": {"size": [0.5, 0.5]}}], (50, 50, 3)),
|
||||
([{"type": "Resize", "args": {"size": [2.0, 2.0]}}], (200, 200, 3)),
|
||||
],
|
||||
)
|
||||
def test_iaa_augment_resize(sample_image, sample_polys, augmenter_args, expected_shape):
|
||||
data = create_data(sample_image, sample_polys)
|
||||
augmenter = IaaAugment(augmenter_args=augmenter_args)
|
||||
transformed_data = augmenter(data)
|
||||
|
||||
# Verify that the transformed image has the expected shape
|
||||
assert (
|
||||
transformed_data["image"].shape == expected_shape
|
||||
), f"Expected image shape {expected_shape}, got {transformed_data['image'].shape}"
|
||||
|
||||
|
||||
# Test custom augmenter arguments with specific transformations
|
||||
def test_iaa_augment_custom(sample_image, sample_polys):
|
||||
data = create_data(sample_image, sample_polys)
|
||||
augmenter_args = [
|
||||
{"type": "Affine", "args": {"rotate": [45, 45]}}, # Apply 45-degree rotation
|
||||
{"type": "Resize", "args": {"size": [0.5, 0.5]}},
|
||||
]
|
||||
augmenter = IaaAugment(augmenter_args=augmenter_args)
|
||||
transformed_data = augmenter(data)
|
||||
|
||||
# Check the expected image dimensions after resizing
|
||||
expected_height = int(sample_image.shape[0] * 0.5)
|
||||
expected_width = int(sample_image.shape[1] * 0.5)
|
||||
assert (
|
||||
transformed_data["image"].shape[0] == expected_height
|
||||
), "Image height should be scaled by 0.5"
|
||||
assert (
|
||||
transformed_data["image"].shape[1] == expected_width
|
||||
), "Image width should be scaled by 0.5"
|
||||
|
||||
# Verify that the polygons have been transformed
|
||||
polys_changed = any(
|
||||
not np.allclose(orig_poly, trans_poly)
|
||||
for orig_poly, trans_poly in zip(sample_polys, transformed_data["polys"])
|
||||
)
|
||||
assert polys_changed, "Polygons should have been transformed"
|
||||
|
||||
|
||||
# Test that an unknown transformation type raises an AttributeError
|
||||
def test_iaa_augment_unknown_transform():
|
||||
augmenter_args = [{"type": "UnknownTransform", "args": {}}]
|
||||
with pytest.raises(AttributeError):
|
||||
IaaAugment(augmenter_args=augmenter_args)
|
||||
|
||||
|
||||
# Test that an invalid resize size parameter raises a ValueError
|
||||
def test_iaa_augment_invalid_resize_size(sample_image, sample_polys):
|
||||
augmenter_args = [{"type": "Resize", "args": {"size": "invalid_size"}}]
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
IaaAugment(augmenter_args=augmenter_args)
|
||||
assert "'size' must be a list or tuple of two numbers" in str(exc_info.value)
|
||||
|
||||
|
||||
# Test that polygons are transformed as expected
|
||||
def test_iaa_augment_polys_transformation(sample_image, sample_polys):
|
||||
data = create_data(sample_image, sample_polys)
|
||||
augmenter_args = [
|
||||
{"type": "Affine", "args": {"rotate": [90, 90]}}, # Apply 90-degree rotation
|
||||
]
|
||||
augmenter = IaaAugment(augmenter_args=augmenter_args)
|
||||
transformed_data = augmenter(data)
|
||||
|
||||
# Verify that the polygons have been transformed
|
||||
polys_changed = any(
|
||||
not np.allclose(orig_poly, trans_poly)
|
||||
for orig_poly, trans_poly in zip(sample_polys, transformed_data["polys"])
|
||||
)
|
||||
assert polys_changed, "Polygons should have been transformed"
|
||||
|
||||
|
||||
# Test multiple transformations applied to the augmenter
|
||||
def test_iaa_augment_multiple_transforms(sample_image, sample_polys):
|
||||
augmenter_args = [
|
||||
{"type": "Fliplr", "args": {"p": 1.0}}, # Always apply horizontal flip
|
||||
{"type": "Affine", "args": {"shear": 10}},
|
||||
]
|
||||
data = create_data(sample_image, sample_polys)
|
||||
augmenter = IaaAugment(augmenter_args=augmenter_args)
|
||||
transformed_data = augmenter(data)
|
||||
|
||||
# Ensure the image has been transformed
|
||||
images_different = not np.array_equal(transformed_data["image"], sample_image)
|
||||
assert images_different, "Image should be transformed"
|
||||
|
||||
# Ensure the polygons have been transformed
|
||||
polys_changed = any(
|
||||
not np.allclose(orig_poly, trans_poly)
|
||||
for orig_poly, trans_poly in zip(sample_polys, transformed_data["polys"])
|
||||
)
|
||||
assert polys_changed, "Polygons should have been transformed"
|
||||
0
tests/test_ppstructure.py
Normal file
36
tests/testing_utils.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from pathlib import Path
|
||||
|
||||
TEST_DATA_DIR = Path(__file__).parent / "test_files"
|
||||
|
||||
|
||||
def check_simple_inference_result(result, *, expected_length=1):
|
||||
assert result is not None
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == expected_length
|
||||
for res in result:
|
||||
assert isinstance(res, dict)
|
||||
|
||||
|
||||
def check_wrapper_simple_inference_param_forwarding(
|
||||
monkeypatch,
|
||||
wrapper,
|
||||
wrapped_obj_attr_name,
|
||||
input,
|
||||
params,
|
||||
):
|
||||
def _dummy_predict(input, **params):
|
||||
yield params
|
||||
|
||||
monkeypatch.setattr(
|
||||
getattr(wrapper, wrapped_obj_attr_name), "predict", _dummy_predict
|
||||
)
|
||||
|
||||
result = getattr(wrapper, "predict")(
|
||||
input,
|
||||
**params,
|
||||
)
|
||||
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == 1
|
||||
for k, v in params.items():
|
||||
assert result[0][k] == v
|
||||