This commit is contained in:
q 2026-03-08 12:27:25 +03:00
parent 268c4a6e7e
commit a61fe467aa
3 changed files with 96 additions and 3 deletions

View file

@ -71,7 +71,7 @@ OpenCV from JetPack repos (4.x) usually ships without CUDA dnn. To use CUDA, bui
- `RETURN_BOXES` (default `true`)
- `USE_CUDA_DNN` (default `false`, set `true` to attempt CUDA backend for EAST if OpenCV built with CUDA)
- `DEBUG_VISUAL` (default `false`; if true, response includes `debug_image_base64`. Per-request: add `?debug=1` or form field `debug=1`.)
- `SHOW_GUI` (default `false`; if true and OpenCV GUI available, service opens a window with overlays. Requires X/Wayland/VDI that supports GUI.)
- `SHOW_GUI` (default `false`; if true and OpenCV GUI available, service opens a text-centric window: left = detected text regions, right = OCR block text/conf. Requires X/Wayland/VDI that supports GUI.)
## Run
```bash

Binary file not shown.

97
app.py
View file

@ -235,6 +235,90 @@ def build_debug_image(img_rgb, boxes, blocks, objects, target_width=1024, return
except Exception:
return None, None
def build_text_gui_image(img_rgb, boxes, blocks, target_width=1600):
"""Build a text-centric GUI frame: regions on left, OCR lines on right."""
if cv2 is None or img_rgb is None:
return None
try:
src = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
h, w = src.shape[:2]
frame_w = target_width if target_width and target_width > 0 else 1600
if frame_w < 900:
frame_w = 900
left_w = int(frame_w * 0.64)
scale = float(left_w) / float(max(1, w))
left_h = max(360, int(h * scale))
left = cv2.resize(src, (left_w, left_h), interpolation=cv2.INTER_AREA if scale < 1.0 else cv2.INTER_CUBIC)
# text detector regions
for idx, b in enumerate(boxes or []):
try:
x1, y1, x2, y2 = [int(v * scale) for v in b]
except Exception:
continue
cv2.rectangle(left, (x1, y1), (x2, y2), (255, 90, 0), 2)
cv2.putText(left, "T{}".format(idx + 1), (x1, max(12, y1 - 4)),
cv2.FONT_HERSHEY_SIMPLEX, 0.45, (255, 90, 0), 1, cv2.LINE_AA)
# OCR blocks (where text was actually extracted)
for idx, blk in enumerate(blocks or []):
try:
x1, y1, x2, y2 = [int(v * scale) for v in blk.get("bbox", [0, 0, 0, 0])]
except Exception:
continue
cv2.rectangle(left, (x1, y1), (x2, y2), (0, 160, 255), 2)
cv2.putText(left, "R{}".format(idx + 1), (x1, min(left_h - 8, y2 + 14)),
cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 160, 255), 1, cv2.LINE_AA)
right_w = frame_w - left_w
if right_w < 320:
right_w = 320
left = cv2.resize(left, (frame_w - right_w, left_h))
left_w = left.shape[1]
right = np.ones((left_h, right_w, 3), dtype=np.uint8) * 245
y = 28
line_h = 22
cv2.putText(right, "OCR text panel", (14, y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (30, 30, 30), 2, cv2.LINE_AA)
y += line_h + 4
cv2.putText(right, "detected regions: {}".format(len(boxes or [])), (14, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.55, (70, 70, 70), 1, cv2.LINE_AA)
y += line_h
cv2.putText(right, "recognized blocks: {}".format(len(blocks or [])), (14, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.55, (70, 70, 70), 1, cv2.LINE_AA)
y += line_h + 4
cv2.line(right, (12, y), (right_w - 12, y), (200, 200, 200), 1)
y += 18
if not blocks:
cv2.putText(right, "No OCR text blocks", (14, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.56, (100, 100, 100), 1, cv2.LINE_AA)
else:
visible = blocks[:10]
max_chars = max(18, int((right_w - 24) / 8))
for idx, blk in enumerate(visible):
conf = blk.get("conf", -1)
conf_str = "{:.1f}".format(conf) if isinstance(conf, (float, int)) and conf >= 0 else "n/a"
header = "#{:02d} conf={}".format(idx + 1, conf_str)
cv2.putText(right, header, (14, y), cv2.FONT_HERSHEY_SIMPLEX, 0.50, (20, 20, 20), 1, cv2.LINE_AA)
y += line_h - 2
raw = (blk.get("text", "") or "").replace("\n", " ").replace("\r", " ").strip()
txt = " ".join(raw.split())
if len(txt) > max_chars:
txt = txt[:max_chars - 1] + "..."
cv2.putText(right, txt if txt else "<empty>", (14, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.52, (30, 30, 30), 1, cv2.LINE_AA)
y += line_h
if y > left_h - 18:
break
frame = np.concatenate([left, right], axis=1)
return frame
except Exception:
return None
# ---- Routes ----
@app.route('/health', methods=['GET'])
@ -382,9 +466,18 @@ def image2text():
target_width=target_w,
return_image=SHOW_GUI,
)
if SHOW_GUI and cv2 is not None and debug_image_arr is not None:
if SHOW_GUI and cv2 is not None:
try:
_gui_show(debug_image_arr)
gui_frame = build_text_gui_image(
img_rgb,
boxes,
blocks if RETURN_BOXES else [],
target_width=GUI_TARGET_WIDTH,
)
if gui_frame is None:
gui_frame = debug_image_arr
if gui_frame is not None:
_gui_show(gui_frame)
except Exception:
pass