Spaces:
Sleeping
Sleeping
File size: 1,994 Bytes
a3953cb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | """
detect_text.py — POST /detect-text
Runs PaddleOCR on the original image stored by /upload and returns a list
of axis-aligned bounding boxes in original-image pixel coordinates.
Why axis-aligned boxes, not raw quads?
---------------------------------------
PaddleOCR returns rotated quadrilaterals (4 corner points per region).
Converting to the minimum enclosing axis-aligned rect (min/max of the 4 x
and y values) allows mask_service.build_masks() to rasterize them with zero
changes — it already accepts {"x", "y", "width", "height"} dicts. The
slight extra background at rotated-text corners is absorbed by the dilation
and feathering steps, so the composite seam is invisible.
Zero detections is not an error
---------------------------------
If OCR finds no text, {"boxes": []} is returned with HTTP 200. The frontend
displays a "nothing detected" hint; the user can still paint manually.
"""
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from app.jobs_store import get_job
from app.services.ocr_service import detect_text_regions
router = APIRouter()
class DetectTextRequest(BaseModel):
job_id: str
@router.post("")
def detect_text(body: DetectTextRequest) -> dict:
"""Run OCR on the uploaded image and return detected text bounding boxes.
Response
--------
{"boxes": [{"x": int, "y": int, "width": int, "height": int}, ...]}
All coordinates are in original-image pixels — the same space the mask
JSON contract uses — so the frontend can put them directly into the
``boxes`` array of buildMaskJson() without any scaling.
Raises 404 if the job_id is not found.
Returns {"boxes": []} with HTTP 200 if no text is detected.
"""
job = get_job(body.job_id)
if job is None:
raise HTTPException(
status_code=404,
detail=f"Job '{body.job_id}' not found.",
)
boxes = detect_text_regions(job.steps[0].original_image)
return {"boxes": boxes}
|