Metadata-Version: 2.4
Name: camera-util
Version: 1.4.2
Summary: Python wrapper for USB, spin, Raspi, Jetson Nano cameras. Works on Windows, Raspian (incl Bullseye), JetsonNano, MacOS
Home-page: https://github.com/uutzinger/camera
Author: Urs Utzinger
Author-email: uutzinger@gmail.com
License: MIT
Keywords: camera,driver,opencv,spin
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Multimedia :: Video :: Capture
Description-Content-Type: text/x-rst
License-File: LICENSE
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: summary

Camera Util
===========

A collection of threaded camera capture and streaming utilities.

Supports:

- USB and laptop internal webcams (OpenCV)
- RTSP/RTP network streams (GStreamer or FFmpeg fallback)
- MIPI CSI cameras (Raspberry Pi Picamera2/libcamera, Jetson Nano)
- Teledyne/FLIR Spinnaker cameras (PySpin)
- Basler cameras (pypylon)

Storage helpers for HDF5, TIFF, AVI, MKV.

Processing helpers for temporal filtering, background subtraction, and binning.

Full documentation (configs, backends, examples): `README.md <https://github.com/uutzinger/camera/blob/master/README.md>`_.

Install
-------

.. code-block:: bash

   pip install camera-util

Quickstart (OpenCV webcam)
--------------------------

.. code-block:: python

   import time
   import cv2
   from camera.capture.cv2capture import cv2Capture

   configs = {
       "camera_res": (640, 480),
       "fps": 30,
       "fourcc": "MJPG",
       "displayfps": 30,
   }

   camera = cv2Capture(configs, 0)
   camera.start()

   window_name = "Camera"
   cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE)
   last_display = time.perf_counter()
   display_interval = 1.0 / configs["displayfps"]
   stop = False
   while cv2.getWindowProperty(window_name, cv2.WND_PROP_VISIBLE) >= 0 and not stop:
       frame = None
       if camera.buffer and camera.buffer.avail > 0:
           frame, _ts_ms = camera.buffer.pull(copy=False)
       elif camera.capture is not None:
           _ts_ms, frame = camera.capture.get(block=True, timeout=0.25)

       if frame is None:
           continue

       current_time = time.perf_counter()
       if (current_time - last_display) >= display_interval:
           frame_display = frame.copy()
           cv2.putText(frame_display, f"Capture FPS:{camera.measured_fps:.1f} [Hz]", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1)
           cv2.imshow(window_name, frame_display)
           if cv2.waitKey(1) & 0xFF == ord("q"):
               stop = True
           last_display = current_time

   camera.stop()
   cv2.destroyAllWindows()

Raspberry Pi (Picamera2/libcamera)
----------------------------------

Two wrappers are provided:

- ``piCamera2Capture`` (threaded, non-Qt)
- ``piCamera2CaptureQt`` (Qt5/Qt6)

Frame delivery model:

- Frames go into a single-producer/single-consumer ring buffer ``camera.buffer``.
- Consumers poll (no queue semantics):

.. code-block:: python

   if camera.buffer and camera.buffer.avail > 0:
       frame, ts_ms = camera.buffer.pull(copy=False)

The Qt wrapper does not emit a per-frame signal; GUI code typically polls via a ``QTimer``.
