move test scripts inside .dev

This commit is contained in:
Martino Russi
2025-11-21 14:13:05 +01:00
parent 8f06c02c17
commit f30e15d411
2 changed files with 0 additions and 371 deletions
-121
View File
@@ -1,121 +0,0 @@
#!/usr/bin/env python3
"""
Single-script ZMQ camera demo - runs server and client in one process
Demonstrates ZMQ camera functionality for PR reviewers
"""
import time
from threading import Thread
import cv2
import numpy as np
import zmq
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from threading import Event
from lerobot.cameras.zmq import ZMQCamera, ZMQCameraConfig
from lerobot.cameras.configs import ColorMode
def create_test_pattern(width=640, height=480, frame_num=0):
"""Generate simple vertical color bars"""
img = np.zeros((height, width, 3), dtype=np.uint8)
# Classic SMPTE color bars
colors = [
(255, 255, 255), # White
(0, 255, 255), # Yellow
(0, 255, 255), # Cyan
(0, 255, 0), # Green
(255, 0, 255), # Magenta
(0, 0, 255), # Red
(255, 0, 0), # Blue
]
bar_width = width // len(colors)
for i, color in enumerate(colors):
x_start = i * bar_width
x_end = (i + 1) * bar_width if i < len(colors) - 1 else width
img[:, x_start:x_end] = color
return img
def run_server(port=5550, stop_event=None):
"""Background thread: publishes test pattern frames via ZMQ"""
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind(f"tcp://*:{port}")
time.sleep(0.5)
frame_num = 0
while stop_event is None or not stop_event.is_set():
frame = create_test_pattern(frame_num=frame_num)
_, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 85])
socket.send(buffer.tobytes())
frame_num += 1
time.sleep(1.0 / 30) # 30 FPS
socket.close()
context.term()
port = 5550
#SERVER
stop_event = Event()
server_thread = Thread(target=run_server, args=(port, stop_event), daemon=True)
server_thread.start()
time.sleep(1) # Let server initialize
#CLIENT
config = ZMQCameraConfig(
server_address="localhost",
port=port,
color_mode=ColorMode.RGB,
timeout_ms=5000
)
camera = ZMQCamera(config)
camera.connect()
# Setup matplotlib viewer
fig, ax = plt.subplots(figsize=(10, 7))
ax.set_title('ZMQ Camera Demo - Server & Client in one script', fontweight='bold')
ax.axis('off')
frame = camera.read()
im = ax.imshow(frame)
text = ax.text(0.02, 0.98, '', transform=ax.transAxes, fontsize=10, va='top',
bbox=dict(boxstyle='round', facecolor='black', alpha=0.7),
color='lime', fontweight='bold', family='monospace')
fig.tight_layout()
frame_count = [0]
fps_times = []
def update(frame_num):
loop_start = time.time()
frame = camera.read()
frame_count[0] += 1
im.set_data(frame)
fps_times.append(time.time() - loop_start)
if len(fps_times) > 30:
fps_times.pop(0)
fps = len(fps_times) / sum(fps_times) if fps_times else 0
text.set_text(f'Frame: {frame_count[0]}\nFPS: {fps:.1f}')
return [im, text]
try:
anim = FuncAnimation(fig, update, interval=33, blit=True, cache_frame_data=False)
plt.show()
except KeyboardInterrupt:
pass
finally:
camera.disconnect()
stop_event.set()
plt.close('all')
-250
View File
@@ -1,250 +0,0 @@
#!/usr/bin/env python3
"""
ZMQ Camera Server - Publishes camera frames via ZeroMQ
This script captures frames from a camera (or generates test patterns) and
publishes them as JPEG-encoded images over a ZMQ PUB socket.
Usage:
# Using a webcam (default camera index 0)
python test_zmq_camera_server.py --port 5554
# Using a specific camera
python test_zmq_camera_server.py --camera 1 --port 5555
# Using test pattern (no camera required)
python test_zmq_camera_server.py --test-pattern --port 5554
# Specify IP address and resolution
python test_zmq_camera_server.py --address 192.168.1.100 --width 1280 --height 720
"""
import argparse
import time
from datetime import datetime
import cv2
import numpy as np
import zmq
def create_test_pattern(width: int = 640, height: int = 480, frame_count: int = 0) -> np.ndarray:
"""
Creates an animated test pattern image.
Args:
width: Image width
height: Image height
frame_count: Current frame number for animation
Returns:
BGR image array
"""
# Create a colorful test pattern
img = np.zeros((height, width, 3), dtype=np.uint8)
# Animated gradient background
for i in range(height):
color_shift = int(((i + frame_count) % height) / height * 255)
img[i, :] = [color_shift, 128, 255 - color_shift]
# Moving circle
center_x = int(width // 2 + 200 * np.sin(frame_count * 0.05))
center_y = int(height // 2 + 100 * np.cos(frame_count * 0.05))
cv2.circle(img, (center_x, center_y), 50, (0, 255, 0), -1)
# Add text with timestamp
text = f"ZMQ Test Pattern - Frame {frame_count}"
cv2.putText(img, text, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
cv2.putText(img, timestamp, (20, height - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
return img
def main():
parser = argparse.ArgumentParser(description="ZMQ Camera Server - Publishes camera frames via ZeroMQ")
parser.add_argument("--address", type=str, default="*",
help="IP address to bind to (* for all interfaces)")
parser.add_argument("--port", type=int, default=5550,
help="Port number to publish on (default: 5554)")
parser.add_argument("--camera", type=int, default=0,
help="Camera device index (default: 0)")
parser.add_argument("--test-pattern", action="store_true",
help="Use animated test pattern instead of camera")
parser.add_argument("--width", type=int, default=640,
help="Frame width (default: 640)")
parser.add_argument("--height", type=int, default=480,
help="Frame height (default: 480)")
parser.add_argument("--fps", type=int, default=30,
help="Target frames per second (default: 30)")
parser.add_argument("--quality", type=int, default=80,
help="JPEG quality 1-100 (default: 80)")
parser.add_argument("--display", action="store_true",
help="Display the video feed locally")
args = parser.parse_args()
# Initialize ZMQ
print(f"Initializing ZMQ publisher on tcp://{args.address}:{args.port}")
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind(f"tcp://{args.address}:{args.port}")
# Give ZMQ time to establish connections
print("Waiting for subscribers to connect...")
time.sleep(1)
# Initialize camera or test pattern
cap = None
if not args.test_pattern:
print(f"Opening camera {args.camera}...")
cap = cv2.VideoCapture(args.camera)
if not cap.isOpened():
print(f"ERROR: Could not open camera {args.camera}")
print("Falling back to test pattern mode")
args.test_pattern = True
else:
# Set camera properties
cap.set(cv2.CAP_PROP_FRAME_WIDTH, args.width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, args.height)
cap.set(cv2.CAP_PROP_FPS, args.fps)
# Read actual properties (camera may not support requested values)
actual_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
actual_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
actual_fps = cap.get(cv2.CAP_PROP_FPS)
print(f"Camera opened successfully")
print(f" Resolution: {actual_width}x{actual_height}")
print(f" FPS: {actual_fps}")
if args.test_pattern:
print(f"Using test pattern mode")
print(f" Resolution: {args.width}x{args.height}")
print(f" FPS: {args.fps}")
print("\n" + "="*60)
print("SERVER RUNNING - Press Ctrl+C to stop")
print("="*60)
print(f"Publishing JPEG frames on tcp://{args.address}:{args.port}")
if args.address == "*":
print("\nClients can connect using your machine's IP address")
print("Run 'hostname -I' or 'ipconfig' to find your IP")
print("\nPress Ctrl+C to stop the server")
print("="*60 + "\n")
frame_count = 0
start_time = time.time()
last_print_time = start_time
frame_times = []
# JPEG encoding parameters
encode_params = [int(cv2.IMWRITE_JPEG_QUALITY), args.quality]
try:
while True:
loop_start = time.time()
# Capture or generate frame
if args.test_pattern:
frame = create_test_pattern(args.width, args.height, frame_count)
ret = True
else:
ret, frame = cap.read()
if not ret:
print("ERROR: Failed to capture frame")
break
# Resize if needed
if frame.shape[1] != args.width or frame.shape[0] != args.height:
frame = cv2.resize(frame, (args.width, args.height))
# Encode frame as JPEG
encode_start = time.time()
_, buffer = cv2.imencode('.jpg', frame, encode_params)
encode_time = (time.time() - encode_start) * 1000
# Publish frame
publish_start = time.time()
socket.send(buffer.tobytes())
publish_time = (time.time() - publish_start) * 1000
frame_count += 1
# Display locally if requested
if args.display:
# Add stats overlay
display_frame = frame.copy()
stats_text = f"Frame: {frame_count} | FPS: {len(frame_times):.1f}"
cv2.putText(display_frame, stats_text, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow('ZMQ Camera Server', display_frame)
# Exit on 'q' key
if cv2.waitKey(1) & 0xFF == ord('q'):
print("\nStopping server (user pressed 'q')...")
break
# Calculate timing statistics
loop_time = time.time() - loop_start
frame_times.append(loop_time)
# Keep only last second of frame times for FPS calculation
if len(frame_times) > args.fps * 2:
frame_times = frame_times[-args.fps:]
# Print statistics every 2 seconds
current_time = time.time()
if current_time - last_print_time >= 2.0:
elapsed = current_time - start_time
actual_fps = len(frame_times) / sum(frame_times) if frame_times else 0
avg_loop_time = np.mean(frame_times) * 1000 if frame_times else 0
print(f"[{elapsed:6.1f}s] Frames: {frame_count:5d} | "
f"FPS: {actual_fps:5.1f} | "
f"Loop: {avg_loop_time:5.1f}ms | "
f"Encode: {encode_time:4.1f}ms | "
f"Publish: {publish_time:4.1f}ms")
last_print_time = current_time
# Control frame rate
target_loop_time = 1.0 / args.fps
sleep_time = target_loop_time - loop_time
if sleep_time > 0:
time.sleep(sleep_time)
except KeyboardInterrupt:
print("\n\nStopping server (Ctrl+C pressed)...")
finally:
# Cleanup
if cap is not None:
cap.release()
if args.display:
cv2.destroyAllWindows()
socket.close()
context.term()
# Print final statistics
elapsed = time.time() - start_time
avg_fps = frame_count / elapsed if elapsed > 0 else 0
print("\n" + "="*60)
print("SERVER STOPPED")
print("="*60)
print(f"Total frames published: {frame_count}")
print(f"Total time: {elapsed:.2f}s")
print(f"Average FPS: {avg_fps:.2f}")
print("="*60)
if __name__ == "__main__":
main()