feat(phase1): implement OpenCV image processing pipeline

- Create ImageProcessor service with EXIF orientation detection
- Implement smart cropping via OpenCV contour detection (10% padding)
- Add text orientation detection using Hough line transform
- Resize and compress images to 1200px with 85% JPEG quality
- Generate 200px square thumbnails with center crop
- Fallback to Pillow if OpenCV fails
- Comprehensive test suite: 28 tests all passing
- File size validation (reject >10MB)
- Graceful error handling for corrupted/invalid images
- Update requirements.txt with opencv-python, piexif, python-magic
This commit is contained in:
2026-04-20 22:17:11 +03:00
parent 01321bf607
commit 3aafacab12
1068 changed files with 720366 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
__all__: list[str] = []
import cv2.gapi.onnx.ep
import cv2.typing
import typing as _typing
from cv2.gapi.onnx import ep as ep
# Enumerations
TraitAs_TENSOR: int
TRAIT_AS_TENSOR: int
TraitAs_IMAGE: int
TRAIT_AS_IMAGE: int
TraitAs = int
"""One of [TraitAs_TENSOR, TRAIT_AS_TENSOR, TraitAs_IMAGE, TRAIT_AS_IMAGE]"""
# Classes
class PyParams:
# Functions
@_typing.overload
def __init__(self) -> None: ...
@_typing.overload
def __init__(self, tag: str, model_path: str) -> None: ...
def cfgMeanStd(self, layer_name: str, m: cv2.typing.Scalar, s: cv2.typing.Scalar) -> PyParams: ...
def cfgNormalize(self, layer_name: str, flag: bool) -> PyParams: ...
@_typing.overload
def cfgAddExecutionProvider(self, ep: cv2.gapi.onnx.ep.OpenVINO) -> PyParams: ...
@_typing.overload
def cfgAddExecutionProvider(self, ep: cv2.gapi.onnx.ep.DirectML) -> PyParams: ...
@_typing.overload
def cfgAddExecutionProvider(self, ep: cv2.gapi.onnx.ep.CoreML) -> PyParams: ...
@_typing.overload
def cfgAddExecutionProvider(self, ep: cv2.gapi.onnx.ep.CUDA) -> PyParams: ...
@_typing.overload
def cfgAddExecutionProvider(self, ep: cv2.gapi.onnx.ep.TensorRT) -> PyParams: ...
def cfgDisableMemPattern(self) -> PyParams: ...
def cfgSessionOptions(self, options: cv2.typing.map_string_and_string) -> PyParams: ...
def cfgOptLevel(self, opt_level: int) -> PyParams: ...
# Functions
def params(tag: str, model_path: str) -> PyParams: ...

View File

@@ -0,0 +1,63 @@
__all__: list[str] = []
import cv2.typing
import typing as _typing
# Classes
class CoreML:
# Functions
def __init__(self) -> None: ...
def cfgUseCPUOnly(self) -> CoreML: ...
def cfgEnableOnSubgraph(self) -> CoreML: ...
def cfgEnableOnlyNeuralEngine(self) -> CoreML: ...
class CUDA:
# Functions
@_typing.overload
def __init__(self) -> None: ...
@_typing.overload
def __init__(self, dev_id: int) -> None: ...
class TensorRT:
# Functions
@_typing.overload
def __init__(self) -> None: ...
@_typing.overload
def __init__(self, dev_id: int) -> None: ...
class OpenVINO:
# Functions
@_typing.overload
def __init__(self) -> None: ...
@_typing.overload
def __init__(self, dev_type: str) -> None: ...
@_typing.overload
def __init__(self, params: cv2.typing.map_string_and_string) -> None: ...
def cfgCacheDir(self, dir: str) -> OpenVINO: ...
def cfgNumThreads(self, nthreads: int) -> OpenVINO: ...
def cfgEnableOpenCLThrottling(self) -> OpenVINO: ...
def cfgEnableDynamicShapes(self) -> OpenVINO: ...
class DirectML:
# Functions
@_typing.overload
def __init__(self) -> None: ...
@_typing.overload
def __init__(self, device_id: int) -> None: ...
@_typing.overload
def __init__(self, adapter_name: str) -> None: ...