I have a project where I'm trying to project a live video feed to a large RGB LED matrix (currently 256x256).
There are several PicoW involved that receive the image data over WiFi. That part's been solved.
Now I need to implement the rest on a Pi 5, by using the directly connected camera, from which I extract frames at 20 fps, reduce the image size to 256x256, then convert that into RGB565 format (i.e. a raw pixel buffer with 16 bit per pixel) so that I can send it to the Picos.
How do I do this in Python?
I've skimmed over the Picamera2 docs, which seems to offer only direct output to various streams and files. I am unsure how I'd get at the frames so that I can resize them and then get the raw pixels.
I gave ChatGPT a try and it came up with a seemingly nice and complete solution on my first try:
Problem is: It always reports "Error: Could not read frame.".
The same camera works with the rpicam-... commands just fine.
So I asked GPT to rewrite the program by using Picamera2 instead. It made this:
And that worked!
Wow.
There are several PicoW involved that receive the image data over WiFi. That part's been solved.
Now I need to implement the rest on a Pi 5, by using the directly connected camera, from which I extract frames at 20 fps, reduce the image size to 256x256, then convert that into RGB565 format (i.e. a raw pixel buffer with 16 bit per pixel) so that I can send it to the Picos.
How do I do this in Python?
I've skimmed over the Picamera2 docs, which seems to offer only direct output to various streams and files. I am unsure how I'd get at the frames so that I can resize them and then get the raw pixels.
I gave ChatGPT a try and it came up with a seemingly nice and complete solution on my first try:
Code:
import cv2import numpy as npdef rgb888_to_rgb565(rgb888_frame): # Extract the R, G, B components from the 8-bit image r = rgb888_frame[:, :, 0] >> 3 g = rgb888_frame[:, :, 1] >> 2 b = rgb888_frame[:, :, 2] >> 3 # Combine the components into a 16-bit RGB565 format rgb565_frame = (r << 11) | (g << 5) | b return rgb565_framedef save_rgb565(filename, rgb565_frame): with open(filename, "wb") as f: # Convert the numpy array to bytes and write to file rgb565_frame.tofile(f)# Open a connection to the cameracap = cv2.VideoCapture(0) # You might need to change the device index if you have multiple camerasif not cap.isOpened(): print("Error: Could not open camera.") exit()while True: # Capture a frame from the camera ret, frame = cap.read() if not ret: print("Error: Could not read frame.") break # Resize the frame to 256x256 resized_frame = cv2.resize(frame, (256, 256)) # Convert the frame from BGR (OpenCV default) to RGB rgb_frame = cv2.cvtColor(resized_frame, cv2.COLOR_BGR2RGB) # Convert the RGB frame to RGB565 format rgb565_frame = rgb888_to_rgb565(rgb_frame) # Save the RGB565 frame to a file save_rgb565("frame.rgb565", rgb565_frame) # Display the frame (optional) cv2.imshow('Frame', resized_frame) # Break the loop if 'q' is pressed if cv2.waitKey(1) & 0xFF == ord('q'): break# Release the camera and close any OpenCV windowscap.release()cv2.destroyAllWindows()
The same camera works with the rpicam-... commands just fine.
So I asked GPT to rewrite the program by using Picamera2 instead. It made this:
Code:
from picamera2 import Picamera2import numpy as npfrom PIL import Imagedef rgb888_to_rgb565(rgb888_frame): # Extract the R, G, B components from the 8-bit image r = (rgb888_frame[:, :, 0] >> 3).astype(np.uint16) g = (rgb888_frame[:, :, 1] >> 2).astype(np.uint16) b = (rgb888_frame[:, :, 2] >> 3).astype(np.uint16) # Combine the components into a 16-bit RGB565 format rgb565_frame = (r << 11) | (g << 5) | b return rgb565_framedef save_rgb565(filename, rgb565_frame): with open(filename, "wb") as f: # Convert the numpy array to bytes and write to file rgb565_frame.tofile(f)# Initialize the camerapicam2 = Picamera2()# Configure the cameraconfig = picam2.create_preview_configuration(main={"size": (640, 480)})picam2.configure(config)# Start the camerapicam2.start()try: while True: # Capture a frame from the camera frame = picam2.capture_array() # Convert the frame to a PIL image for resizing image = Image.fromarray(frame) # Resize the frame to 256x256 resized_image = image.resize((256, 256)) # Convert the resized image back to a numpy array rgb_frame = np.array(resized_image) # Convert the RGB frame to RGB565 format rgb565_frame = rgb888_to_rgb565(rgb_frame) # Save the RGB565 frame to a file save_rgb565("frame.rgb565", rgb565_frame) # Optionally display the frame (requires additional libraries like matplotlib) # plt.imshow(resized_image) # plt.show() # Break the loop if a specific condition is met, e.g., capturing a fixed number of frames # For an interactive approach, implement a key listener or other stopping condition except KeyboardInterrupt: # Handle the keyboard interrupt to exit gracefully print("Capture stopped by user")# Stop the camerapicam2.stop()
Wow.
Statistics: Posted by tem_pi — Thu Aug 01, 2024 3:17 pm