Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions paddlex/inference/models/text_detection/_large_input_warning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


LARGE_DET_INPUT_WARN_PIXELS = 4_000_000


class LargeDetectorInputWarner:
def __init__(self):
self._emitted = False

def warn(self, source_shape, detector_shape, warning):
detector_h, detector_w = detector_shape[:2]
if self._emitted or detector_h * detector_w <= LARGE_DET_INPUT_WARN_PIXELS:
return

source_h, source_w = source_shape[:2]
self._emitted = True
warning(
f"Text detection preprocessing produced a large detector input of "
f"{detector_w}x{detector_h} "
f"({detector_w * detector_h / 1e6:.1f} megapixels) from a "
f"{source_w}x{source_h} source image. This may increase memory use "
f"or cause an out-of-memory error. Consider lowering the detector "
f"input-size limits in the pipeline or model configuration."
)
4 changes: 4 additions & 0 deletions paddlex/inference/models/text_detection/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from ....utils import logging
from ....utils.deps import class_requires_deps, is_dep_available
from ...utils.benchmark import benchmark
from ._large_input_warning import LargeDetectorInputWarner

if is_dep_available("opencv-contrib-python"):
import cv2
Expand All @@ -35,6 +36,7 @@ class DetResizeForTest:
def __init__(self, input_shape=None, max_side_limit=4000, **kwargs):
self.resize_type = 0
self.keep_ratio = False
self._large_input_warner = LargeDetectorInputWarner()
if input_shape is not None:
self.input_shape = input_shape
self.resize_type = 3
Expand Down Expand Up @@ -71,6 +73,8 @@ def __call__(
img, shape = self.resize(
ori_img, limit_side_len, limit_type, max_side_limit
)
if img is not None:
self._large_input_warner.warn(ori_img.shape, img.shape, logging.warning)
resize_imgs.append(img)
img_shapes.append(shape)
return resize_imgs, img_shapes
Expand Down
66 changes: 66 additions & 0 deletions tests/inference/models/text_detection/test_processors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import importlib.util
from pathlib import Path
from unittest.mock import Mock


REPO_ROOT = Path(__file__).resolve().parents[4]
spec = importlib.util.spec_from_file_location(
"large_input_warning",
REPO_ROOT / "paddlex/inference/models/text_detection/_large_input_warning.py",
)
large_input_warning = importlib.util.module_from_spec(spec)
spec.loader.exec_module(large_input_warning)


LARGE_DET_INPUT_WARN_PIXELS = large_input_warning.LARGE_DET_INPUT_WARN_PIXELS
LargeDetectorInputWarner = large_input_warning.LargeDetectorInputWarner


def test_large_detector_input_warning_boundary():
warner = LargeDetectorInputWarner()
warning = Mock()

warner.warn(
(1000, 4000, 3),
(1000, LARGE_DET_INPUT_WARN_PIXELS // 1000, 3),
warning,
)

warning.assert_not_called()


def test_large_detector_input_warning_is_bounded_per_processor():
warner = LargeDetectorInputWarner()
warning = Mock()

warner.warn((3000, 2000, 3), (3000, 2000, 3), warning)
warner.warn((4000, 3000, 3), (4000, 3000, 3), warning)

warning.assert_called_once()


def test_large_detector_input_warning_describes_detector_and_source_paths():
warner = LargeDetectorInputWarner()
warning = Mock()

warner.warn((3000, 4000, 3), (2048, 2048, 3), warning)

message = warning.call_args.args[0]
assert "2048x2048" in message
assert "4000x3000 source image" in message
assert "without downscaling" not in message
assert "text_det_limit" not in message