From 5d42088502e1bf0a073cc516e5ab7eae18510225 Mon Sep 17 00:00:00 2001 From: Joachim Hummel Date: Tue, 2 Jun 2026 18:04:57 +0200 Subject: [PATCH] Hilfs-Scripts nach scripts/ verschoben (test.py -> grab_frame.py) - fps_test.py -> scripts/fps_test.py - test.py -> scripts/grab_frame.py (umbenannt + nutzbar gemacht: CAMERA_URL aus .env oder URL-Arg, --save, sauberes Error-Handling) Co-Authored-By: Claude Opus 4.8 (1M context) --- fps_test.py => scripts/fps_test.py | 0 scripts/grab_frame.py | 68 ++++++++++++++++++++++++++++++ test.py | 10 ----- 3 files changed, 68 insertions(+), 10 deletions(-) rename fps_test.py => scripts/fps_test.py (100%) create mode 100644 scripts/grab_frame.py delete mode 100644 test.py diff --git a/fps_test.py b/scripts/fps_test.py similarity index 100% rename from fps_test.py rename to scripts/fps_test.py diff --git a/scripts/grab_frame.py b/scripts/grab_frame.py new file mode 100644 index 0000000..8ff8d70 --- /dev/null +++ b/scripts/grab_frame.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +""" +grab_frame.py - Holt EIN Bild aus einem MJPEG-Stream und gibt die Groesse aus. +Schneller Check, ob die Kamera ueberhaupt ein dekodierbares Frame liefert. + + python3 scripts/grab_frame.py # CAMERA_URL aus .env + python3 scripts/grab_frame.py http://192.168.10.99:81/stream + python3 scripts/grab_frame.py --save bild.jpg # Frame zusaetzlich speichern +""" +import argparse +import os +import sys + +import cv2 +import numpy as np +import requests + +try: + from dotenv import load_dotenv + load_dotenv() +except ImportError: + pass + + +def main() -> int: + p = argparse.ArgumentParser(description="Ein Frame aus einem MJPEG-Stream holen.") + p.add_argument("url", nargs="?", default=os.environ.get("CAMERA_URL"), + help="MJPEG-URL (Default: CAMERA_URL aus .env)") + p.add_argument("--save", metavar="DATEI", help="Frame als JPEG speichern") + args = p.parse_args() + + if not args.url: + print("Keine URL und keine CAMERA_URL in .env gesetzt.") + return 1 + + try: + r = requests.get(args.url, stream=True, timeout=(5, 10)) + r.raise_for_status() + except requests.RequestException as exc: + print(f"FEHLER: {exc}") + return 1 + + buf = b"" + try: + for chunk in r.iter_content(4096): + buf += chunk + a = buf.find(b"\xff\xd8") + b = buf.find(b"\xff\xd9", a + 2) + if a != -1 and b != -1: + img = cv2.imdecode(np.frombuffer(buf[a:b + 2], np.uint8), cv2.IMREAD_COLOR) + if img is None: + print("Frame empfangen, aber nicht dekodierbar.") + return 1 + print(f"Frame OK: {img.shape[1]}x{img.shape[0]} px ({b + 2 - a} Bytes JPEG)") + if args.save: + cv2.imwrite(args.save, img) + print(f"gespeichert -> {args.save}") + return 0 + if len(buf) > 5_000_000: + break + finally: + r.close() + print("Kein vollstaendiges Frame empfangen.") + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/test.py b/test.py deleted file mode 100644 index b4e1916..0000000 --- a/test.py +++ /dev/null @@ -1,10 +0,0 @@ -import requests, numpy as np, cv2 -r = requests.get("http://CAMERA-IP:81/stream", stream=True, timeout=5) -buf = b"" -for chunk in r.iter_content(4096): - buf += chunk - a = buf.find(b"\xff\xd8"); b = buf.find(b"\xff\xd9") - if a != -1 and b != -1 and b > a: - img = cv2.imdecode(np.frombuffer(buf[a:b+2], np.uint8), cv2.IMREAD_COLOR) - print("frame:", None if img is None else img.shape) - break